From e5a10db41cad2c1bcf8404a8e02f8d5a8f6a993d Mon Sep 17 00:00:00 2001 From: "https://blog.iamtsm.cn" <1905333456@qq.com> Date: Tue, 4 Jul 2023 14:45:31 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E7=BB=98=E7=94=BB?= =?UTF-8?q?=E5=90=8C=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit feat: 支持敏感词检测 feat: 支持多语言版本 feat: 支持回车发送消息 feat: 支持展示房主,语言版本 feat: 支持分享链接带上语言版本 feat: 支持设置公共聊天频道消息展示条数 feat: 支持固定/临时turn账号切换 feat: 支持一键启动脚本 feat: 支持浏览器控制台打印logo feat: 调整优化svg, icon图标 feat: 调整优化弹窗动画 feat: 调整优化媒体流时间动画 feat: 调整优化oss逻辑 feat: 调整优化报错告警信息 --- PAY.md | 10 +- README.md | 198 +- doc/README_EN.md | 119 +- svr/bin/genTurnUser.sh | 1 - svr/bin/startTurnserver.sh | 1 - svr/bin/turnStart.sh | 8 + svr/build/webpack/package-lock.json | 331 +- svr/conf/cfg.json | 221 +- svr/conf/turn/turnserver.conf | 662 +-- svr/package-lock.json | 4710 ++++++++--------- svr/package.json | 72 +- svr/res/css/index.css | 191 +- svr/res/home.html | 4 + svr/res/home_en.html | 4 + svr/res/image/drawcircle.png | Bin 0 -> 457 bytes svr/res/image/drawcirclefill.png | Bin 0 -> 366 bytes svr/res/image/drawdelete.png | Bin 0 -> 365 bytes svr/res/image/drawhexagon.png | Bin 0 -> 389 bytes svr/res/image/drawhexagonfill.png | Bin 0 -> 330 bytes svr/res/image/drawline.png | Bin 0 -> 359 bytes svr/res/image/drawrectangle.png | Bin 0 -> 253 bytes svr/res/image/drawrectanglefill.png | Bin 0 -> 249 bytes svr/res/image/drawrhomboid.png | Bin 0 -> 287 bytes svr/res/image/drawrhomboidfill.png | Bin 0 -> 255 bytes svr/res/image/drawstar.png | Bin 0 -> 511 bytes svr/res/image/drawstarfill.png | Bin 0 -> 396 bytes svr/res/image/drawtext.png | Bin 0 -> 227 bytes svr/res/image/drawtriangle.png | Bin 0 -> 352 bytes svr/res/image/drawtrianglefill.png | Bin 0 -> 343 bytes svr/res/index.html | 1121 ++-- svr/res/js/comm.js | 215 +- svr/res/js/draw.js | 1014 ++++ svr/res/js/index.js | 2467 +++++---- svr/res/js/language.js | 628 +++ svr/res/js/liveShare.js | 18 +- svr/res/js/screen.js | 69 +- svr/res/js/screenShare.js | 19 +- svr/res/js/videoShare.js | 18 +- svr/res/pay.html | 16 +- svr/src/bussiness/manage/settingPage.js | 28 +- svr/src/bussiness/notify/notifyHandler.js | 37 +- svr/src/bussiness/oss/oss.js | 33 + svr/src/bussiness/oss/seafile.js | 112 +- svr/src/bussiness/oss/tx.js | 4 + svr/src/controller/check/check.js | 32 + svr/src/controller/check/index.js | 11 + svr/src/controller/comm/comm.js | 19 +- svr/src/dao/dog/dog.js | 9 +- svr/src/dao/room/room.js | 2 + svr/src/socket/rtcChatingComm/chatingComm.js | 11 +- svr/src/socket/rtcChatingRoom/chatingRoom.js | 3 +- svr/src/socket/rtcCodeFile/addCodeFile.js | 12 +- svr/src/socket/rtcCodeFile/getCodeFile.js | 2 + svr/src/socket/rtcCodeFile/prepareCodeFile.js | 7 +- svr/src/socket/rtcCommData/commData.js | 7 +- svr/src/socket/rtcConstant.js | 6 +- svr/src/socket/rtcControl/control.js | 3 +- svr/src/socket/rtcCount/count.js | 2 +- svr/src/socket/rtcCreateJoin/createJoin.js | 19 +- svr/src/socket/rtcDraw/draw.js | 2 +- svr/src/socket/rtcExit/exit.js | 1 + svr/src/socket/rtcManage/change.js | 2 + svr/src/socket/rtcManage/confirm.js | 2 + svr/src/socket/rtcManage/reload.js | 2 + svr/src/socket/rtcMessage/message.js | 26 + svr/src/socket/rtcOpenai/openai.js | 7 +- svr/src/utils/check/content.js | 39 +- svr/src/utils/check/core.js | 10 + svr/src/utils/check/words.js | 1 + svr/src/utils/utils.js | 140 +- svr/start-local.sh | 11 + svr/start-server.sh | 5 + svr/static/layui/font-ext/demo.css | 539 ++ svr/static/layui/font-ext/demo_index.html | 1959 +++++++ svr/static/layui/font-ext/iconfont.css | 323 ++ svr/static/layui/font-ext/iconfont.js | 1 + svr/static/layui/font-ext/iconfont.json | 548 ++ svr/static/layui/font-ext/iconfont.ttf | Bin 0 -> 30868 bytes svr/static/layui/font-ext/iconfont.woff | Bin 0 -> 17640 bytes svr/static/layui/font-ext/iconfont.woff2 | Bin 0 -> 15076 bytes 80 files changed, 10503 insertions(+), 5591 deletions(-) delete mode 100644 svr/bin/genTurnUser.sh delete mode 100644 svr/bin/startTurnserver.sh create mode 100644 svr/bin/turnStart.sh create mode 100644 svr/res/image/drawcircle.png create mode 100644 svr/res/image/drawcirclefill.png create mode 100644 svr/res/image/drawdelete.png create mode 100644 svr/res/image/drawhexagon.png create mode 100644 svr/res/image/drawhexagonfill.png create mode 100644 svr/res/image/drawline.png create mode 100644 svr/res/image/drawrectangle.png create mode 100644 svr/res/image/drawrectanglefill.png create mode 100644 svr/res/image/drawrhomboid.png create mode 100644 svr/res/image/drawrhomboidfill.png create mode 100644 svr/res/image/drawstar.png create mode 100644 svr/res/image/drawstarfill.png create mode 100644 svr/res/image/drawtext.png create mode 100644 svr/res/image/drawtriangle.png create mode 100644 svr/res/image/drawtrianglefill.png create mode 100644 svr/res/js/draw.js create mode 100644 svr/res/js/language.js create mode 100644 svr/src/bussiness/oss/tx.js create mode 100644 svr/src/controller/check/check.js create mode 100644 svr/src/controller/check/index.js create mode 100644 svr/src/utils/check/words.js create mode 100755 svr/start-local.sh create mode 100755 svr/start-server.sh create mode 100644 svr/static/layui/font-ext/demo.css create mode 100644 svr/static/layui/font-ext/demo_index.html create mode 100644 svr/static/layui/font-ext/iconfont.css create mode 100644 svr/static/layui/font-ext/iconfont.js create mode 100644 svr/static/layui/font-ext/iconfont.json create mode 100644 svr/static/layui/font-ext/iconfont.ttf create mode 100644 svr/static/layui/font-ext/iconfont.woff create mode 100644 svr/static/layui/font-ext/iconfont.woff2 diff --git a/PAY.md b/PAY.md index 140e2a7..4444eee 100644 --- a/PAY.md +++ b/PAY.md @@ -7,14 +7,14 @@ ## 项目定制服务 -### 1. 项目功能定制 +### 1. 定制开发支持 +- **服务内容:** 免费提供定制开发技术支持,可协助部署安装相关事项,或协助自行开发,细节问题答疑 +- **免费:** 非常乐意为各位使用的小伙伴提供帮助,大家觉得好用的同时可以点击start支持下 + +### 2. 项目功能定制 - **服务内容:** 对项目进行功能定制或扩展 - **价格:** 按功能大小,紧急程度,耗时,定制内容是否允许开源,等情况收费 -### 2. 定制开发支持 -- **服务内容:** 提供定制开发技术支持,可协助部署安装相关事项,或协助自行开发,细节问题答疑 -- **价格:** 一杯咖啡 - ## 收费模式 - **按小时计费:** 根据实际工作时间计算费用,目前个人定制功能2小时起,每小时200~300,企业定制另谈 - **阶段性付费:** 确认开发前,预付1/3,开发完成付1/3,交付上线1/3 diff --git a/README.md b/README.md index 40a2dd3..e2718c8 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ **qq交流群 : 624214498** -## 准备 +## 准备 (必须步骤) 安装node-14.x,npm后进入项目目录运行下面命令 @@ -40,68 +40,177 @@ `npm run dev` (打包开发环境min) 或者 `npm run pro` 打包生产环境min -## 启动 +## 启动 (必须步骤) -http形式启动以下两个服务 +http形式启动以下两个服务, 选一种模式启动即可 api服务: `npm run lapi` socket服务 : `npm run lsocket` - 或者https形式启动一下两个服务 +或者https形式启动一下两个服务 api服务: `npm run sapi` socket服务 : `npm run ssocket` -选一种模式启动即可 -## 配置数据库 (默认关闭) +## 配置websocket (必须步骤) - 修改conf/cfg.json中相应数据库配置即可, 如open, dbName, host, port, user, pwd 等 +修改cfg.json中相应ws配置,或者wss配置 + + "ws": { + "port": 8444, #socket 端口 + "host": "ws://127.0.0.1:8444", #socket ip + "control_port": 8445, #远程控制socket 端口 + "control_host": "ws://127.0.0.1:8445" #远程控制socket ip + }, + "wss" : { + "port": 8444, + "host": "wss://域名||ip:port", + "control_port": 8445, + "control_host": "wss://域名||ip:port" + }, + +## 配置数据库 (非必须步骤) + +修改cfg.json中相应数据库配置 + + "db": { + "open": false, #是否开启数据库, 默认关闭 + "mysql": { + "host": "host地址", + "port": 3306, + "dbName": "数据库名称", + "user": "用户名", + "password": "密码", + "other": { + "sequelize": { + "dialect": "mysql", + "host": "host地址", + "port": 3306, + "logging": false, + "pool": { + "max": 5, + "min": 0, + "acquire": 30000, + "idle": 10000 + }, + "timezone": "+08:00", + "define": { + "freezeTableName": true, + "underscored": true, + "charset": "utf8", + "collate": "utf8_general_ci", + "timestamps": false, + "paranoid": true + } + } + } + } + } + +## 配置turnserver (局域网非必须步骤,公网必须步骤) + +ubuntu示例: + + 安装coturn `sudo apt-get install coturn` + + 项目提供了一份配置文件模板在 : `conf/turn/turnserver.conf` + + 修改配置文件后复制一份 `cp conf/turn/turnserver.conf /etc/turnserver.conf` + +示例用户和密码: tlrtcfile + + 生成用户 (turnadmin生成密码) `turnadmin -k -u tlrtcfile -r 你的域名` + 或者 (自定义密码) `turnadmin -a -u tlrtcfile -p tlrtcfile -r 你的域名` + 启动turnserver `turnserver -c /etc/turnserver.conf` + + 可参考示例模板 : `bin/turnStart.sh` -## 配置websocket (ws/wss) +## Docker (非必须步骤) - 修改conf/cfg.json中相应ws配置,或者wss配置 + 按需配置conf.json中的ws, 或者wss (需要填容器的ip,端口信息) -## 配置turnserver (中继服务) + docker build -t tl-open-source/tl-rtc-file . - ubuntu: - - 1. sudo apt-get install coturn #安装coturn - - 2. cp conf/turn/turnserver.conf /etc/turnserver.conf #修改配置文件, 文件内容按需修改 - - 3. chomd +x bin/genTurnUser.sh && ./genTurnUser.sh #文件内容按需修改 - - 4. chomd +x bin/startTurnServer.sh && ./startTurnServer.sh #启动turnserver,文件内容按需修改 - -## Docker - - 修改conf/cfg.json中的ws/wss的ip地址(有更好的办法可以反馈下) - - docker build -t iamtsm/tl-rtc-file . - - docker run -p 9092:9092 -p 8444:8444 --name local -d iamtsm/tl-rtc-file + docker run -p 9092:9092 -p 8444:8444 --name tl-rtc-file-local -d tl-open-source/tl-rtc-file 访问 : http://localhost:9092 或者 http://本机ip:9092 -## 管理后台 +## 管理后台 (非必须步骤) - 前提 : 需要开启数据库配置 +前提 : 需要开启数据库配置 - 修改conf/cfg.json中的manage的room和password,默认房间号和密码都是tlrtcfile +修改cfg.json中的manage的room和password,默认房间号和密码都是tlrtcfile 访问 : http://localhost:9092 或者 http://本机ip:9092 输入配置的房间号,输入密码,即可进入管理后台 - ps : 如有需要配置企业微信通知,修改conf/cfg.json中的notify的qiwei数组,填入企业微信机器人的key即可 + "manage": { + "room": "tlrtcfile", + "password": "tlrtcfile" + }, -## Chat-GPT +## 企微通知 (非必须步骤) - 修改conf/cfg.json中的openai.apiKeys,填写你自己openai账号生成的apiKey +修改cfg.json中的notify的qiwei数组,填入企业微信机器人的key即可 + +normal : 正常通知, error : 系统报错通知 + + "notify": { + "open": true, #是否开启企业微信通知 + "qiwei": { + "normal" : [ + "key1", + "key2" + ], + "error" : [ + "key3", + "key4" + ] + } + }, + +## OSS云存储 (非必须步骤) + +修改cfg.json中的oss + + "oss": { + "seafile": { + "repoid": "", + "host": "", + "username": "帐号", + "password": "密码" + }, + "alyun": { + "AccessKey": "", + "SecretKey": "", + "bucket": "tl-rtc-file" + }, + "txyun": { + "AccessKey": "", + "SecretKey": "", + "bucket": "tl-rtc-file" + }, + "qiniuyun": { + "AccessKey": "", + "SecretKey": "", + "bucket": "tl-rtc-file" + } + }, + +## Chat-GPT (非必须步骤) + +修改cfg.json中的openai.apiKeys,填写你自己openai账号生成的apiKey + + "openai": { + "apiKeys": [ + + ] + }, ## 概述图 @@ -109,28 +218,7 @@ http形式启动以下两个服务 ## License -MIT License - -Copyright (c) 2022 iamtsm - -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. - +### MIT License Copyright (c) 2022 iamtsm ## 免责声明 diff --git a/doc/README_EN.md b/doc/README_EN.md index 7111824..9da1adf 100644 --- a/doc/README_EN.md +++ b/doc/README_EN.md @@ -1,4 +1,4 @@ -# tl-rtc-file-tool [More than just file transfer, starting from file transfer] +# tl-rtc-file-tool 【More Than Just File Transfer】 [![](https://img.shields.io/badge/webrtc-p2p-blue)](https://webrtc.org.cn/) [![](https://img.shields.io/badge/code-simple-green)](https://github.com/iamtsm/tl-rtc-file/) @@ -6,16 +6,13 @@ [![](https://img.shields.io/badge/deployment-private-yellow)](https://github.com/iamtsm/tl-rtc-file/) [![](https://img.shields.io/badge/platform-unlimited-coral)](https://github.com/iamtsm/tl-rtc-file/) +#### Background: Organized around the topic of a 2020 thesis -#### Background: Consolidated from the topic of the 20-year graduation project +#### Introduction: (tl webrtc datachannel filetools) uses WebRTC to transfer files on the web and supports the transfer of very large files. -#### Introduction: (tl webrtc datachannel filetools) Transfer files on the web using WebRTC, supporting the transfer of large files. +#### Advantages: Supports fragmented transmission, cross-device compatibility, platform independence, easy-to-use, unlimited internal network speed, private deployment, and supports the drag-and-drop sending of multiple files. -#### Advantages: Fragmented transmission, cross-platform, platform-independent, easy to use, unlimited speed in the intranet, support for private deployment, support for multiple file drag and drop sending. - -#### Extensions: Extended with many rich features such as local screen recording, remote screen sharing, remote audio and video calls, live streaming, pickup codes, password-protected rooms, relay service settings, WebRTC detection, text transmission, public chat, rich backend management, integration of Enterprise WeChat robot alert notification, real-time execution log display, and more. - -#### Instructions: The example website is in a public network environment. In order to better demonstrate the transmission function, the relay service is enabled by default. If you want to verify whether P2P transmission is possible, simply disable the relay service. After the P2P detection, if you can see the internal network IP, the WebRTC connection can most likely go through P2P. In general, users in the internal network environment in the public network environment will also be automatically recognized. If the internal network speed is slow, you can leave feedback and it will be optimized and processed as soon as possible. +#### Extensions: Many rich functions have been added, such as local screen recording, remote screen sharing, remote audio and video calls, live broadcasting, password rooms, relay service settings, WebRTC detection, text transmission, public chat, rich back-end management, integrated Enterprise WeChat robot alarm notification, real-time execution log display, etc. #### Experience: https://im.iamtsm.cn/file @@ -23,115 +20,63 @@ ## Preparation -Install node-14.x and npm, then enter the project directory and run the following commands: + Install Node.js and npm and then enter the project directory. + + npm install - `cd svr/` + Go to the build directory: cd build/webpack/ - `npm install` + Install some dependencies: npm install - `cd build/webpack/` - `npm install` + If you need to develop and modify the files in the res directory, keep one of the following two backend commands open. - For the first run or self-developed pages, you need to start the following two commands: + npm run dev packages the development environment min. - `cd build/webpack/` + npm run pro packages the production environment min. - `npm run dev` (package for development environment min) or `npm run pro` (package for production environment min) +## Test Environment -## Start + Start the following two services. -Start the following two services in HTTP format: + Local startup file-res: npm run dev - API service: `npm run lapi` + Local startup file-socket: npm run devsocket - Socket service: `npm run lsocket` +## Online Environment (WSS Configuration Required) - Or start the following two services in HTTPS format: + Start the following two services. - API service: `npm run sapi` + Public network environment starts file-res: npm run svr - Socket service: `npm run ssocket` + Public network environment starts file-socket: npm run svrsocket -Choose one mode to start. -## Configure Database (Default: Disabled) +## Configure the db (turned off by default) - Modify the corresponding database configuration in conf/cfg.json, such as open, dbName, host, port, user, pwd, etc. + Modify the corresponding DB configuration in conf/cfg.json, such as open, dbName, host, port, user, pwd, etc. -## Configure WebSocket (WS/WSS) - Modify the corresponding WS configuration or WSS configuration in conf/cfg.json. +## Configure the wss -## Configure TURN Server (Relay Service) + Modify the corresponding WS configuration in conf/cfg.json, such as port, ws_online, etc. + + +## Configure turnserver (private deployment) Ubuntu: 1. sudo apt-get install coturn # Install coturn. - 2. cp conf/turn/turnserver.conf /etc/turnserver.conf # Modify the configuration file, modify the file content as needed. + 2. cp conf/turn/turnserver.conf /etc/turnserver.conf # Modify the configuration file, and modify the file content as needed. - 3. chmod +x bin/genTurnUser.sh && ./ + 3. chomd +x bin/genTurnUser.sh && ./genTurn - genTurnUser.sh # Modify the file content as needed. - 4. chmod +x bin/startTurnServer.sh && ./startTurnServer.sh # Start turnserver, modify the file content as needed. - -## Docker - - Modify the IP address of ws/wss in conf/cfg.json (feedback is welcome if there is a better way). - - docker build -t iamtsm/tl-rtc-file . - - docker run -p 9092:9092 -p 8444:8444 --name local -d iamtsm/tl-rtc-file - - Access: http://localhost:9092 or http://localhost-ip:9092 - -## Admin Panel - - Prerequisite: Database configuration needs to be enabled. - - Modify the room and password of manage in conf/cfg.json. The default room number and password are both tlrtcfile. - - Access: http://localhost:9092 or http://localhost-ip:9092 - - Enter the configured room number and password to enter the admin panel. - - PS: If you need to configure Enterprise WeChat notification, modify the qiwei array in conf/cfg.json of notify and enter the key of the Enterprise WeChat robot. - -## Chat-GPT - - Modify openai.apiKeys in conf/cfg.json and fill in your own apiKey generated by your OpenAI account. - -## Overview Diagram +### Overview ![image](tl-rtc-file-tool.jpg) ## License -MIT License - -Copyright (c) 2022 iamtsm - -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. - - -## Disclaimer - -[Disclaimer](DISCLAIMER.md) \ No newline at end of file +### MIT License Copyright (c) 2022 iamtsm \ No newline at end of file diff --git a/svr/bin/genTurnUser.sh b/svr/bin/genTurnUser.sh deleted file mode 100644 index 5741f15..0000000 --- a/svr/bin/genTurnUser.sh +++ /dev/null @@ -1 +0,0 @@ -turnadmin -a -u 用户名 -p 密码 -r 公网ip \ No newline at end of file diff --git a/svr/bin/startTurnserver.sh b/svr/bin/startTurnserver.sh deleted file mode 100644 index 457fc23..0000000 --- a/svr/bin/startTurnserver.sh +++ /dev/null @@ -1 +0,0 @@ -turnserver -o -a -f -user=用户名:密码 diff --git a/svr/bin/turnStart.sh b/svr/bin/turnStart.sh new file mode 100644 index 0000000..0bfe613 --- /dev/null +++ b/svr/bin/turnStart.sh @@ -0,0 +1,8 @@ +#生成账号密码方式1 +turnadmin -a -u tlrtcfile -p tlrtcfile -r 域名或ip:port + +#生成账号密码方式2 +turnadmin -k -u tlrtcfile -r 域名或ip:port + +#启动turnserver +turnserver -c turnserver.conf路径 diff --git a/svr/build/webpack/package-lock.json b/svr/build/webpack/package-lock.json index 820c0c1..89a8575 100644 --- a/svr/build/webpack/package-lock.json +++ b/svr/build/webpack/package-lock.json @@ -15,36 +15,36 @@ } }, "@babel/code-frame": { - "version": "7.21.4", - "resolved": "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.21.4.tgz", - "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", + "version": "7.22.5", + "resolved": "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.22.5.tgz", + "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", "dev": true, "requires": { - "@babel/highlight": "^7.18.6" + "@babel/highlight": "^7.22.5" } }, "@babel/compat-data": { - "version": "7.22.3", - "resolved": "https://registry.npmmirror.com/@babel/compat-data/-/compat-data-7.22.3.tgz", - "integrity": "sha512-aNtko9OPOwVESUFp3MZfD8Uzxl7JzSeJpd7npIoxCasU37PFbAQRpKglkaKwlHOyeJdrREpo8TW8ldrkYWwvIQ==", + "version": "7.22.5", + "resolved": "https://registry.npmmirror.com/@babel/compat-data/-/compat-data-7.22.5.tgz", + "integrity": "sha512-4Jc/YuIaYqKnDDz892kPIledykKg12Aw1PYX5i/TY28anJtacvM1Rrr8wbieB9GfEJwlzqT0hUEao0CxEebiDA==", "dev": true }, "@babel/core": { - "version": "7.22.1", - "resolved": "https://registry.npmmirror.com/@babel/core/-/core-7.22.1.tgz", - "integrity": "sha512-Hkqu7J4ynysSXxmAahpN1jjRwVJ+NdpraFLIWflgjpVob3KNyK3/tIUc7Q7szed8WMp0JNa7Qtd1E9Oo22F9gA==", + "version": "7.22.5", + "resolved": "https://registry.npmmirror.com/@babel/core/-/core-7.22.5.tgz", + "integrity": "sha512-SBuTAjg91A3eKOvD+bPEz3LlhHZRNu1nFOVts9lzDJTXshHTjII0BAtDS3Y2DAkdZdDKWVZGVwkDfc4Clxn1dg==", "dev": true, "requires": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.21.4", - "@babel/generator": "^7.22.0", - "@babel/helper-compilation-targets": "^7.22.1", - "@babel/helper-module-transforms": "^7.22.1", - "@babel/helpers": "^7.22.0", - "@babel/parser": "^7.22.0", - "@babel/template": "^7.21.9", - "@babel/traverse": "^7.22.1", - "@babel/types": "^7.22.0", + "@babel/code-frame": "^7.22.5", + "@babel/generator": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.5", + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helpers": "^7.22.5", + "@babel/parser": "^7.22.5", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.5", + "@babel/types": "^7.22.5", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -53,181 +53,181 @@ } }, "@babel/generator": { - "version": "7.22.3", - "resolved": "https://registry.npmmirror.com/@babel/generator/-/generator-7.22.3.tgz", - "integrity": "sha512-C17MW4wlk//ES/CJDL51kPNwl+qiBQyN7b9SKyVp11BLGFeSPoVaHrv+MNt8jwQFhQWowW88z1eeBx3pFz9v8A==", + "version": "7.22.5", + "resolved": "https://registry.npmmirror.com/@babel/generator/-/generator-7.22.5.tgz", + "integrity": "sha512-+lcUbnTRhd0jOewtFSedLyiPsD5tswKkbgcezOqqWFUVNEwoUTlpPOBmvhG7OXWLR4jMdv0czPGH5XbflnD1EA==", "dev": true, "requires": { - "@babel/types": "^7.22.3", + "@babel/types": "^7.22.5", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" } }, "@babel/helper-compilation-targets": { - "version": "7.22.1", - "resolved": "https://registry.npmmirror.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.1.tgz", - "integrity": "sha512-Rqx13UM3yVB5q0D/KwQ8+SPfX/+Rnsy1Lw1k/UwOC4KC6qrzIQoY3lYnBu5EHKBlEHHcj0M0W8ltPSkD8rqfsQ==", + "version": "7.22.5", + "resolved": "https://registry.npmmirror.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.5.tgz", + "integrity": "sha512-Ji+ywpHeuqxB8WDxraCiqR0xfhYjiDE/e6k7FuIaANnoOFxAHskHChz4vA1mJC9Lbm01s1PVAGhQY4FUKSkGZw==", "dev": true, "requires": { - "@babel/compat-data": "^7.22.0", - "@babel/helper-validator-option": "^7.21.0", + "@babel/compat-data": "^7.22.5", + "@babel/helper-validator-option": "^7.22.5", "browserslist": "^4.21.3", "lru-cache": "^5.1.1", "semver": "^6.3.0" } }, "@babel/helper-environment-visitor": { - "version": "7.22.1", - "resolved": "https://registry.npmmirror.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.1.tgz", - "integrity": "sha512-Z2tgopurB/kTbidvzeBrc2To3PUP/9i5MUe+fU6QJCQDyPwSH2oRapkLw3KGECDYSjhQZCNxEvNvZlLw8JjGwA==", + "version": "7.22.5", + "resolved": "https://registry.npmmirror.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", + "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", "dev": true }, "@babel/helper-function-name": { - "version": "7.21.0", - "resolved": "https://registry.npmmirror.com/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz", - "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==", + "version": "7.22.5", + "resolved": "https://registry.npmmirror.com/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", + "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", "dev": true, "requires": { - "@babel/template": "^7.20.7", - "@babel/types": "^7.21.0" + "@babel/template": "^7.22.5", + "@babel/types": "^7.22.5" } }, "@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmmirror.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "version": "7.22.5", + "resolved": "https://registry.npmmirror.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "dev": true, "requires": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" } }, "@babel/helper-module-imports": { - "version": "7.21.4", - "resolved": "https://registry.npmmirror.com/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz", - "integrity": "sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==", + "version": "7.22.5", + "resolved": "https://registry.npmmirror.com/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz", + "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==", "dev": true, "requires": { - "@babel/types": "^7.21.4" + "@babel/types": "^7.22.5" } }, "@babel/helper-module-transforms": { - "version": "7.22.1", - "resolved": "https://registry.npmmirror.com/@babel/helper-module-transforms/-/helper-module-transforms-7.22.1.tgz", - "integrity": "sha512-dxAe9E7ySDGbQdCVOY/4+UcD8M9ZFqZcZhSPsPacvCG4M+9lwtDDQfI2EoaSvmf7W/8yCBkGU0m7Pvt1ru3UZw==", + "version": "7.22.5", + "resolved": "https://registry.npmmirror.com/@babel/helper-module-transforms/-/helper-module-transforms-7.22.5.tgz", + "integrity": "sha512-+hGKDt/Ze8GFExiVHno/2dvG5IdstpzCq0y4Qc9OJ25D4q3pKfiIP/4Vp3/JvhDkLKsDK2api3q3fpIgiIF5bw==", "dev": true, "requires": { - "@babel/helper-environment-visitor": "^7.22.1", - "@babel/helper-module-imports": "^7.21.4", - "@babel/helper-simple-access": "^7.21.5", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.19.1", - "@babel/template": "^7.21.9", - "@babel/traverse": "^7.22.1", - "@babel/types": "^7.22.0" + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.5", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.5", + "@babel/types": "^7.22.5" } }, "@babel/helper-simple-access": { - "version": "7.21.5", - "resolved": "https://registry.npmmirror.com/@babel/helper-simple-access/-/helper-simple-access-7.21.5.tgz", - "integrity": "sha512-ENPDAMC1wAjR0uaCUwliBdiSl1KBJAVnMTzXqi64c2MG8MPR6ii4qf7bSXDqSFbr4W6W028/rf5ivoHop5/mkg==", + "version": "7.22.5", + "resolved": "https://registry.npmmirror.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", "dev": true, "requires": { - "@babel/types": "^7.21.5" + "@babel/types": "^7.22.5" } }, "@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmmirror.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "version": "7.22.5", + "resolved": "https://registry.npmmirror.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.5.tgz", + "integrity": "sha512-thqK5QFghPKWLhAV321lxF95yCg2K3Ob5yw+M3VHWfdia0IkPXUtoLH8x/6Fh486QUvzhb8YOWHChTVen2/PoQ==", "dev": true, "requires": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" } }, "@babel/helper-string-parser": { - "version": "7.21.5", - "resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.21.5.tgz", - "integrity": "sha512-5pTUx3hAJaZIdW99sJ6ZUUgWq/Y+Hja7TowEnLNMm1VivRgZQL3vpBY3qUACVsvw+yQU6+YgfBVmcbLaZtrA1w==", + "version": "7.22.5", + "resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", "dev": true }, "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "version": "7.22.5", + "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", + "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", "dev": true }, "@babel/helper-validator-option": { - "version": "7.21.0", - "resolved": "https://registry.npmmirror.com/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz", - "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==", + "version": "7.22.5", + "resolved": "https://registry.npmmirror.com/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz", + "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==", "dev": true }, "@babel/helpers": { - "version": "7.22.3", - "resolved": "https://registry.npmmirror.com/@babel/helpers/-/helpers-7.22.3.tgz", - "integrity": "sha512-jBJ7jWblbgr7r6wYZHMdIqKc73ycaTcCaWRq4/2LpuPHcx7xMlZvpGQkOYc9HeSjn6rcx15CPlgVcBtZ4WZJ2w==", + "version": "7.22.5", + "resolved": "https://registry.npmmirror.com/@babel/helpers/-/helpers-7.22.5.tgz", + "integrity": "sha512-pSXRmfE1vzcUIDFQcSGA5Mr+GxBV9oiRKDuDxXvWQQBCh8HoIjs/2DlDB7H8smac1IVrB9/xdXj2N3Wol9Cr+Q==", "dev": true, "requires": { - "@babel/template": "^7.21.9", - "@babel/traverse": "^7.22.1", - "@babel/types": "^7.22.3" + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.5", + "@babel/types": "^7.22.5" } }, "@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmmirror.com/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "version": "7.22.5", + "resolved": "https://registry.npmmirror.com/@babel/highlight/-/highlight-7.22.5.tgz", + "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.18.6", + "@babel/helper-validator-identifier": "^7.22.5", "chalk": "^2.0.0", "js-tokens": "^4.0.0" } }, "@babel/parser": { - "version": "7.22.4", - "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.22.4.tgz", - "integrity": "sha512-VLLsx06XkEYqBtE5YGPwfSGwfrjnyPP5oiGty3S8pQLFDFLaS8VwWSIxkTXpcvr5zeYLE6+MBNl2npl/YnfofA==", + "version": "7.22.5", + "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.22.5.tgz", + "integrity": "sha512-DFZMC9LJUG9PLOclRC32G63UXwzqS2koQC8dkx+PLdmt1xSePYpbT/NbsrJy8Q/muXz7o/h/d4A7Fuyixm559Q==", "dev": true }, "@babel/template": { - "version": "7.21.9", - "resolved": "https://registry.npmmirror.com/@babel/template/-/template-7.21.9.tgz", - "integrity": "sha512-MK0X5k8NKOuWRamiEfc3KEJiHMTkGZNUjzMipqCGDDc6ijRl/B7RGSKVGncu4Ro/HdyzzY6cmoXuKI2Gffk7vQ==", + "version": "7.22.5", + "resolved": "https://registry.npmmirror.com/@babel/template/-/template-7.22.5.tgz", + "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", "dev": true, "requires": { - "@babel/code-frame": "^7.21.4", - "@babel/parser": "^7.21.9", - "@babel/types": "^7.21.5" + "@babel/code-frame": "^7.22.5", + "@babel/parser": "^7.22.5", + "@babel/types": "^7.22.5" } }, "@babel/traverse": { - "version": "7.22.4", - "resolved": "https://registry.npmmirror.com/@babel/traverse/-/traverse-7.22.4.tgz", - "integrity": "sha512-Tn1pDsjIcI+JcLKq1AVlZEr4226gpuAQTsLMorsYg9tuS/kG7nuwwJ4AB8jfQuEgb/COBwR/DqJxmoiYFu5/rQ==", + "version": "7.22.5", + "resolved": "https://registry.npmmirror.com/@babel/traverse/-/traverse-7.22.5.tgz", + "integrity": "sha512-7DuIjPgERaNo6r+PZwItpjCZEa5vyw4eJGufeLxrPdBXBoLcCJCIasvK6pK/9DVNrLZTLFhUGqaC6X/PA007TQ==", "dev": true, "requires": { - "@babel/code-frame": "^7.21.4", - "@babel/generator": "^7.22.3", - "@babel/helper-environment-visitor": "^7.22.1", - "@babel/helper-function-name": "^7.21.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.22.4", - "@babel/types": "^7.22.4", + "@babel/code-frame": "^7.22.5", + "@babel/generator": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.5", + "@babel/parser": "^7.22.5", + "@babel/types": "^7.22.5", "debug": "^4.1.0", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.22.4", - "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.22.4.tgz", - "integrity": "sha512-Tx9x3UBHTTsMSW85WB2kphxYQVvrZ/t1FxD88IpSgIjiUJlCm9z+xWIDwyo1vffTwSqteqyznB8ZE9vYYk16zA==", + "version": "7.22.5", + "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.22.5.tgz", + "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==", "dev": true, "requires": { - "@babel/helper-string-parser": "^7.21.5", - "@babel/helper-validator-identifier": "^7.19.1", + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.5", "to-fast-properties": "^2.0.0" } }, @@ -896,13 +896,13 @@ } }, "browserslist": { - "version": "4.21.7", - "resolved": "https://registry.npmmirror.com/browserslist/-/browserslist-4.21.7.tgz", - "integrity": "sha512-BauCXrQ7I2ftSqd2mvKHGo85XR0u7Ru3C/Hxsy/0TkfCtjrmAbPdzLGasmoiBxplpDXlPvdjX9u7srIMfgasNA==", + "version": "4.21.9", + "resolved": "https://registry.npmmirror.com/browserslist/-/browserslist-4.21.9.tgz", + "integrity": "sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001489", - "electron-to-chromium": "^1.4.411", + "caniuse-lite": "^1.0.30001503", + "electron-to-chromium": "^1.4.431", "node-releases": "^2.0.12", "update-browserslist-db": "^1.0.11" } @@ -976,6 +976,16 @@ "unset-value": "^1.0.0" } }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, "camelcase": { "version": "5.3.1", "resolved": "https://registry.npmmirror.com/camelcase/-/camelcase-5.3.1.tgz", @@ -983,9 +993,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001492", - "resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001492.tgz", - "integrity": "sha512-2efF8SAZwgAX1FJr87KWhvuJxnGJKOnctQa8xLOskAXNXq8oiuqgl6u1kk3fFpsp3GgvzlRjiK1sl63hNtFADw==", + "version": "1.0.30001512", + "resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001512.tgz", + "integrity": "sha512-2S9nK0G/mE+jasCUsMPlARhRCts1ebcp2Ji8Y8PWi4NDE1iRdLCnEPHkEfeBrGC45L4isBx5ur3IQ6yTE2mRZw==", "dev": true }, "chalk": { @@ -1490,9 +1500,9 @@ } }, "electron-to-chromium": { - "version": "1.4.416", - "resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.4.416.tgz", - "integrity": "sha512-AUYh0XDTb2vrj0rj82jb3P9hHSyzQNdTPYWZIhPdCOui7/vpme7+HTE07BE5jwuqg/34TZ8ktlRz6GImJ4IXjA==", + "version": "1.4.449", + "resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.4.449.tgz", + "integrity": "sha512-TxLRpRUj/107ATefeP8VIUWNOv90xJxZZbCW/eIbSZQiuiFANCx2b7u+GbVc9X4gU+xnbvypNMYVM/WArE1DNQ==", "dev": true }, "elliptic": { @@ -1909,6 +1919,12 @@ "dev": true, "optional": true }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, "gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmmirror.com/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -1921,6 +1937,18 @@ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, + "get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + } + }, "get-value": { "version": "2.0.6", "resolved": "https://registry.npmmirror.com/get-value/-/get-value-2.0.6.tgz", @@ -1972,12 +2000,33 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, "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 }, + "has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true + }, + "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 + }, "has-value": { "version": "1.0.0", "resolved": "https://registry.npmmirror.com/has-value/-/has-value-1.0.0.tgz", @@ -2697,6 +2746,12 @@ } } }, + "object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "dev": true + }, "object-visit": { "version": "1.0.1", "resolved": "https://registry.npmmirror.com/object-visit/-/object-visit-1.0.1.tgz", @@ -3027,11 +3082,14 @@ "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", "dev": true }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmmirror.com/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", - "dev": true + "qs": { + "version": "6.11.2", + "resolved": "https://registry.npmmirror.com/qs/-/qs-6.11.2.tgz", + "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", + "dev": true, + "requires": { + "side-channel": "^1.0.4" + } }, "querystring-es3": { "version": "0.2.1", @@ -3241,6 +3299,17 @@ "safe-buffer": "^5.0.1" } }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmmirror.com/snapdragon/-/snapdragon-0.8.2.tgz", @@ -3985,19 +4054,19 @@ "dev": true }, "url": { - "version": "0.11.0", - "resolved": "https://registry.npmmirror.com/url/-/url-0.11.0.tgz", - "integrity": "sha512-kbailJa29QrtXnxgq+DdCEGlbTeYM2eJUxsz6vjZavrCYPMIFHMKQmSKYAIuUK2i7hgPm28a8piX5NTUtM/LKQ==", + "version": "0.11.1", + "resolved": "https://registry.npmmirror.com/url/-/url-0.11.1.tgz", + "integrity": "sha512-rWS3H04/+mzzJkv0eZ7vEDGiQbgquI1fGfOad6zKvgYQi1SzMmhl7c/DdRGxhaWrVH6z0qWITo8rpnxK/RfEhA==", "dev": true, "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" + "punycode": "^1.4.1", + "qs": "^6.11.0" }, "dependencies": { "punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmmirror.com/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==", + "version": "1.4.1", + "resolved": "https://registry.npmmirror.com/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", "dev": true } } diff --git a/svr/conf/cfg.json b/svr/conf/cfg.json index 4870bc8..78e51bc 100644 --- a/svr/conf/cfg.json +++ b/svr/conf/cfg.json @@ -1,105 +1,120 @@ { - "version": "10.1.1", - "ws": { - "port": 8444, - "host": "ws://127.0.0.1:8444", - "control_port": 8445, - "control_host": "ws://127.0.0.1:8445" - }, - "wss" : { - "port": 8444, - "host": "wss://域名 || wss://ip:8444", - "control_port": 8445, - "control_host": "wss://域名 || wss://ip:8445" - }, - "api": { - "port": 9092, - "router": { - "filter": { - "whiteDir": [ ], - "whiteFile": [ "router.js" ] - }, - "res": { - "/": "res/", - "/static": "static/" - } - } - }, - "manage": { - "room": "tlrtcfile", - "password": "tlrtcfile" - }, - "webrtc": { - "iceServers": [{ - "urls": "stun:stun.xten.com" - }], - "iceTransportPolicy": "all", - "options": { - "offerToReceiveAudio": 1, - "offerToReceiveVideo": 1 - } - }, - "openai" : { - "apiKeys" : [ - - ] - }, - "oss" : { - "seafile" : { - "repoid" : "存储库id", - "host" : "seafile私有网盘域名", - "username" : "账号", - "password" : "密码" - }, - "alyun" : { - - }, - "qiniuyun" : { - - } - }, - "notify": { - "open": false, - "qiwei": { - "normal" : [ - "填写企业微信机器人key" - ], - "error" : [ - "填写企业微信机器人key" - ] - } - }, - "db": { - "open" : false, - "mysql": { - "host": "host地址", - "port": 3306, - "dbName": "数据库名称", - "user": "用户名", - "password": "密码", - "other": { - "sequelize": { - "dialect": "mysql", - "host": "host地址", - "port": 3306, - "logging": false, - "pool": { - "max": 5, - "min": 0, - "acquire": 30000, - "idle": 10000 - }, - "timezone": "+08:00", - "define": { - "freezeTableName": true, - "underscored": true, - "charset": "utf8", - "collate": "utf8_general_ci", - "timestamps": false, - "paranoid": true - } - } - } - } - } + "version": "10.2.0", + "ws": { + "port": 8444, + "host": "ws://127.0.0.1:8444", + "control_port": 8445, + "control_host": "ws://127.0.0.1:8445" + }, + "wss": { + "port": 8444, + "host": "wss://域名 || wss://ip:8444", + "control_port": 8445, + "control_host": "wss://域名 || wss://ip:8445" + }, + "api": { + "port": 9092, + "router": { + "filter": { + "whiteDir": [], + "whiteFile": [ + "router.js" + ] + }, + "res": { + "/": "res/", + "/static": "static/" + } + } + }, + "manage": { + "room": "tlrtcfile", + "password": "tlrtcfile" + }, + "webrtc": { + "turn": { + "host": "turn服务地址", + "secret": "tl-rtc-file", + "username": "tl-rtc-file", + "credential": "tl-rtc-file" + }, + "stun": { + "host": "stun:stun.xten.com" + }, + "iceTransportPolicy": "all", + "options": { + "offerToReceiveAudio": 1, + "offerToReceiveVideo": 1 + } + }, + "openai": { + "apiKeys": [] + }, + "oss": { + "seafile": { + "repoid": "存储库id", + "host": "seafile私有网盘域名", + "username": "账号", + "password": "密码" + }, + "alyun": { + "AccessKey": "", + "SecretKey": "", + "bucket": "tl-rtc-file" + }, + "txyun": { + "AccessKey": "", + "SecretKey": "", + "bucket": "tl-rtc-file" + }, + "qiniuyun": { + "AccessKey": "", + "SecretKey": "", + "bucket": "tl-rtc-file" + } + }, + "notify": { + "open": false, + "qiwei": { + "normal": [ + "填写企业微信机器人key" + ], + "error": [ + "填写企业微信机器人key" + ] + } + }, + "db": { + "open": false, + "mysql": { + "host": "host地址", + "port": 3306, + "dbName": "数据库名称", + "user": "用户名", + "password": "密码", + "other": { + "sequelize": { + "dialect": "mysql", + "host": "host地址", + "port": 3306, + "logging": false, + "pool": { + "max": 5, + "min": 0, + "acquire": 30000, + "idle": 10000 + }, + "timezone": "+08:00", + "define": { + "freezeTableName": true, + "underscored": true, + "charset": "utf8", + "collate": "utf8_general_ci", + "timestamps": false, + "paranoid": true + } + } + } + } + } } \ No newline at end of file diff --git a/svr/conf/turn/turnserver.conf b/svr/conf/turn/turnserver.conf index b366d02..8c75c9c 100644 --- a/svr/conf/turn/turnserver.conf +++ b/svr/conf/turn/turnserver.conf @@ -1,636 +1,46 @@ -# Coturn TURN SERVER configuration file -# -# Boolean values note: where boolean value is supposed to be used, -# you can use '0', 'off', 'no', 'false', 'f' as 'false, -# and you can use '1', 'on', 'yes', 'true', 't' as 'true' -# If the value is missed, then it means 'true'. -# - - -cli-password=qwerty +#------------TURN BASE CONFIG------------# +#监听网卡 listening-device=eth0 -listening-ip=内网ip +#监听ip(内网ip) +listening-ip= +#监听端口(端口) listening-port=3478 -#tls-listening-port=5349 -external-ip=公网ip -#relay-threads=50 -#lt-cred-mech -user=用户名:密码 -realm=公网ip:3478 +#公网ip +external-ip= +#端口最小值 +min-port=49152 +#端口最大值 +min-port=55000 +#cli密码 +cli-password=qwerty +#后台运行 +daemon +#会话指纹 +fingerprint +#中等详细日志 +verbose +#长期凭证 +lt-cred-mech +#关闭tls +no-tls +#关闭dtls +no-dtls +#------------TURN USER CONFIG------------# +#用户账号密码 +user=tlrtcfile:tlrtcfile -# Listener interface device (optional, Linux only). -# NOT RECOMMENDED. -# -#listening-device=eth0 +#来源(域名或ip:port) +realm= -# TURN listener port for UDP and TCP (Default: 3478). -# Note: actually, TLS & DTLS sessions can connect to the -# "plain" TCP & UDP port(s), too - if allowed by configuration. -# -#listening-port=3478 +#------------TURN REST API USER CONFIG------------# -# TURN listener port for TLS (Default: 5349). -# Note: actually, "plain" TCP & UDP sessions can connect to the TLS & DTLS -# port(s), too - if allowed by configuration. The TURN server -# "automatically" recognizes the type of traffic. Actually, two listening -# endpoints (the "plain" one and the "tls" one) are equivalent in terms of -# functionality; but we keep both endpoints to satisfy the RFC 5766 specs. -# For secure TCP connections, we currently support SSL version 3 and -# TLS version 1.0, 1.1 and 1.2. -# For secure UDP connections, we support DTLS version 1. -# -#tls-listening-port=5349 - -# Alternative listening port for UDP and TCP listeners; -# default (or zero) value means "listening port plus one". -# This is needed for RFC 5780 support -# (STUN extension specs, NAT behavior discovery). The TURN Server -# supports RFC 5780 only if it is started with more than one -# listening IP address of the same family (IPv4 or IPv6). -# RFC 5780 is supported only by UDP protocol, other protocols -# are listening to that endpoint only for "symmetry". -# -#alt-listening-port=0 - -# Alternative listening port for TLS and DTLS protocols. -# Default (or zero) value means "TLS listening port plus one". -# -#alt-tls-listening-port=0 - -# Listener IP address of relay server. Multiple listeners can be specified. -# If no IP(s) specified in the config file or in the command line options, -# then all IPv4 and IPv6 system IPs will be used for listening. -# -#listening-ip=172.17.19.101 -#listening-ip=10.207.21.238 -#listening-ip=2607:f0d0:1002:51::4 - -# Auxiliary STUN/TURN server listening endpoint. -# Aux servers have almost full TURN and STUN functionality. -# The (minor) limitations are: -# -# 1) Auxiliary servers do not have alternative ports and -# they do not support STUN RFC 5780 functionality (CHANGE REQUEST). -# -# 2) Auxiliary servers also are never returning ALTERNATIVE-SERVER reply. -# -# Valid formats are 1.2.3.4:5555 for IPv4 and [1:2::3:4]:5555 for IPv6. -# -# There may be multiple aux-server options, each will be used for listening -# to client requests. -# -#aux-server=172.17.19.110:33478 -#aux-server=[2607:f0d0:1002:51::4]:33478 - -# (recommended for older Linuxes only) -# Automatically balance UDP traffic over auxiliary servers (if configured). -# The load balancing is using the ALTERNATE-SERVER mechanism. -# The TURN client must support 300 ALTERNATE-SERVER response for this -# functionality. -# -#udp-self-balance - -# Relay interface device for relay sockets (optional, Linux only). -# NOT RECOMMENDED. -# -#relay-device=eth1 - -# Relay address (the local IP address that will be used to relay the -# packets to the peer). -# Multiple relay addresses may be used. -# The same IP(s) can be used as both listening IP(s) and relay IP(s). -# -# If no relay IP(s) specified, then the turnserver will apply the default -# policy: it will decide itself which relay addresses to be used, and it -# will always be using the client socket IP address as the relay IP address -# of the TURN session (if the requested relay address family is the same -# as the family of the client socket). -# -#relay-ip=172.17.19.105 -#relay-ip=2607:f0d0:1002:51::5 - -# For Amazon EC2 users: -# -# TURN Server public/private address mapping, if the server is behind NAT. -# In that situation, if a -X is used in form "-X " then that ip will be reported -# as relay IP address of all allocations. This scenario works only in a simple case -# when one single relay address is be used, and no RFC5780 functionality is required. -# That single relay address must be mapped by NAT to the 'external' IP. -# The "external-ip" value, if not empty, is returned in XOR-RELAYED-ADDRESS field. -# For that 'external' IP, NAT must forward ports directly (relayed port 12345 -# must be always mapped to the same 'external' port 12345). -# -# In more complex case when more than one IP address is involved, -# that option must be used several times, each entry must -# have form "-X ", to map all involved addresses. -# RFC5780 NAT discovery STUN functionality will work correctly, -# if the addresses are mapped properly, even when the TURN server itself -# is behind A NAT. -# -# By default, this value is empty, and no address mapping is used. -# -#external-ip=60.70.80.91 -# -#OR: -# -#external-ip=60.70.80.91/172.17.19.101 -#external-ip=60.70.80.92/172.17.19.102 - - -# Number of the relay threads to handle the established connections -# (in addition to authentication thread and the listener thread). -# If explicitly set to 0 then application runs relay process in a -# single thread, in the same thread with the listener process -# (the authentication thread will still be a separate thread). -# -# If this parameter is not set, then the default OS-dependent -# thread pattern algorithm will be employed. Usually the default -# algorithm is the most optimal, so you have to change this option -# only if you want to make some fine tweaks. -# -# In the older systems (Linux kernel before 3.9), -# the number of UDP threads is always one thread per network listening -# endpoint - including the auxiliary endpoints - unless 0 (zero) or -# 1 (one) value is set. -# -#relay-threads=0 - -# Lower and upper bounds of the UDP relay endpoints: -# (default values are 49152 and 65535) -# -#min-port=49152 -#max-port=65535 - -# Uncomment to run TURN server in 'normal' 'moderate' verbose mode. -# By default the verbose mode is off. -#verbose - -# Uncomment to run TURN server in 'extra' verbose mode. -# This mode is very annoying and produces lots of output. -# Not recommended under any normal circumstances. -# -#Verbose - -# Uncomment to use fingerprints in the TURN messages. -# By default the fingerprints are off. -# -#fingerprint - -# Uncomment to use long-term credential mechanism. -# By default no credentials mechanism is used (any user allowed). -# -#lt-cred-mech - -# This option is opposite to lt-cred-mech. -# (TURN Server with no-auth option allows anonymous access). -# If neither option is defined, and no users are defined, -# then no-auth is default. If at least one user is defined, -# in this file or in command line or in usersdb file, then -# lt-cred-mech is default. -# -#no-auth - -# TURN REST API flag. -# Flag that sets a special authorization option that is based upon authentication secret. -# This feature can be used with the long-term authentication mechanism, only. -# This feature purpose is to support "TURN Server REST API", see -# "TURN REST API" link in the project's page -# https://github.com/coturn/coturn/ -# -# This option is used with timestamp: -# -# usercombo -> "timestamp:userid" -# turn user -> usercombo -# turn password -> base64(hmac(secret key, usercombo)) -# -# This allows TURN credentials to be accounted for a specific user id. -# If you don't have a suitable id, the timestamp alone can be used. -# This option is just turning on secret-based authentication. -# The actual value of the secret is defined either by option static-auth-secret, -# or can be found in the turn_secret table in the database (see below). -# +#开启rest api #use-auth-secret -# 'Static' authentication secret value (a string) for TURN REST API only. -# If not set, then the turn server -# will try to use the 'dynamic' value in turn_secret table -# in user database (if present). The database-stored value can be changed on-the-fly -# by a separate program, so this is why that other mode is 'dynamic'. -# -#static-auth-secret=north +#rest api账号密码 +#static-auth-secret=this-is-the-secret-configured-for-coturn-server -# Server name used for -# the oAuth authentication purposes. -# The default value is the realm name. -# -#server-name=blackdow.carleon.gov - -# Flag that allows oAuth authentication. -# -#oauth - -# 'Static' user accounts for long term credentials mechanism, only. -# This option cannot be used with TURN REST API. -# 'Static' user accounts are NOT dynamically checked by the turnserver process, -# so that they can NOT be changed while the turnserver is running. -# -#user=username1:key1 -#user=username2:key2 -# OR: -#user=username1:password1 -#user=username2:password2 -# -# Keys must be generated by turnadmin utility. The key value depends -# on user name, realm, and password: -# -# Example: -# $ turnadmin -k -u ninefingers -r north.gov -p youhavetoberealistic -# Output: 0xbc807ee29df3c9ffa736523fb2c4e8ee -# ('0x' in the beginning of the key is what differentiates the key from -# password. If it has 0x then it is a key, otherwise it is a password). -# -# The corresponding user account entry in the config file will be: -# -#user=ninefingers:0xbc807ee29df3c9ffa736523fb2c4e8ee -# Or, equivalently, with open clear password (less secure): -#user=ninefingers:youhavetoberealistic -# - -# SQLite database file name. -# -# Default file name is /var/db/turndb or /usr/local/var/db/turndb or -# /var/lib/turn/turndb. -# -#userdb=/var/db/turndb - -# PostgreSQL database connection string in the case that we are using PostgreSQL -# as the user database. -# This database can be used for long-term credential mechanism -# and it can store the secret value for secret-based timed authentication in TURN RESP API. -# See http://www.postgresql.org/docs/8.4/static/libpq-connect.html for 8.x PostgreSQL -# versions connection string format, see -# http://www.postgresql.org/docs/9.2/static/libpq-connect.html#LIBPQ-CONNSTRING -# for 9.x and newer connection string formats. -# -#psql-userdb="host= dbname= user= password= connect_timeout=30" - -# MySQL database connection string in the case that we are using MySQL -# as the user database. -# This database can be used for long-term credential mechanism -# and it can store the secret value for secret-based timed authentication in TURN RESP API. -# -# Optional connection string parameters for the secure communications (SSL): -# ca, capath, cert, key, cipher -# (see http://dev.mysql.com/doc/refman/5.1/en/ssl-options.html for the -# command options description). -# -# Use string format as below (space separated parameters, all optional): -# -#mysql-userdb="host= dbname= user= password= port= connect_timeout=" - -# MongoDB database connection string in the case that we are using MongoDB -# as the user database. -# This database can be used for long-term credential mechanism -# and it can store the secret value for secret-based timed authentication in TURN RESP API. -# Use string format is described at http://hergert.me/docs/mongo-c-driver/mongoc_uri.html -# -#mongo-userdb="mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]" - -# Redis database connection string in the case that we are using Redis -# as the user database. -# This database can be used for long-term credential mechanism -# and it can store the secret value for secret-based timed authentication in TURN RESP API. -# Use string format as below (space separated parameters, all optional): -# -#redis-userdb="ip= dbname= password= port= connect_timeout=" - -# Redis status and statistics database connection string, if used (default - empty, no Redis stats DB used). -# This database keeps allocations status information, and it can be also used for publishing -# and delivering traffic and allocation event notifications. -# The connection string has the same parameters as redis-userdb connection string. -# Use string format as below (space separated parameters, all optional): -# -#redis-statsdb="ip= dbname= password= port= connect_timeout=" - -# The default realm to be used for the users when no explicit -# origin/realm relationship was found in the database, or if the TURN -# server is not using any database (just the commands-line settings -# and the userdb file). Must be used with long-term credentials -# mechanism or with TURN REST API. -# -#realm=mycompany.org - -# The flag that sets the origin consistency -# check: across the session, all requests must have the same -# main ORIGIN attribute value (if the ORIGIN was -# initially used by the session). -# -#check-origin-consistency - -# Per-user allocation quota. -# default value is 0 (no quota, unlimited number of sessions per user). -# This option can also be set through the database, for a particular realm. -# -#user-quota=0 - -# Total allocation quota. -# default value is 0 (no quota). -# This option can also be set through the database, for a particular realm. -# -#total-quota=0 - -# Max bytes-per-second bandwidth a TURN session is allowed to handle -# (input and output network streams are treated separately). Anything above -# that limit will be dropped or temporary suppressed (within -# the available buffer limits). -# This option can also be set through the database, for a particular realm. -# -#max-bps=0 - -# -# Maximum server capacity. -# Total bytes-per-second bandwidth the TURN server is allowed to allocate -# for the sessions, combined (input and output network streams are treated separately). -# -# bps-capacity=0 - -# Uncomment if no UDP client listener is desired. -# By default UDP client listener is always started. -# -#no-udp - -# Uncomment if no TCP client listener is desired. -# By default TCP client listener is always started. -# -#no-tcp - -# Uncomment if no TLS client listener is desired. -# By default TLS client listener is always started. -# -#no-tls - -# Uncomment if no DTLS client listener is desired. -# By default DTLS client listener is always started. -# -#no-dtls - -# Uncomment if no UDP relay endpoints are allowed. -# By default UDP relay endpoints are enabled (like in RFC 5766). -# -#no-udp-relay - -# Uncomment if no TCP relay endpoints are allowed. -# By default TCP relay endpoints are enabled (like in RFC 6062). -# -#no-tcp-relay - -# Uncomment if extra security is desired, -# with nonce value having limited lifetime (600 secs). -# By default, the nonce value is unique for a session, -# but it has unlimited lifetime. With this option, -# the nonce lifetime is limited to 600 seconds, after that -# the client will get 438 error and will have to re-authenticate itself. -# -#stale-nonce - -# Certificate file. -# Use an absolute path or path relative to the -# configuration file. -# -#cert=/usr/local/etc/turn_server_cert.pem - -# Private key file. -# Use an absolute path or path relative to the -# configuration file. -# Use PEM file format. -# -#pkey=/usr/local/etc/turn_server_pkey.pem - -# Private key file password, if it is in encoded format. -# This option has no default value. -# -#pkey-pwd=... - -# Allowed OpenSSL cipher list for TLS/DTLS connections. -# Default value is "DEFAULT". -# -#cipher-list="DEFAULT" - -# CA file in OpenSSL format. -# Forces TURN server to verify the client SSL certificates. -# By default it is not set: there is no default value and the client -# certificate is not checked. -# -# Example: -#CA-file=/etc/ssh/id_rsa.cert - -# Curve name for EC ciphers, if supported by OpenSSL -# library (TLS and DTLS). The default value is prime256v1, -# if pre-OpenSSL 1.0.2 is used. With OpenSSL 1.0.2+, -# an optimal curve will be automatically calculated, if not defined -# by this option. -# -#ec-curve-name=prime256v1 - -# Use 566 bits predefined DH TLS key. Default size of the key is 1066. -# -#dh566 - -# Use 2066 bits predefined DH TLS key. Default size of the key is 1066. -# -#dh2066 - -# Use custom DH TLS key, stored in PEM format in the file. -# Flags --dh566 and --dh2066 are ignored when the DH key is taken from a file. -# -#dh-file= - -# Flag to prevent stdout log messages. -# By default, all log messages are going to both stdout and to -# the configured log file. With this option everything will be -# going to the configured log only (unless the log file itself is stdout). -# -#no-stdout-log - -# Option to set the log file name. -# By default, the turnserver tries to open a log file in -# /var/log, /var/tmp, /tmp and current directories directories -# (which open operation succeeds first that file will be used). -# With this option you can set the definite log file name. -# The special names are "stdout" and "-" - they will force everything -# to the stdout. Also, the "syslog" name will force everything to -# the system log (syslog). -# In the runtime, the logfile can be reset with the SIGHUP signal -# to the turnserver process. -# -#log-file=/var/tmp/turn.log - -# Option to redirect all log output into system log (syslog). -# -#syslog - -# This flag means that no log file rollover will be used, and the log file -# name will be constructed as-is, without PID and date appendage. -# This option can be used, for example, together with the logrotate tool. -# -#simple-log - -# Option to set the "redirection" mode. The value of this option -# will be the address of the alternate server for UDP & TCP service in form of -# [:]. The server will send this value in the attribute -# ALTERNATE-SERVER, with error 300, on ALLOCATE request, to the client. -# Client will receive only values with the same address family -# as the client network endpoint address family. -# See RFC 5389 and RFC 5766 for ALTERNATE-SERVER functionality description. -# The client must use the obtained value for subsequent TURN communications. -# If more than one --alternate-server options are provided, then the functionality -# can be more accurately described as "load-balancing" than a mere "redirection". -# If the port number is omitted, then the default port -# number 3478 for the UDP/TCP protocols will be used. -# Colon (:) characters in IPv6 addresses may conflict with the syntax of -# the option. To alleviate this conflict, literal IPv6 addresses are enclosed -# in square brackets in such resource identifiers, for example: -# [2001:db8:85a3:8d3:1319:8a2e:370:7348]:3478 . -# Multiple alternate servers can be set. They will be used in the -# round-robin manner. All servers in the pool are considered of equal weight and -# the load will be distributed equally. For example, if we have 4 alternate servers, -# then each server will receive 25% of ALLOCATE requests. A alternate TURN server -# address can be used more than one time with the alternate-server option, so this -# can emulate "weighting" of the servers. -# -# Examples: -#alternate-server=1.2.3.4:5678 -#alternate-server=11.22.33.44:56789 -#alternate-server=5.6.7.8 -#alternate-server=[2001:db8:85a3:8d3:1319:8a2e:370:7348]:3478 - -# Option to set alternative server for TLS & DTLS services in form of -# :. If the port number is omitted, then the default port -# number 5349 for the TLS/DTLS protocols will be used. See the previous -# option for the functionality description. -# -# Examples: -#tls-alternate-server=1.2.3.4:5678 -#tls-alternate-server=11.22.33.44:56789 -#tls-alternate-server=[2001:db8:85a3:8d3:1319:8a2e:370:7348]:3478 - -# Option to suppress TURN functionality, only STUN requests will be processed. -# Run as STUN server only, all TURN requests will be ignored. -# By default, this option is NOT set. -# -#stun-only - -# Option to suppress STUN functionality, only TURN requests will be processed. -# Run as TURN server only, all STUN requests will be ignored. -# By default, this option is NOT set. -# -#no-stun - -# This is the timestamp/username separator symbol (character) in TURN REST API. -# The default value is ':'. -# rest-api-separator=: - -# Flag that can be used to disallow peers on the loopback addresses (127.x.x.x and ::1). -# This is an extra security measure. -# -#no-loopback-peers - -# Flag that can be used to disallow peers on well-known broadcast addresses (224.0.0.0 and above, and FFXX:*). -# This is an extra security measure. -# -#no-multicast-peers - -# Option to set the max time, in seconds, allowed for full allocation establishment. -# Default is 60 seconds. -# -#max-allocate-timeout=60 - -# Option to allow or ban specific ip addresses or ranges of ip addresses. -# If an ip address is specified as both allowed and denied, then the ip address is -# considered to be allowed. This is useful when you wish to ban a range of ip -# addresses, except for a few specific ips within that range. -# -# This can be used when you do not want users of the turn server to be able to access -# machines reachable by the turn server, but would otherwise be unreachable from the -# internet (e.g. when the turn server is sitting behind a NAT) -# -# Examples: -# denied-peer-ip=83.166.64.0-83.166.95.255 -# allowed-peer-ip=83.166.68.45 - -# File name to store the pid of the process. -# Default is /var/run/turnserver.pid (if superuser account is used) or -# /var/tmp/turnserver.pid . -# -#pidfile="/var/run/turnserver.pid" - -# Require authentication of the STUN Binding request. -# By default, the clients are allowed anonymous access to the STUN Binding functionality. -# -#secure-stun - -# Mobility with ICE (MICE) specs support. -# -#mobility - -# User name to run the process. After the initialization, the turnserver process -# will make an attempt to change the current user ID to that user. -# -#proc-user= - -# Group name to run the process. After the initialization, the turnserver process -# will make an attempt to change the current group ID to that group. -# -#proc-group= - -# Turn OFF the CLI support. -# By default it is always ON. -# See also options cli-ip and cli-port. -# -#no-cli - -#Local system IP address to be used for CLI server endpoint. Default value -# is 127.0.0.1. -# -#cli-ip=127.0.0.1 - -# CLI server port. Default is 5766. -# -#cli-port=5766 - -# CLI access password. Default is empty (no password). -# For the security reasons, it is recommended to use the encrypted -# for of the password (see the -P command in the turnadmin utility). -# -# Secure form for password 'qwerty': -# -#cli-password=$5$79a316b350311570$81df9cfb9af7f5e5a76eada31e7097b663a0670f99a3c07ded3f1c8e59c5658a -# -# Or unsecure form for the same paassword: -# -#cli-password=qwerty - -# Server relay. NON-STANDARD AND DANGEROUS OPTION. -# Only for those applications when we want to run -# server applications on the relay endpoints. -# This option eliminates the IP permissions check on -# the packets incoming to the relay endpoints. -# -#server-relay - -# Maximum number of output sessions in ps CLI command. -# This value can be changed on-the-fly in CLI. The default value is 256. -# -#cli-max-output-sessions - -# Set network engine type for the process (for internal purposes). -# -#ne=[1|2|3] - -# Do not allow an TLS/DTLS version of protocol -# -#no-tlsv1 -#no-tlsv1_1 -#no-tlsv1_2 +#来源(域名或ip:port) +#realm= \ No newline at end of file diff --git a/svr/package-lock.json b/svr/package-lock.json index c06cc7c..cf543ab 100644 --- a/svr/package-lock.json +++ b/svr/package-lock.json @@ -1,2357 +1,2357 @@ { - "name": "tl-rtc-file", - "version": "1.0.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@types/debug": { - "version": "4.1.8", - "resolved": "https://registry.npmmirror.com/@types/debug/-/debug-4.1.8.tgz", - "integrity": "sha512-/vPO1EPOs306Cvhwv7KfVfYvOJqA/S/AXjaHQiJboCZzcNDb+TIJFN9/2C9DZ//ijSKWioNyUxD792QmDJ+HKQ==", - "requires": { - "@types/ms": "*" - } - }, - "@types/ms": { - "version": "0.7.31", - "resolved": "https://registry.npmmirror.com/@types/ms/-/ms-0.7.31.tgz", - "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==" - }, - "@types/node": { - "version": "20.2.5", - "resolved": "https://registry.npmmirror.com/@types/node/-/node-20.2.5.tgz", - "integrity": "sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ==" - }, - "@types/validator": { - "version": "13.7.17", - "resolved": "https://registry.npmmirror.com/@types/validator/-/validator-13.7.17.tgz", - "integrity": "sha512-aqayTNmeWrZcvnG2MG9eGYI6b7S5fl+yKgPs6bAjOTwPS316R5SxBGKvtSExfyoJU7pIeHJfsHI0Ji41RVMkvQ==" - }, - "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==", - "requires": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - } - }, - "after": { - "version": "0.8.2", - "resolved": "https://registry.npmmirror.com/after/-/after-0.8.2.tgz", - "integrity": "sha512-QbJ0NTQ/I9DI3uSJA4cbexiwQeRAfjPScqIbSjUDd9TOrcg6pTkdgziesOqxBMBzit8vFCTwrP27t13vFOORRA==" - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmmirror.com/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==" - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmmirror.com/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" - }, - "are-we-there-yet": { - "version": "1.1.7", - "resolved": "https://registry.npmmirror.com/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", - "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" - }, - "arraybuffer.slice": { - "version": "0.0.7", - "resolved": "https://registry.npmmirror.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", - "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==" - }, - "asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmmirror.com/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==" - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmmirror.com/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==" - }, - "aws4": { - "version": "1.12.0", - "resolved": "https://registry.npmmirror.com/aws4/-/aws4-1.12.0.tgz", - "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==" - }, - "backo2": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/backo2/-/backo2-1.0.2.tgz", - "integrity": "sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA==" - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "base64-arraybuffer": { - "version": "0.1.4", - "resolved": "https://registry.npmmirror.com/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz", - "integrity": "sha512-a1eIFi4R9ySrbiMuyTGx5e92uRH5tQY6kArNcFaKBUleIoLjdjBg7Zxm3Mqm3Kmkf27HLR/1fnxX9q8GQ7Iavg==" - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, - "base64id": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/base64id/-/base64id-2.0.0.tgz", - "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==" - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmmirror.com/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" - }, - "bl": { - "version": "4.1.0", - "resolved": "https://registry.npmmirror.com/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "requires": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "blob": { - "version": "0.0.5", - "resolved": "https://registry.npmmirror.com/blob/-/blob-0.0.5.tgz", - "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==" - }, - "body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmmirror.com/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", - "requires": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.1", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmmirror.com/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "requires": { - "fill-range": "^7.0.1" - } - }, - "browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmmirror.com/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==" - }, - "buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmmirror.com/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmmirror.com/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmmirror.com/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==" - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmmirror.com/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "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==", - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.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" - } - }, - "chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmmirror.com/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmmirror.com/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==" - }, - "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==", - "requires": { - "color-name": "~1.1.4" - } - }, - "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==" - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "component-bind": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/component-bind/-/component-bind-1.0.0.tgz", - "integrity": "sha512-WZveuKPeKAG9qY+FkYDeADzdHyTYdIboXS59ixDeRJL5ZhxpqUnxSOwop4FQjMsiYm3/Or8cegVbpAHNA7pHxw==" - }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmmirror.com/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" - }, - "component-inherit": { - "version": "0.0.3", - "resolved": "https://registry.npmmirror.com/component-inherit/-/component-inherit-0.0.3.tgz", - "integrity": "sha512-w+LhYREhatpVqTESyGFg3NlP6Iu0kEKUHETY9GoZP/pQyW4mHFZuFWRUCIqVPZ36ueVLtoOEZaAqbCF2RDndaA==" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" - }, - "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==", - "requires": { - "safe-buffer": "5.2.1" - } - }, - "content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmmirror.com/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" - }, - "cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmmirror.com/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmmirror.com/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" - }, - "cross-env": { - "version": "5.2.1", - "resolved": "https://registry.npmmirror.com/cross-env/-/cross-env-5.2.1.tgz", - "integrity": "sha512-1yHhtcfAd1r4nwQgknowuUNfIT9E8dOMMspC36g45dN+iD1blloi7xp8X/xAIDnjHWyt1uQ8PHk2fkNaym7soQ==", - "requires": { - "cross-spawn": "^6.0.5" - } - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmmirror.com/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", - "requires": { - "assert-plus": "^1.0.0" - } - }, - "data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmmirror.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==" - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==" - }, - "decompress-response": { - "version": "4.2.1", - "resolved": "https://registry.npmmirror.com/decompress-response/-/decompress-response-4.2.1.tgz", - "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", - "requires": { - "mimic-response": "^2.0.0" - } - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmmirror.com/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" - }, - "delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" - }, - "denque": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/denque/-/denque-2.1.0.tgz", - "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==" - }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" - }, - "destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" - }, - "detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmmirror.com/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==" - }, - "diff": { - "version": "5.0.0", - "resolved": "https://registry.npmmirror.com/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==" - }, - "dottie": { - "version": "2.0.3", - "resolved": "https://registry.npmmirror.com/dottie/-/dottie-2.0.3.tgz", - "integrity": "sha512-4liA0PuRkZWQFQjwBypdxPfZaRWiv5tkhMXY2hzsa2pNf5s7U3m9cwUchfNKe8wZQxdGPQQzO6Rm2uGe0rvohQ==" - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmmirror.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "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==" - }, - "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==" - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" - }, - "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==", - "requires": { - "once": "^1.4.0" - } - }, - "engine.io": { - "version": "3.6.1", - "resolved": "https://registry.npmmirror.com/engine.io/-/engine.io-3.6.1.tgz", - "integrity": "sha512-dfs8EVg/i7QjFsXxn7cCRQ+Wai1G1TlEvHhdYEi80fxn5R1vZ2K661O6v/rezj1FP234SZ14r9CmJke99iYDGg==", - "requires": { - "accepts": "~1.3.4", - "base64id": "2.0.0", - "cookie": "~0.4.1", - "debug": "~4.1.0", - "engine.io-parser": "~2.2.0", - "ws": "~7.4.2" - }, - "dependencies": { - "cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmmirror.com/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==" - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmmirror.com/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - } - } - }, - "engine.io-client": { - "version": "3.5.3", - "resolved": "https://registry.npmmirror.com/engine.io-client/-/engine.io-client-3.5.3.tgz", - "integrity": "sha512-qsgyc/CEhJ6cgMUwxRRtOndGVhIu5hpL5tR4umSpmX/MvkFoIxUTM7oFMDQumHNzlNLwSVy6qhstFPoWTf7dOw==", - "requires": { - "component-emitter": "~1.3.0", - "component-inherit": "0.0.3", - "debug": "~3.1.0", - "engine.io-parser": "~2.2.0", - "has-cors": "1.1.0", - "indexof": "0.0.1", - "parseqs": "0.0.6", - "parseuri": "0.0.6", - "ws": "~7.4.2", - "xmlhttprequest-ssl": "~1.6.2", - "yeast": "0.1.2" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmmirror.com/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - } - } - }, - "engine.io-parser": { - "version": "2.2.1", - "resolved": "https://registry.npmmirror.com/engine.io-parser/-/engine.io-parser-2.2.1.tgz", - "integrity": "sha512-x+dN/fBH8Ro8TFwJ+rkB2AmuVw9Yu2mockR/p3W8f8YtExwFgDvBDi0GWyb4ZLkpahtDGZgtr3zLovanJghPqg==", - "requires": { - "after": "0.8.2", - "arraybuffer.slice": "~0.0.7", - "base64-arraybuffer": "0.1.4", - "blob": "0.0.5", - "has-binary2": "~1.0.2" - } - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmmirror.com/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" - }, - "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==" - }, - "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==" - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmmirror.com/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" - }, - "expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmmirror.com/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" - }, - "express": { - "version": "4.18.2", - "resolved": "https://registry.npmmirror.com/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", - "requires": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.1", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.5.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.11.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmmirror.com/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmmirror.com/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==" - }, - "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==" - }, - "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==" - }, - "fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmmirror.com/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "requires": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmmirror.com/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - } - }, - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmmirror.com/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "flat": { - "version": "5.0.2", - "resolved": "https://registry.npmmirror.com/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==" - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==" - }, - "form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, - "formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmmirror.com/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "requires": { - "fetch-blob": "^3.1.2" - } - }, - "forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmmirror.com/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmmirror.com/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" - }, - "fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmmirror.com/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg==", - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==" - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, - "generate-function": { - "version": "2.3.1", - "resolved": "https://registry.npmmirror.com/generate-function/-/generate-function-2.3.1.tgz", - "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", - "requires": { - "is-property": "^1.0.2" - } - }, - "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==" - }, - "get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" - } - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmmirror.com/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "requires": { - "assert-plus": "^1.0.0" - } - }, - "github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmmirror.com/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" - }, - "glob": { - "version": "7.2.0", - "resolved": "https://registry.npmmirror.com/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "dependencies": { - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "requires": { - "brace-expansion": "^1.1.7" - } - } - } - }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "requires": { - "is-glob": "^4.0.1" - } - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==" - }, - "har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmmirror.com/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "requires": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmmirror.com/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-binary2": { - "version": "1.0.3", - "resolved": "https://registry.npmmirror.com/has-binary2/-/has-binary2-1.0.3.tgz", - "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", - "requires": { - "isarray": "2.0.1" - }, - "dependencies": { - "isarray": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/isarray/-/isarray-2.0.1.tgz", - "integrity": "sha512-c2cu3UxbI+b6kR3fy0nRnAhodsvR9dx7U5+znCOzdj6IfP3upFURTr0Xl5BlQZNKZjEtxrmVyfSdeE3O57smoQ==" - } - } - }, - "has-cors": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/has-cors/-/has-cors-1.1.0.tgz", - "integrity": "sha512-g5VNKdkFuUuVCP9gYfDJHjK2nqdQJ7aDLTnycnc2+RvsOQbuLdF5pm7vuE5J76SEBIQjs4kQY/BWq74JUmjbXA==" - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==" - }, - "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" - }, - "has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" - }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" - }, - "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==", - "requires": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - } - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - }, - "indexof": { - "version": "0.0.1", - "resolved": "https://registry.npmmirror.com/indexof/-/indexof-0.0.1.tgz", - "integrity": "sha512-i0G7hLJ1z0DE8dsqJa2rycj9dBmNKgXBvotXtZYXakU9oivfB9Uj2ZBC27qqef2U58/ZLwalxa1X/RDCdkHtVg==" - }, - "inflection": { - "version": "1.13.4", - "resolved": "https://registry.npmmirror.com/inflection/-/inflection-1.13.4.tgz", - "integrity": "sha512-6I/HUDeYFfuNCVS3td055BaXBwKYuzw7K3ExVMStBowKo9oOAMJIXIHvdyR3iboTCp1b+1i5DSkIZTcwIktuDw==" - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmmirror.com/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" - }, - "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==" - }, - "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==", - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" - }, - "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==" - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" - }, - "is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==" - }, - "is-property": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/is-property/-/is-property-1.0.2.tgz", - "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==" - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" - }, - "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==" - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmmirror.com/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "requires": { - "argparse": "^2.0.1" - } - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmmirror.com/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==" - }, - "json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmmirror.com/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" - }, - "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==" - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmmirror.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" - }, - "jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmmirror.com/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - } - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmmirror.com/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "requires": { - "p-locate": "^5.0.0" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "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==", - "requires": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - } - }, - "long": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" - }, - "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==", - "requires": { - "yallist": "^4.0.0" - } - }, - "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==" - }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmmirror.com/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" - }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" - }, - "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==", - "requires": { - "mime-db": "1.52.0" - } - }, - "mimic-response": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/mimic-response/-/mimic-response-2.1.0.tgz", - "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==" - }, - "minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", - "requires": { - "brace-expansion": "^2.0.1" - }, - "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "requires": { - "balanced-match": "^1.0.0" - } - } - } - }, - "minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmmirror.com/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" - }, - "mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmmirror.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" - }, - "mocha": { - "version": "10.2.0", - "resolved": "https://registry.npmmirror.com/mocha/-/mocha-10.2.0.tgz", - "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", - "requires": { - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.2.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "nanoid": "3.3.3", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmmirror.com/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "requires": { - "ms": "2.1.2" - }, - "dependencies": { - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - } - } - }, - "moment": { - "version": "2.29.4", - "resolved": "https://registry.npmmirror.com/moment/-/moment-2.29.4.tgz", - "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" - }, - "moment-timezone": { - "version": "0.5.43", - "resolved": "https://registry.npmmirror.com/moment-timezone/-/moment-timezone-0.5.43.tgz", - "integrity": "sha512-72j3aNyuIsDxdF1i7CEgV2FfxM1r6aaqJyLB2vwb33mXYyoyLly+F1zbWqhA3/bVIoJ4szlUoMbUnVdid32NUQ==", - "requires": { - "moment": "^2.29.4" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "mysql2": { - "version": "2.3.3", - "resolved": "https://registry.npmmirror.com/mysql2/-/mysql2-2.3.3.tgz", - "integrity": "sha512-wxJUev6LgMSgACDkb/InIFxDprRa6T95+VEoR+xPvtngtccNH2dGjEB/fVZ8yg1gWv1510c9CvXuJHi5zUm0ZA==", - "requires": { - "denque": "^2.0.1", - "generate-function": "^2.3.1", - "iconv-lite": "^0.6.3", - "long": "^4.0.0", - "lru-cache": "^6.0.0", - "named-placeholders": "^1.1.2", - "seq-queue": "^0.0.5", - "sqlstring": "^2.3.2" - }, - "dependencies": { - "iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - } - } - }, - "named-placeholders": { - "version": "1.1.3", - "resolved": "https://registry.npmmirror.com/named-placeholders/-/named-placeholders-1.1.3.tgz", - "integrity": "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==", - "requires": { - "lru-cache": "^7.14.1" - }, - "dependencies": { - "lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==" - } - } - }, - "nan": { - "version": "2.17.0", - "resolved": "https://registry.npmmirror.com/nan/-/nan-2.17.0.tgz", - "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==" - }, - "nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==" - }, - "napi-build-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" - }, - "negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmmirror.com/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" - }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmmirror.com/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" - }, - "node-abi": { - "version": "2.30.1", - "resolved": "https://registry.npmmirror.com/node-abi/-/node-abi-2.30.1.tgz", - "integrity": "sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w==", - "requires": { - "semver": "^5.4.1" - } - }, - "node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==" - }, - "node-fetch": { - "version": "3.1.0", - "resolved": "https://registry.npmmirror.com/node-fetch/-/node-fetch-3.1.0.tgz", - "integrity": "sha512-QU0WbIfMUjd5+MUzQOYhenAazakV7Irh1SGkWCsRzBwvm4fAhzEUaHMJ6QLP7gWT6WO9/oH2zhKMMGMuIrDyKw==", - "requires": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.2", - "formdata-polyfill": "^4.0.10" - } - }, - "noop-logger": { - "version": "0.1.1", - "resolved": "https://registry.npmmirror.com/noop-logger/-/noop-logger-0.1.1.tgz", - "integrity": "sha512-6kM8CLXvuW5crTxsAtva2YLrRrDaiTIkIePWs9moLHqbFWT94WpNFjwS/5dfLfECg5i/lkmw3aoqVidxt23TEQ==" - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" - }, - "npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmmirror.com/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==" - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmmirror.com/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" - }, - "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==" - }, - "object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==" - }, - "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==", - "requires": { - "ee-first": "1.1.1" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmmirror.com/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "requires": { - "wrappy": "1" - } - }, - "openai": { - "version": "1.1.3", - "resolved": "https://registry.npmmirror.com/openai/-/openai-1.1.3.tgz", - "integrity": "sha512-G+VounGq9lSo15Swc5wyT2tgtI+9bCw9N51Vryy/UNwSpYCjtF3lFDQOjak6ELqRmqHBpMltzVV1R0svrk3QDQ==", - "requires": { - "form-data": "4.0.0", - "node-fetch": "3.1.0", - "openai": "^1.1.2" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmmirror.com/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmmirror.com/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "requires": { - "p-limit": "^3.0.2" - } - }, - "parseqs": { - "version": "0.0.6", - "resolved": "https://registry.npmmirror.com/parseqs/-/parseqs-0.0.6.tgz", - "integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w==" - }, - "parseuri": { - "version": "0.0.6", - "resolved": "https://registry.npmmirror.com/parseuri/-/parseuri-0.0.6.tgz", - "integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow==" - }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmmirror.com/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" - }, - "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==" - }, - "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==" - }, - "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==" - }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmmirror.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" - }, - "pg-connection-string": { - "version": "2.6.0", - "resolved": "https://registry.npmmirror.com/pg-connection-string/-/pg-connection-string-2.6.0.tgz", - "integrity": "sha512-x14ibktcwlHKoHxx9X3uTVW9zIGR41ZB6QNhHb21OPNdCCO3NaRnpJuwKIQSR4u+Yqjx4HCvy7Hh7VSy1U4dGg==" - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" - }, - "pngjs": { - "version": "7.0.0", - "resolved": "https://registry.npmmirror.com/pngjs/-/pngjs-7.0.0.tgz", - "integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==" - }, - "prebuild-install": { - "version": "5.3.6", - "resolved": "https://registry.npmmirror.com/prebuild-install/-/prebuild-install-5.3.6.tgz", - "integrity": "sha512-s8Aai8++QQGi4sSbs/M1Qku62PFK49Jm1CbgXklGz4nmHveDq0wzJkg7Na5QbnO1uNH8K7iqx2EQ/mV0MZEmOg==", - "requires": { - "detect-libc": "^1.0.3", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^2.7.0", - "noop-logger": "^0.1.1", - "npmlog": "^4.0.1", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^3.0.3", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0", - "which-pm-runs": "^1.0.0" - } - }, - "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==" - }, - "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==", - "requires": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - } - }, - "psl": { - "version": "1.9.0", - "resolved": "https://registry.npmmirror.com/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmmirror.com/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==" - }, - "qs": { - "version": "6.11.0", - "resolved": "https://registry.npmmirror.com/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "requires": { - "side-channel": "^1.0.4" - } - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "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==" - }, - "raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmmirror.com/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", - "requires": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - } - }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmmirror.com/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==" - } - } - }, - "readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "requires": { - "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" - }, - "dependencies": { - "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==" - } - } - }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmmirror.com/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "requires": { - "picomatch": "^2.2.1" - } - }, - "request": { - "version": "2.88.2", - "resolved": "https://registry.npmmirror.com/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "dependencies": { - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmmirror.com/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "qs": { - "version": "6.5.3", - "resolved": "https://registry.npmmirror.com/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==" - } - } - }, - "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==" - }, - "retry-as-promised": { - "version": "7.0.4", - "resolved": "https://registry.npmmirror.com/retry-as-promised/-/retry-as-promised-7.0.4.tgz", - "integrity": "sha512-XgmCoxKWkDofwH8WddD0w85ZfqYz+ZHlr5yo+3YUCfycWawU56T5ckWXsScsj5B8tqUcIG67DxXByo3VUgiAdA==" - }, - "robotjs": { - "version": "0.6.0", - "resolved": "https://registry.npmmirror.com/robotjs/-/robotjs-0.6.0.tgz", - "integrity": "sha512-6pRWI3d+CBZqCXT/rsJfabbZoELua+jTeXilG27F8Jvix/J2BYZ0O7Tly2WCmXyqw5xYdCvOwvCeLRHEtXkt4w==", - "requires": { - "nan": "^2.14.0", - "node-abi": "^2.13.0", - "prebuild-install": "^5.3.3" - } - }, - "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==" - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmmirror.com/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - }, - "send": { - "version": "0.18.0", - "resolved": "https://registry.npmmirror.com/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "requires": { - "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" - }, - "dependencies": { - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - } - } - }, - "seq-queue": { - "version": "0.0.5", - "resolved": "https://registry.npmmirror.com/seq-queue/-/seq-queue-0.0.5.tgz", - "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==" - }, - "sequelize": { - "version": "6.31.1", - "resolved": "https://registry.npmmirror.com/sequelize/-/sequelize-6.31.1.tgz", - "integrity": "sha512-cahWtRrYLjqoZP/aurGBoaxn29qQCF4bxkAUPEQ/ozjJjt6mtL4Q113S3N39mQRmX5fgxRbli+bzZARP/N51eg==", - "requires": { - "@types/debug": "^4.1.7", - "@types/validator": "^13.7.1", - "debug": "^4.3.3", - "dottie": "^2.0.2", - "inflection": "^1.13.2", - "lodash": "^4.17.21", - "moment": "^2.29.1", - "moment-timezone": "^0.5.35", - "pg-connection-string": "^2.5.0", - "retry-as-promised": "^7.0.3", - "semver": "^7.3.5", - "sequelize-pool": "^7.1.0", - "toposort-class": "^1.0.1", - "uuid": "^8.3.2", - "validator": "^13.7.0", - "wkx": "^0.5.0" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmmirror.com/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "semver": { - "version": "7.5.1", - "resolved": "https://registry.npmmirror.com/semver/-/semver-7.5.1.tgz", - "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", - "requires": { - "lru-cache": "^6.0.0" - } - }, - "sequelize-pool": { - "version": "7.1.0", - "resolved": "https://registry.npmmirror.com/sequelize-pool/-/sequelize-pool-7.1.0.tgz", - "integrity": "sha512-G9c0qlIWQSK29pR/5U2JF5dDQeqqHRragoyahj/Nx4KOOQ3CPPfzxnfqFPCSB7x5UgjOgnZ61nSxz+fjDpRlJg==" - }, - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmmirror.com/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" - } - } - }, - "sequelize-pool": { - "version": "6.1.0", - "resolved": "https://registry.npmmirror.com/sequelize-pool/-/sequelize-pool-6.1.0.tgz", - "integrity": "sha512-4YwEw3ZgK/tY/so+GfnSgXkdwIJJ1I32uZJztIEgZeAO6HMgj64OzySbWLgxj+tXhZCJnzRfkY9gINw8Ft8ZMg==" - }, - "serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmmirror.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "requires": { - "randombytes": "^2.1.0" - } - }, - "serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmmirror.com/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - } - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" - }, - "setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, - "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==", - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==" - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "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==" - }, - "simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==" - }, - "simple-get": { - "version": "3.1.1", - "resolved": "https://registry.npmmirror.com/simple-get/-/simple-get-3.1.1.tgz", - "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", - "requires": { - "decompress-response": "^4.2.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "socket.io": { - "version": "2.5.0", - "resolved": "https://registry.npmmirror.com/socket.io/-/socket.io-2.5.0.tgz", - "integrity": "sha512-gGunfS0od3VpwDBpGwVkzSZx6Aqo9uOcf1afJj2cKnKFAoyl16fvhpsUhmUFd4Ldbvl5JvRQed6eQw6oQp6n8w==", - "requires": { - "debug": "~4.1.0", - "engine.io": "~3.6.0", - "has-binary2": "~1.0.2", - "socket.io-adapter": "~1.1.0", - "socket.io-client": "2.5.0", - "socket.io-parser": "~3.4.0" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmmirror.com/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - } - } - }, - "socket.io-adapter": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz", - "integrity": "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==" - }, - "socket.io-client": { - "version": "2.5.0", - "resolved": "https://registry.npmmirror.com/socket.io-client/-/socket.io-client-2.5.0.tgz", - "integrity": "sha512-lOO9clmdgssDykiOmVQQitwBAF3I6mYcQAo7hQ7AM6Ny5X7fp8hIJ3HcQs3Rjz4SoggoxA1OgrQyY8EgTbcPYw==", - "requires": { - "backo2": "1.0.2", - "component-bind": "1.0.0", - "component-emitter": "~1.3.0", - "debug": "~3.1.0", - "engine.io-client": "~3.5.0", - "has-binary2": "~1.0.2", - "indexof": "0.0.1", - "parseqs": "0.0.6", - "parseuri": "0.0.6", - "socket.io-parser": "~3.3.0", - "to-array": "0.1.4" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmmirror.com/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - }, - "isarray": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/isarray/-/isarray-2.0.1.tgz", - "integrity": "sha512-c2cu3UxbI+b6kR3fy0nRnAhodsvR9dx7U5+znCOzdj6IfP3upFURTr0Xl5BlQZNKZjEtxrmVyfSdeE3O57smoQ==" - }, - "socket.io-parser": { - "version": "3.3.3", - "resolved": "https://registry.npmmirror.com/socket.io-parser/-/socket.io-parser-3.3.3.tgz", - "integrity": "sha512-qOg87q1PMWWTeO01768Yh9ogn7chB9zkKtQnya41Y355S0UmpXgpcrFwAgjYJxu9BdKug5r5e9YtVSeWhKBUZg==", - "requires": { - "component-emitter": "~1.3.0", - "debug": "~3.1.0", - "isarray": "2.0.1" - } - } - } - }, - "socket.io-parser": { - "version": "3.4.3", - "resolved": "https://registry.npmmirror.com/socket.io-parser/-/socket.io-parser-3.4.3.tgz", - "integrity": "sha512-1rE4dZN3kCI/E5wixd393hmbqa78vVpkKmnEJhLeWoS/C5hbFYAbcSfnWoaVH43u9ToUVtzKjguxEZq+1XZfCQ==", - "requires": { - "component-emitter": "1.2.1", - "debug": "~4.1.0", - "isarray": "2.0.1" - }, - "dependencies": { - "component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmmirror.com/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha512-jPatnhd33viNplKjqXKRkGU345p263OIWzDL2wH3LGIGp5Kojo+uXizHmOADRvhGFFTnJqX3jBAKP6vvmSDKcA==" - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmmirror.com/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - }, - "isarray": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/isarray/-/isarray-2.0.1.tgz", - "integrity": "sha512-c2cu3UxbI+b6kR3fy0nRnAhodsvR9dx7U5+znCOzdj6IfP3upFURTr0Xl5BlQZNKZjEtxrmVyfSdeE3O57smoQ==" - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - } - } - }, - "sqlstring": { - "version": "2.3.3", - "resolved": "https://registry.npmmirror.com/sqlstring/-/sqlstring-2.3.3.tgz", - "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==" - }, - "sshpk": { - "version": "1.17.0", - "resolved": "https://registry.npmmirror.com/sshpk/-/sshpk-1.17.0.tgz", - "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, - "statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" - }, - "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==", - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "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==", - "requires": { - "safe-buffer": "~5.1.0" - }, - "dependencies": { - "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==" - } - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "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==" - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "requires": { - "has-flag": "^4.0.0" - } - }, - "tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmmirror.com/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "requires": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmmirror.com/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "requires": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "to-array": { - "version": "0.1.4", - "resolved": "https://registry.npmmirror.com/to-array/-/to-array-0.1.4.tgz", - "integrity": "sha512-LhVdShQD/4Mk4zXNroIQZJC+Ap3zgLcDuwEdcmLv9CCO73NWockQDwyUnW/m8VX/EElfL6FcYx7EeutN4HJA6A==" - }, - "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==", - "requires": { - "is-number": "^7.0.0" - } - }, - "toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" - }, - "toposort-class": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/toposort-class/-/toposort-class-1.0.1.tgz", - "integrity": "sha512-OsLcGGbYF3rMjPUf8oKktyvCiUxSbqMMS39m33MAjLTC1DVIH6x3WSt63/M77ihI09+Sdfk1AXvfhCEeUmC7mg==" - }, - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmmirror.com/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmmirror.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmmirror.com/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==" - }, - "type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmmirror.com/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - } - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmmirror.com/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "requires": { - "punycode": "^2.1.0" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "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==" - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmmirror.com/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" - }, - "validator": { - "version": "13.9.0", - "resolved": "https://registry.npmmirror.com/validator/-/validator-13.9.0.tgz", - "integrity": "sha512-B+dGG8U3fdtM0/aNK4/X8CXq/EcxU2WPrPEkJGslb47qyHsxmbggTWK0yEA4qnYVNF+nxNlN88o14hIcPmSIEA==" - }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmmirror.com/verror/-/verror-1.10.0.tgz", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "web-streams-polyfill": { - "version": "3.2.1", - "resolved": "https://registry.npmmirror.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", - "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==" - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmmirror.com/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "requires": { - "isexe": "^2.0.0" - } - }, - "which-pm-runs": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/which-pm-runs/-/which-pm-runs-1.1.0.tgz", - "integrity": "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==" - }, - "wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmmirror.com/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "requires": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "wkx": { - "version": "0.5.0", - "resolved": "https://registry.npmmirror.com/wkx/-/wkx-0.5.0.tgz", - "integrity": "sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg==", - "requires": { - "@types/node": "*" - } - }, - "workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmmirror.com/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==" - }, - "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==", - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "ws": { - "version": "7.4.6", - "resolved": "https://registry.npmmirror.com/ws/-/ws-7.4.6.tgz", - "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==" - }, - "xmlhttprequest-ssl": { - "version": "1.6.3", - "resolved": "https://registry.npmmirror.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.6.3.tgz", - "integrity": "sha512-3XfeQE/wNkvrIktn2Kf0869fC0BN6UpydVasGIeSm2B1Llihf7/0UfZM+eCkOw3P7bP4+qPgqhm7ZoxuJtFU0Q==" - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmmirror.com/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "requires": { - "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" - } - }, - "yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==" - }, - "yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "requires": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - } - }, - "yeast": { - "version": "0.1.2", - "resolved": "https://registry.npmmirror.com/yeast/-/yeast-0.1.2.tgz", - "integrity": "sha512-8HFIh676uyGYP6wP13R/j6OJ/1HwJ46snpvzE7aHAN3Ryqh2yX6Xox2B4CUmTwwOIzlG3Bs7ocsP5dZH/R1Qbg==" - }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" - } - } + "name": "tl-rtc-file", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@types/debug": { + "version": "4.1.8", + "resolved": "https://registry.npmmirror.com/@types/debug/-/debug-4.1.8.tgz", + "integrity": "sha512-/vPO1EPOs306Cvhwv7KfVfYvOJqA/S/AXjaHQiJboCZzcNDb+TIJFN9/2C9DZ//ijSKWioNyUxD792QmDJ+HKQ==", + "requires": { + "@types/ms": "*" + } + }, + "@types/ms": { + "version": "0.7.31", + "resolved": "https://registry.npmmirror.com/@types/ms/-/ms-0.7.31.tgz", + "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==" + }, + "@types/node": { + "version": "20.3.3", + "resolved": "https://registry.npmmirror.com/@types/node/-/node-20.3.3.tgz", + "integrity": "sha512-wheIYdr4NYML61AjC8MKj/2jrR/kDQri/CIpVoZwldwhnIrD/j9jIU5bJ8yBKuB2VhpFV7Ab6G2XkBjv9r9Zzw==" + }, + "@types/validator": { + "version": "13.7.17", + "resolved": "https://registry.npmmirror.com/@types/validator/-/validator-13.7.17.tgz", + "integrity": "sha512-aqayTNmeWrZcvnG2MG9eGYI6b7S5fl+yKgPs6bAjOTwPS316R5SxBGKvtSExfyoJU7pIeHJfsHI0Ji41RVMkvQ==" + }, + "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==", + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + } + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmmirror.com/after/-/after-0.8.2.tgz", + "integrity": "sha512-QbJ0NTQ/I9DI3uSJA4cbexiwQeRAfjPScqIbSjUDd9TOrcg6pTkdgziesOqxBMBzit8vFCTwrP27t13vFOORRA==" + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmmirror.com/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==" + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + }, + "are-we-there-yet": { + "version": "1.1.7", + "resolved": "https://registry.npmmirror.com/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", + "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmmirror.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==" + }, + "asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmmirror.com/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmmirror.com/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==" + }, + "aws4": { + "version": "1.12.0", + "resolved": "https://registry.npmmirror.com/aws4/-/aws4-1.12.0.tgz", + "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==" + }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA==" + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "base64-arraybuffer": { + "version": "0.1.4", + "resolved": "https://registry.npmmirror.com/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz", + "integrity": "sha512-a1eIFi4R9ySrbiMuyTGx5e92uRH5tQY6kArNcFaKBUleIoLjdjBg7Zxm3Mqm3Kmkf27HLR/1fnxX9q8GQ7Iavg==" + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==" + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" + }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "blob": { + "version": "0.0.5", + "resolved": "https://registry.npmmirror.com/blob/-/blob-0.0.5.tgz", + "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==" + }, + "body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmmirror.com/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmmirror.com/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==" + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmmirror.com/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmmirror.com/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==" + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmmirror.com/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "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==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.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" + } + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmmirror.com/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmmirror.com/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==" + }, + "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==", + "requires": { + "color-name": "~1.1.4" + } + }, + "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==" + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha512-WZveuKPeKAG9qY+FkYDeADzdHyTYdIboXS59ixDeRJL5ZhxpqUnxSOwop4FQjMsiYm3/Or8cegVbpAHNA7pHxw==" + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmmirror.com/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha512-w+LhYREhatpVqTESyGFg3NlP6Iu0kEKUHETY9GoZP/pQyW4mHFZuFWRUCIqVPZ36ueVLtoOEZaAqbCF2RDndaA==" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" + }, + "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==", + "requires": { + "safe-buffer": "5.2.1" + } + }, + "content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" + }, + "cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmmirror.com/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" + }, + "cross-env": { + "version": "5.2.1", + "resolved": "https://registry.npmmirror.com/cross-env/-/cross-env-5.2.1.tgz", + "integrity": "sha512-1yHhtcfAd1r4nwQgknowuUNfIT9E8dOMMspC36g45dN+iD1blloi7xp8X/xAIDnjHWyt1uQ8PHk2fkNaym7soQ==", + "requires": { + "cross-spawn": "^6.0.5" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmmirror.com/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmmirror.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==" + }, + "decompress-response": { + "version": "4.2.1", + "resolved": "https://registry.npmmirror.com/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "requires": { + "mimic-response": "^2.0.0" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmmirror.com/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" + }, + "denque": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==" + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" + }, + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==" + }, + "diff": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==" + }, + "dottie": { + "version": "2.0.6", + "resolved": "https://registry.npmmirror.com/dottie/-/dottie-2.0.6.tgz", + "integrity": "sha512-iGCHkfUc5kFekGiqhe8B/mdaurD+lakO9txNnTvKtA6PISrw86LgqHvRzWYPyoE2Ph5aMIrCw9/uko6XHTKCwA==" + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmmirror.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "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==" + }, + "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==" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + }, + "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==", + "requires": { + "once": "^1.4.0" + } + }, + "engine.io": { + "version": "3.6.1", + "resolved": "https://registry.npmmirror.com/engine.io/-/engine.io-3.6.1.tgz", + "integrity": "sha512-dfs8EVg/i7QjFsXxn7cCRQ+Wai1G1TlEvHhdYEi80fxn5R1vZ2K661O6v/rezj1FP234SZ14r9CmJke99iYDGg==", + "requires": { + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "debug": "~4.1.0", + "engine.io-parser": "~2.2.0", + "ws": "~7.4.2" + }, + "dependencies": { + "cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmmirror.com/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==" + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmmirror.com/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "engine.io-client": { + "version": "3.5.3", + "resolved": "https://registry.npmmirror.com/engine.io-client/-/engine.io-client-3.5.3.tgz", + "integrity": "sha512-qsgyc/CEhJ6cgMUwxRRtOndGVhIu5hpL5tR4umSpmX/MvkFoIxUTM7oFMDQumHNzlNLwSVy6qhstFPoWTf7dOw==", + "requires": { + "component-emitter": "~1.3.0", + "component-inherit": "0.0.3", + "debug": "~3.1.0", + "engine.io-parser": "~2.2.0", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.6", + "parseuri": "0.0.6", + "ws": "~7.4.2", + "xmlhttprequest-ssl": "~1.6.2", + "yeast": "0.1.2" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "engine.io-parser": { + "version": "2.2.1", + "resolved": "https://registry.npmmirror.com/engine.io-parser/-/engine.io-parser-2.2.1.tgz", + "integrity": "sha512-x+dN/fBH8Ro8TFwJ+rkB2AmuVw9Yu2mockR/p3W8f8YtExwFgDvBDi0GWyb4ZLkpahtDGZgtr3zLovanJghPqg==", + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.4", + "blob": "0.0.5", + "has-binary2": "~1.0.2" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, + "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==" + }, + "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==" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmmirror.com/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" + }, + "expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" + }, + "express": { + "version": "4.18.2", + "resolved": "https://registry.npmmirror.com/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==" + }, + "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==" + }, + "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==" + }, + "fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "requires": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmmirror.com/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + } + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmmirror.com/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==" + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmmirror.com/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==" + }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmmirror.com/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "requires": { + "fetch-blob": "^3.1.2" + } + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmmirror.com/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmmirror.com/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" + }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmmirror.com/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg==", + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==" + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmmirror.com/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "requires": { + "is-property": "^1.0.2" + } + }, + "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==" + }, + "get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + } + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmmirror.com/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmmirror.com/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "dependencies": { + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "requires": { + "is-glob": "^4.0.1" + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==" + }, + "har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmmirror.com/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-binary2": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", + "requires": { + "isarray": "2.0.1" + }, + "dependencies": { + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha512-c2cu3UxbI+b6kR3fy0nRnAhodsvR9dx7U5+znCOzdj6IfP3upFURTr0Xl5BlQZNKZjEtxrmVyfSdeE3O57smoQ==" + } + } + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha512-g5VNKdkFuUuVCP9gYfDJHjK2nqdQJ7aDLTnycnc2+RvsOQbuLdF5pm7vuE5J76SEBIQjs4kQY/BWq74JUmjbXA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==" + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" + }, + "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==", + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmmirror.com/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha512-i0G7hLJ1z0DE8dsqJa2rycj9dBmNKgXBvotXtZYXakU9oivfB9Uj2ZBC27qqef2U58/ZLwalxa1X/RDCdkHtVg==" + }, + "inflection": { + "version": "1.13.4", + "resolved": "https://registry.npmmirror.com/inflection/-/inflection-1.13.4.tgz", + "integrity": "sha512-6I/HUDeYFfuNCVS3td055BaXBwKYuzw7K3ExVMStBowKo9oOAMJIXIHvdyR3iboTCp1b+1i5DSkIZTcwIktuDw==" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmmirror.com/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "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==" + }, + "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==", + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" + }, + "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==" + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==" + }, + "is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==" + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" + }, + "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==" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmmirror.com/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "requires": { + "argparse": "^2.0.1" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmmirror.com/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==" + }, + "json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmmirror.com/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" + }, + "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==" + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" + }, + "jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmmirror.com/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "requires": { + "p-locate": "^5.0.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "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==", + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + } + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "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==", + "requires": { + "yallist": "^4.0.0" + } + }, + "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==" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmmirror.com/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "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==", + "requires": { + "mime-db": "1.52.0" + } + }, + "mimic-response": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==" + }, + "minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "requires": { + "brace-expansion": "^2.0.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "requires": { + "balanced-match": "^1.0.0" + } + } + } + }, + "minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmmirror.com/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" + }, + "mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmmirror.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" + }, + "mocha": { + "version": "10.2.0", + "resolved": "https://registry.npmmirror.com/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "requires": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmmirror.com/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "moment": { + "version": "2.29.4", + "resolved": "https://registry.npmmirror.com/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" + }, + "moment-timezone": { + "version": "0.5.43", + "resolved": "https://registry.npmmirror.com/moment-timezone/-/moment-timezone-0.5.43.tgz", + "integrity": "sha512-72j3aNyuIsDxdF1i7CEgV2FfxM1r6aaqJyLB2vwb33mXYyoyLly+F1zbWqhA3/bVIoJ4szlUoMbUnVdid32NUQ==", + "requires": { + "moment": "^2.29.4" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "mysql2": { + "version": "2.3.3", + "resolved": "https://registry.npmmirror.com/mysql2/-/mysql2-2.3.3.tgz", + "integrity": "sha512-wxJUev6LgMSgACDkb/InIFxDprRa6T95+VEoR+xPvtngtccNH2dGjEB/fVZ8yg1gWv1510c9CvXuJHi5zUm0ZA==", + "requires": { + "denque": "^2.0.1", + "generate-function": "^2.3.1", + "iconv-lite": "^0.6.3", + "long": "^4.0.0", + "lru-cache": "^6.0.0", + "named-placeholders": "^1.1.2", + "seq-queue": "^0.0.5", + "sqlstring": "^2.3.2" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, + "named-placeholders": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/named-placeholders/-/named-placeholders-1.1.3.tgz", + "integrity": "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==", + "requires": { + "lru-cache": "^7.14.1" + }, + "dependencies": { + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==" + } + } + }, + "nan": { + "version": "2.17.0", + "resolved": "https://registry.npmmirror.com/nan/-/nan-2.17.0.tgz", + "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==" + }, + "nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==" + }, + "napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmmirror.com/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" + }, + "node-abi": { + "version": "2.30.1", + "resolved": "https://registry.npmmirror.com/node-abi/-/node-abi-2.30.1.tgz", + "integrity": "sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w==", + "requires": { + "semver": "^5.4.1" + } + }, + "node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==" + }, + "node-fetch": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/node-fetch/-/node-fetch-3.1.0.tgz", + "integrity": "sha512-QU0WbIfMUjd5+MUzQOYhenAazakV7Irh1SGkWCsRzBwvm4fAhzEUaHMJ6QLP7gWT6WO9/oH2zhKMMGMuIrDyKw==", + "requires": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.2", + "formdata-polyfill": "^4.0.10" + } + }, + "noop-logger": { + "version": "0.1.1", + "resolved": "https://registry.npmmirror.com/noop-logger/-/noop-logger-0.1.1.tgz", + "integrity": "sha512-6kM8CLXvuW5crTxsAtva2YLrRrDaiTIkIePWs9moLHqbFWT94WpNFjwS/5dfLfECg5i/lkmw3aoqVidxt23TEQ==" + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmmirror.com/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==" + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmmirror.com/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + }, + "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==" + }, + "object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==" + }, + "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==", + "requires": { + "ee-first": "1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "requires": { + "wrappy": "1" + } + }, + "openai": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/openai/-/openai-1.1.3.tgz", + "integrity": "sha512-G+VounGq9lSo15Swc5wyT2tgtI+9bCw9N51Vryy/UNwSpYCjtF3lFDQOjak6ELqRmqHBpMltzVV1R0svrk3QDQ==", + "requires": { + "form-data": "4.0.0", + "node-fetch": "3.1.0", + "openai": "^1.1.2" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "requires": { + "p-limit": "^3.0.2" + } + }, + "parseqs": { + "version": "0.0.6", + "resolved": "https://registry.npmmirror.com/parseqs/-/parseqs-0.0.6.tgz", + "integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w==" + }, + "parseuri": { + "version": "0.0.6", + "resolved": "https://registry.npmmirror.com/parseuri/-/parseuri-0.0.6.tgz", + "integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow==" + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmmirror.com/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "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==" + }, + "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==" + }, + "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==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmmirror.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" + }, + "pg-connection-string": { + "version": "2.6.1", + "resolved": "https://registry.npmmirror.com/pg-connection-string/-/pg-connection-string-2.6.1.tgz", + "integrity": "sha512-w6ZzNu6oMmIzEAYVw+RLK0+nqHPt8K3ZnknKi+g48Ak2pr3dtljJW3o+D/n2zzCG07Zoe9VOX3aiKpj+BN0pjg==" + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" + }, + "pngjs": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/pngjs/-/pngjs-7.0.0.tgz", + "integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==" + }, + "prebuild-install": { + "version": "5.3.6", + "resolved": "https://registry.npmmirror.com/prebuild-install/-/prebuild-install-5.3.6.tgz", + "integrity": "sha512-s8Aai8++QQGi4sSbs/M1Qku62PFK49Jm1CbgXklGz4nmHveDq0wzJkg7Na5QbnO1uNH8K7iqx2EQ/mV0MZEmOg==", + "requires": { + "detect-libc": "^1.0.3", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^2.7.0", + "noop-logger": "^0.1.1", + "npmlog": "^4.0.1", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^3.0.3", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0", + "which-pm-runs": "^1.0.0" + } + }, + "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==" + }, + "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==", + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + } + }, + "psl": { + "version": "1.9.0", + "resolved": "https://registry.npmmirror.com/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==" + }, + "qs": { + "version": "6.11.0", + "resolved": "https://registry.npmmirror.com/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "requires": { + "side-channel": "^1.0.4" + } + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "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==" + }, + "raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmmirror.com/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmmirror.com/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==" + } + } + }, + "readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "requires": { + "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" + }, + "dependencies": { + "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==" + } + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmmirror.com/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "requires": { + "picomatch": "^2.2.1" + } + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmmirror.com/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmmirror.com/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "qs": { + "version": "6.5.3", + "resolved": "https://registry.npmmirror.com/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==" + } + } + }, + "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==" + }, + "retry-as-promised": { + "version": "7.0.4", + "resolved": "https://registry.npmmirror.com/retry-as-promised/-/retry-as-promised-7.0.4.tgz", + "integrity": "sha512-XgmCoxKWkDofwH8WddD0w85ZfqYz+ZHlr5yo+3YUCfycWawU56T5ckWXsScsj5B8tqUcIG67DxXByo3VUgiAdA==" + }, + "robotjs": { + "version": "0.6.0", + "resolved": "https://registry.npmmirror.com/robotjs/-/robotjs-0.6.0.tgz", + "integrity": "sha512-6pRWI3d+CBZqCXT/rsJfabbZoELua+jTeXilG27F8Jvix/J2BYZ0O7Tly2WCmXyqw5xYdCvOwvCeLRHEtXkt4w==", + "requires": { + "nan": "^2.14.0", + "node-abi": "^2.13.0", + "prebuild-install": "^5.3.3" + } + }, + "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==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmmirror.com/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "send": { + "version": "0.18.0", + "resolved": "https://registry.npmmirror.com/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "requires": { + "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" + }, + "dependencies": { + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "seq-queue": { + "version": "0.0.5", + "resolved": "https://registry.npmmirror.com/seq-queue/-/seq-queue-0.0.5.tgz", + "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==" + }, + "sequelize": { + "version": "6.32.1", + "resolved": "https://registry.npmmirror.com/sequelize/-/sequelize-6.32.1.tgz", + "integrity": "sha512-3Iv0jruv57Y0YvcxQW7BE56O7DC1BojcfIrqh6my+IQwde+9u/YnuYHzK+8kmZLhLvaziRT1eWu38nh9yVwn/g==", + "requires": { + "@types/debug": "^4.1.8", + "@types/validator": "^13.7.17", + "debug": "^4.3.4", + "dottie": "^2.0.4", + "inflection": "^1.13.4", + "lodash": "^4.17.21", + "moment": "^2.29.4", + "moment-timezone": "^0.5.43", + "pg-connection-string": "^2.6.0", + "retry-as-promised": "^7.0.4", + "semver": "^7.5.1", + "sequelize-pool": "^7.1.0", + "toposort-class": "^1.0.1", + "uuid": "^8.3.2", + "validator": "^13.9.0", + "wkx": "^0.5.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmmirror.com/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "semver": { + "version": "7.5.3", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "sequelize-pool": { + "version": "7.1.0", + "resolved": "https://registry.npmmirror.com/sequelize-pool/-/sequelize-pool-7.1.0.tgz", + "integrity": "sha512-G9c0qlIWQSK29pR/5U2JF5dDQeqqHRragoyahj/Nx4KOOQ3CPPfzxnfqFPCSB7x5UgjOgnZ61nSxz+fjDpRlJg==" + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmmirror.com/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + } + } + }, + "sequelize-pool": { + "version": "6.1.0", + "resolved": "https://registry.npmmirror.com/sequelize-pool/-/sequelize-pool-6.1.0.tgz", + "integrity": "sha512-4YwEw3ZgK/tY/so+GfnSgXkdwIJJ1I32uZJztIEgZeAO6HMgj64OzySbWLgxj+tXhZCJnzRfkY9gINw8Ft8ZMg==" + }, + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "requires": { + "randombytes": "^2.1.0" + } + }, + "serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmmirror.com/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "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==", + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==" + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "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==" + }, + "simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==" + }, + "simple-get": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/simple-get/-/simple-get-3.1.1.tgz", + "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", + "requires": { + "decompress-response": "^4.2.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "socket.io": { + "version": "2.5.0", + "resolved": "https://registry.npmmirror.com/socket.io/-/socket.io-2.5.0.tgz", + "integrity": "sha512-gGunfS0od3VpwDBpGwVkzSZx6Aqo9uOcf1afJj2cKnKFAoyl16fvhpsUhmUFd4Ldbvl5JvRQed6eQw6oQp6n8w==", + "requires": { + "debug": "~4.1.0", + "engine.io": "~3.6.0", + "has-binary2": "~1.0.2", + "socket.io-adapter": "~1.1.0", + "socket.io-client": "2.5.0", + "socket.io-parser": "~3.4.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmmirror.com/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "socket.io-adapter": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz", + "integrity": "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==" + }, + "socket.io-client": { + "version": "2.5.0", + "resolved": "https://registry.npmmirror.com/socket.io-client/-/socket.io-client-2.5.0.tgz", + "integrity": "sha512-lOO9clmdgssDykiOmVQQitwBAF3I6mYcQAo7hQ7AM6Ny5X7fp8hIJ3HcQs3Rjz4SoggoxA1OgrQyY8EgTbcPYw==", + "requires": { + "backo2": "1.0.2", + "component-bind": "1.0.0", + "component-emitter": "~1.3.0", + "debug": "~3.1.0", + "engine.io-client": "~3.5.0", + "has-binary2": "~1.0.2", + "indexof": "0.0.1", + "parseqs": "0.0.6", + "parseuri": "0.0.6", + "socket.io-parser": "~3.3.0", + "to-array": "0.1.4" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha512-c2cu3UxbI+b6kR3fy0nRnAhodsvR9dx7U5+znCOzdj6IfP3upFURTr0Xl5BlQZNKZjEtxrmVyfSdeE3O57smoQ==" + }, + "socket.io-parser": { + "version": "3.3.3", + "resolved": "https://registry.npmmirror.com/socket.io-parser/-/socket.io-parser-3.3.3.tgz", + "integrity": "sha512-qOg87q1PMWWTeO01768Yh9ogn7chB9zkKtQnya41Y355S0UmpXgpcrFwAgjYJxu9BdKug5r5e9YtVSeWhKBUZg==", + "requires": { + "component-emitter": "~1.3.0", + "debug": "~3.1.0", + "isarray": "2.0.1" + } + } + } + }, + "socket.io-parser": { + "version": "3.4.3", + "resolved": "https://registry.npmmirror.com/socket.io-parser/-/socket.io-parser-3.4.3.tgz", + "integrity": "sha512-1rE4dZN3kCI/E5wixd393hmbqa78vVpkKmnEJhLeWoS/C5hbFYAbcSfnWoaVH43u9ToUVtzKjguxEZq+1XZfCQ==", + "requires": { + "component-emitter": "1.2.1", + "debug": "~4.1.0", + "isarray": "2.0.1" + }, + "dependencies": { + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha512-jPatnhd33viNplKjqXKRkGU345p263OIWzDL2wH3LGIGp5Kojo+uXizHmOADRvhGFFTnJqX3jBAKP6vvmSDKcA==" + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmmirror.com/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha512-c2cu3UxbI+b6kR3fy0nRnAhodsvR9dx7U5+znCOzdj6IfP3upFURTr0Xl5BlQZNKZjEtxrmVyfSdeE3O57smoQ==" + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "sqlstring": { + "version": "2.3.3", + "resolved": "https://registry.npmmirror.com/sqlstring/-/sqlstring-2.3.3.tgz", + "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==" + }, + "sshpk": { + "version": "1.17.0", + "resolved": "https://registry.npmmirror.com/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" + }, + "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==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "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==", + "requires": { + "safe-buffer": "~5.1.0" + }, + "dependencies": { + "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==" + } + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "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==" + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "requires": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "requires": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmmirror.com/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha512-LhVdShQD/4Mk4zXNroIQZJC+Ap3zgLcDuwEdcmLv9CCO73NWockQDwyUnW/m8VX/EElfL6FcYx7EeutN4HJA6A==" + }, + "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==", + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" + }, + "toposort-class": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/toposort-class/-/toposort-class-1.0.1.tgz", + "integrity": "sha512-OsLcGGbYF3rMjPUf8oKktyvCiUxSbqMMS39m33MAjLTC1DVIH6x3WSt63/M77ihI09+Sdfk1AXvfhCEeUmC7mg==" + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmmirror.com/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmmirror.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmmirror.com/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==" + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmmirror.com/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmmirror.com/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "requires": { + "punycode": "^2.1.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "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==" + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmmirror.com/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + }, + "validator": { + "version": "13.9.0", + "resolved": "https://registry.npmmirror.com/validator/-/validator-13.9.0.tgz", + "integrity": "sha512-B+dGG8U3fdtM0/aNK4/X8CXq/EcxU2WPrPEkJGslb47qyHsxmbggTWK0yEA4qnYVNF+nxNlN88o14hIcPmSIEA==" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmmirror.com/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "web-streams-polyfill": { + "version": "3.2.1", + "resolved": "https://registry.npmmirror.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", + "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==" + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmmirror.com/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "^2.0.0" + } + }, + "which-pm-runs": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/which-pm-runs/-/which-pm-runs-1.1.0.tgz", + "integrity": "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==" + }, + "wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmmirror.com/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "requires": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "wkx": { + "version": "0.5.0", + "resolved": "https://registry.npmmirror.com/wkx/-/wkx-0.5.0.tgz", + "integrity": "sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg==", + "requires": { + "@types/node": "*" + } + }, + "workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmmirror.com/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==" + }, + "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==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "ws": { + "version": "7.4.6", + "resolved": "https://registry.npmmirror.com/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==" + }, + "xmlhttprequest-ssl": { + "version": "1.6.3", + "resolved": "https://registry.npmmirror.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.6.3.tgz", + "integrity": "sha512-3XfeQE/wNkvrIktn2Kf0869fC0BN6UpydVasGIeSm2B1Llihf7/0UfZM+eCkOw3P7bP4+qPgqhm7ZoxuJtFU0Q==" + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmmirror.com/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "requires": { + "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" + } + }, + "yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==" + }, + "yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "requires": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + } + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmmirror.com/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha512-8HFIh676uyGYP6wP13R/j6OJ/1HwJ46snpvzE7aHAN3Ryqh2yX6Xox2B4CUmTwwOIzlG3Bs7ocsP5dZH/R1Qbg==" + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" + } + } } diff --git a/svr/package.json b/svr/package.json index f742e75..52427aa 100644 --- a/svr/package.json +++ b/svr/package.json @@ -1,38 +1,38 @@ { - "name": "tl-rtc-file", - "version": "1.0.0", - "description": "webrtc, p2p,file", - "main": "main.js", - "scripts": { - "lapi": "cross-env ENV_MODE=local node localapi", - "lsocket": "cross-env ENV_MODE=local node localsocket", - "lcsocket": "cross-env ENV_MODE=local node localcontrolsocket", - "sapi": "cross-env ENV_MODE=server node serverapi", - "ssocket": "cross-env ENV_MODE=server node serversocket", - "scsockert": "cross-env ENV_MODE=server node servercontrolsocket", - "test": "cross-env mocha ./test/test.js" - }, - "repository": { - "type": "git", - "url": "" - }, - "keywords": [ - "none" - ], - "author": "iamtsm", - "license": "MIT", - "dependencies": { - "cross-env": "^5.2.0", - "express": "^4.17.1", - "mocha": "^10.2.0", - "mysql2": "^2.1.0", - "openai": "^1.0.0", - "request": "^2.88.2", - "sequelize": "^6.1.0", - "sequelize-pool": "^6.0.0", - "socket.io": "^2.3.0", - "pngjs": "^7.0.0", - "robotjs": "^0.6.0" - }, - "devDependencies": {} + "name": "tl-rtc-file", + "version": "1.0.0", + "description": "webrtc, p2p,file", + "main": "main.js", + "scripts": { + "lapi": "cross-env ENV_MODE=local node localapi", + "lsocket": "cross-env ENV_MODE=local node localsocket", + "lcsocket": "cross-env ENV_MODE=local node localcontrolsocket", + "sapi": "cross-env ENV_MODE=server node serverapi", + "ssocket": "cross-env ENV_MODE=server node serversocket", + "scsocket": "cross-env ENV_MODE=server node servercontrolsocket", + "test": "cross-env mocha ./test/test.js" + }, + "repository": { + "type": "git", + "url": "" + }, + "keywords": [ + "none" + ], + "author": "iamtsm", + "license": "MIT", + "dependencies": { + "cross-env": "^5.2.0", + "express": "^4.17.1", + "mocha": "^10.2.0", + "mysql2": "^2.1.0", + "openai": "^1.0.0", + "request": "^2.88.2", + "sequelize": "^6.1.0", + "sequelize-pool": "^6.0.0", + "socket.io": "^2.3.0", + "pngjs": "^7.0.0", + "robotjs": "^0.6.0" + }, + "devDependencies": {} } diff --git a/svr/res/css/index.css b/svr/res/css/index.css index 998c36e..b4a07bb 100644 --- a/svr/res/css/index.css +++ b/svr/res/css/index.css @@ -19,6 +19,7 @@ body { margin: 0; margin-left: 5%; max-width: 90%; + padding-bottom: 30px; align-items: center; justify-content: center; transition: background-color var(--duration); @@ -33,6 +34,10 @@ body { border-radius: 8px !important; } +.language-mode{ + border-radius: 8px; +} + .layui-card { box-shadow: none; } @@ -47,7 +52,7 @@ body { .tl-rtc-file-header-tool { position: absolute; top: 10px; - left: 10px; + right: 10px; cursor: pointer; } @@ -220,12 +225,12 @@ body { background-color: rgb(248 253 255 / 45%); border-radius: 10px; display: inline-flex; - /* box-shadow: rgba(0, 0, 0, 0.4) 0px 2px 3px; */ transition: all 0.3s; } .tl-rtc-file-tool:hover { - box-shadow: rgba(0, 0, 0, 0.4) 0px 7px 14px; + box-shadow: rgba(9,30,66,0.25) 0px 8px 9px; + /* box-shadow: 0 20px 32px -8px rgba(9,30,66,0.25), 0 0 1px rgba(9,30,66,0.31); */ } .tl-rtc-file-tool i { @@ -244,6 +249,7 @@ body { .tl-rtc-file-tool b { margin: 10px 10px 10px 0; letter-spacing: 2px; + left: 15px; } .tl-rtc-file-tool-disabled, @@ -385,6 +391,7 @@ body { } .tl-rtc-file-create-room-input { + text-align: right; width: 0%; position: fixed; padding: 0px 15px 0px 15px; @@ -793,8 +800,8 @@ body { @media screen and (min-width: 765px) and (max-width: 1280px) { } -/** 1280px以上 */ -@media screen and (min-width: 1280px) { +/** 765px以上 */ +@media screen and (min-width: 765px) { } @@ -846,15 +853,16 @@ body { .tl-rtc-file-notification-container{ position: fixed; top: 10px; - right: 10px; z-index: 9999; display: flex; flex-direction: column; + transition: right .45s; } .tl-rtc-file-notification { background-color: #fff; - box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1); + box-shadow: 0 20px 32px -8px rgba(9,30,66,0.25), 0 0 1px rgba(9,30,66,0.31); + transition: opacity .45s; border-radius: 10px; padding: 16px; margin: 10px; @@ -864,7 +872,6 @@ body { flex-direction: initial; align-items: center; opacity: 0; - transition: all 0.5s ease-in-out; } .tl-rtc-file-notification-content{ @@ -922,9 +929,9 @@ body { .tl-rtc-file-tool-mobile-title{ position: absolute; + width: 100%; word-break: keep-all; margin: 0 !important; - margin-left: 6px !important; bottom: 0; -webkit-transform-origin-x: 0; transform: scale(0.6); @@ -962,4 +969,168 @@ body { .isMediaing{ width: 50%; margin-left: 50%; -} \ No newline at end of file +} + +#tl-rtc-file-mouse-draw{ + margin: 0px 5px 0px 5px; + border: 1px dashed; + height: 100%; +} + +#tl-rtc-file-mouse-draw svg{ + cursor: pointer; + width: 22px; + height: 22px; + margin-top: -2px; + margin-left: 5px; +} + +#tl-rtc-file-mouse-draw-canvas-body{ + margin-left:4px; + border-top: 1px dashed;} + +.tl-rtc-file-mouse-draw-body{ + margin:5px; + user-select: none; +} + + +.tl-rtc-file-mouse-draw-body-item{ + padding: 10px; + display: inline-flex; + font-weight: 300; +} + +.tl-rtc-file-mouse-draw-body-item i{ + margin-left: 5px; + font-size: 20px; + margin-top: -2px; + font-weight: 900; + color: black; + cursor: pointer; +} + +#tl-rtc-file-mouse-draw-line-size-txt, #tl-rtc-file-mouse-draw-div-size-txt{ + position: relative; + top: 3px; + margin-left: 5px; + font-size: 20px; + margin-top: -2px; + font-weight: 900; + color: black; + cursor: pointer; +} + +.tl-rtc-file-mouse-draw-body-item i:hover{ + color: #5280d7; +} + +#tl-rtc-file-mouse-draw-stroke-color{ + margin-left: 3px; + margin-top: -8px; +} + +#tl-rtc-file-mouse-draw-stroke-color .layui-colorpicker{ + width: 50px; + height: 35px; +} + +.tl-rtc-file-mouse-draw-body-item:disabled{ + color: #4c53d91f; + cursor: no-drop; +} + +.tl-rtc-file-mouse-draw-canvas-line{ + cursor: url("/image/drawline.png") 5 24, auto; +} + +.tl-rtc-file-mouse-draw-canvas-delete{ + cursor: url("/image/drawdelete.png") 15 20, auto; +} + +.tl-rtc-file-mouse-draw-canvas-circle{ + cursor: url("/image/drawcircle.png") 5 24, auto; +} + +.tl-rtc-file-mouse-draw-canvas-circle-fill{ + cursor: url("/image/drawcirclefill.png") 5 24, auto; +} + +.tl-rtc-file-mouse-draw-canvas-rectangle{ + cursor: url("/image/drawrectangle.png") 5 24, auto; +} + +.tl-rtc-file-mouse-draw-canvas-rectangle-fill{ + cursor: url("/image/drawrectanglefill.png") 5 24, auto; +} + +.tl-rtc-file-mouse-draw-canvas-hexagon{ + cursor: url("/image/drawhexagon.png") 5 24, auto; +} + +.tl-rtc-file-mouse-draw-canvas-hexagon-fill{ + cursor: url("/image/drawhexagonfill.png") 5 24, auto; +} + +.tl-rtc-file-mouse-draw-canvas-triangle{ + cursor: url("/image/drawtriangle.png") 5 24, auto; +} + +.tl-rtc-file-mouse-draw-canvas-triangle-fill{ + cursor: url("/image/drawtrianglefill.png") 5 24, auto; +} + +.tl-rtc-file-mouse-draw-canvas-rhomboid{ + cursor: url("/image/drawrhomboid.png") 5 24, auto; +} + +.tl-rtc-file-mouse-draw-canvas-rhomboid-fill{ + cursor: url("/image/drawrhomboidfill.png") 5 24, auto; +} + +.tl-rtc-file-mouse-draw-canvas-star{ + cursor: url("/image/drawstar.png") 5 24, auto; +} + +.tl-rtc-file-mouse-draw-canvas-star-fill{ + cursor: url("/image/drawstarfill.png") 5 24, auto; +} + +.tl-rtc-file-mouse-draw-canvas-text{ + cursor: url("/image/drawtext.png") 5 24, auto; +} + +.layui-layer-title{ + user-select: none; +} + + +.chating_input_body{ + bottom: 0px; + position: absolute; + width: 100%; + padding: 20px; +} + +.chating_input_body textarea{ + border-radius: 15px; +} + +.chating_send_body{ + float: right; + margin-top: 10px; + user-select: none; +} + +.chating_send_body_span{ + font-size: 12px; + color: #0000007d; + position: absolute; + bottom: 26px; + right: 75px; +} + +.chating_send_body_button{ + border-radius: 5px; +} + diff --git a/svr/res/home.html b/svr/res/home.html index 6668241..d535e30 100644 --- a/svr/res/home.html +++ b/svr/res/home.html @@ -150,6 +150,10 @@
基于webrtc的媒体流传输工具
+
+ GitHub Repo stars + GitHub forks +
文件传输 文件暂存 diff --git a/svr/res/home_en.html b/svr/res/home_en.html index 3f1eb6a..48ee7fb 100644 --- a/svr/res/home_en.html +++ b/svr/res/home_en.html @@ -149,6 +149,10 @@
webrtc based media streaming tool
+
+ GitHub Repo stars + GitHub forks +
file transfer audio and video call diff --git a/svr/res/image/drawcircle.png b/svr/res/image/drawcircle.png new file mode 100644 index 0000000000000000000000000000000000000000..4a0b7ccfae0abe450bb378a2d103224c647c2f92 GIT binary patch literal 457 zcmV;)0XF`LP)Px$gGod|R9HvNSKDpFKn%O=qaD&r)?~7_J7}K-3M_*@>j@Zf{SzCOPZX&;F_&@j zbvZfzXaOLiuQA3qfR<;uewW`rxo2j5PU|ZHfW(?GU3iS~VCH)k7y@t-Z>n7qC@^G4 zUZo&h088>8s6Z0Sf+4-jce7MC?>iHKk=$LtqnL<&WdQ*wMTgTL$?$0a%CgCTHembEsrCr=naYd|oDSd;0E&f+%x#$uDozCyZo(|vzHI@M|?)yjD00000NkvXXu0mjf*Q>!d literal 0 HcmV?d00001 diff --git a/svr/res/image/drawcirclefill.png b/svr/res/image/drawcirclefill.png new file mode 100644 index 0000000000000000000000000000000000000000..f3cdf0615a820077f30239e6837ed0570be30761 GIT binary patch literal 366 zcmV-!0g?WRP)Px$C`m*?R9Hvtms=9TAPhy*{bUd7%G8xv_mKVQ!~rHic(pu!~;K>S~LdW ze<0!%7ia+lFu{c=6{RBCh^bI>VJ?*R%!SEhTocRBv?j-K zR^A@VWg{O5E5*Y0`BiU5_GSaZUoT2_uqv~P!yT##ptQXm`F%OS7bA9xAqXOkxc~qF M07*qoM6N<$fPx$CrLy>R9HvtmQfA@Aq+&jCsR+Ro=iQNW)f;x17)U=?2jaVE#W;{7~JgOu^r5} zzrgAW+{_F=daMut@M&h(LVYO`vjTuS_+G$X0jd%+0yW%Aeks+UC9(o7cuFE85W!^$ zRe*s*0*4aqzzEx+2(WOk0wuu;sPLA=!_06~Aod-MKo(w0ARA6qTWEn70LMK>B|PghJ|Vm(@EaW2voM7B1bp}PeN`nW zcu$}i7$s7fcF^!h0N*^z>)wwlA;Cw7u(w!GLWV~Io&&5z3O>q#NCH(rwqs5jJ`%w9 zTEfo)!2ZV*-*>N@8WzlJh&6r3p6OFi^*L5ICCz6mAT6p){tJ8nmKsPQpTlt~00000 LNkvXXu0mjf4sMHc literal 0 HcmV?d00001 diff --git a/svr/res/image/drawhexagon.png b/svr/res/image/drawhexagon.png new file mode 100644 index 0000000000000000000000000000000000000000..6b58393103cc1d3f9c3379b2cc655a1e7e7296ec GIT binary patch literal 389 zcmV;00eb$4P)Px$KS@MER9HvtmfH=3FbqY_J|3b>)^@Tog!gIXDnV(8eI1BIKj4=nKE8fVbn-Wy zY@aTGkOIv7*b%BlL>6=p0xT5WqWoE+TVJ7)p3g1rs3pfCt6Q*#T39CP0sb06-Ja4WR{)6HiO2OZplJ zsjva4ybmXyr9_p;n^3d>hIyZ%ynOlr*jsjy>aapl1Hi0}7;BxeR5%5Ih}PUPLx5Un zj}l&4w~}yp7?{~i>=r=TJm54#N}#f~8qo@IG!&lq3jd$2IE~c9DipPEw)E&Y?#_ki zG(`Y#ni)-}T;ujHBq}6P7A;Fno`~X$k>~9WO7YVFd1U literal 0 HcmV?d00001 diff --git a/svr/res/image/drawhexagonfill.png b/svr/res/image/drawhexagonfill.png new file mode 100644 index 0000000000000000000000000000000000000000..960639bc6b5d8d754c034d6fb172322b667fe384 GIT binary patch literal 330 zcmV-Q0k!^#P)Px$1W80eR9HvtmhBA!Aq<9l`*a7r$<)a_cj!KvCSv$#DMBx3a{L9#)3;wNFnKML z--iR>KNLX3D*&9n%$Eld@xAJ5QUDR3mLX}Mh)nzD0Ytn5z_|wi0B)8FRRBcfhZ$gG ztwgkG1}uOP@57r_6;uEx?@fprfQR=V<+X$q0p4YI840{_R}4h~;4FQ@A*mn%xJsWX zQK*mr?CE_3l0f7D+&aBupQl687o-sE39%8;8WU+%(AE1Js;20QzgLFAi{1&Ss8C2B z&eb}hXD+A%$r?r;5UTgAf(0;l95dnIT&Q|)DlnRmE?=@pg?XRSh6dAp#Qc0~A^6c~rT_o{07*qoM6N<$f;bt2v;Y7A literal 0 HcmV?d00001 diff --git a/svr/res/image/drawline.png b/svr/res/image/drawline.png new file mode 100644 index 0000000000000000000000000000000000000000..f08d09051fdf6d838b281045bbc90ba520509013 GIT binary patch literal 359 zcmV-t0hs=YP)Px$AxT6*R9Hvtmfa1*APj`J0$Xx>AL3WmjETZ^FGO>GEzn;K}wtyQZ>F=6bAU&A-+%4d82fl~jy&Px#w@E}nR9Hvtm%$CgFbo5keY8W9$=XbobO-L!f`%DyW&n2pI(yU#U?;hk<}M%)-+D~_&~qswY5|YDy}p;iX9qE&oBESnbg2cr z^5aTUVw#tkiE#S8B-8AF3vkLIAP5A3AP@wCKoAH5LEzE^+_AQHrDpck6S`vspa9Xj zZdKrM=Y5@EqIGjRD)Fo}ff9JM{W+TTnD$H0;pzAd=jG`kfF+AW00000NkvXXu0mjf Dbc|<{ literal 0 HcmV?d00001 diff --git a/svr/res/image/drawrectanglefill.png b/svr/res/image/drawrectanglefill.png new file mode 100644 index 0000000000000000000000000000000000000000..bee8ff894bfafdd523b8e37ca64c050f683330ca GIT binary patch literal 249 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}n>}3|Ln7SY zPWR?(cHnV7TwBvVZSvH4YYN!!w`*lIwe=rS^NC0a^H4rIPh6}_{or!$Ytw_78S0MS zxP9`0hLZ5fMEm??h6b)#J0^ci^zjek)lJV&*yp`JkdX)Iux)#j`m>CGJfn&W)uQz@~--JPn} wE(yl<{XcT4WexY0nSWFVdQ&MBb@0Cy8#2><{9 literal 0 HcmV?d00001 diff --git a/svr/res/image/drawrhomboid.png b/svr/res/image/drawrhomboid.png new file mode 100644 index 0000000000000000000000000000000000000000..59d7338381c8d755d31d181cbd0ca7e12f760e3a GIT binary patch literal 287 zcmV+)0pR|LP)Px#*-1n}R9HvtmfH=3FbqY_J|3b>R&_EM!ux<+m54_gTPWB5A>URwIW{*LD0vOZ z-=_z_Wq_F%K&xgE8BG9Yei6}Ii+e#Z^F%}+5t%&zr8o;<5fKyA3wJi!+!(E2p)CM} zejVsh`|kmO>Td!>=(hmi`Yiys{=WcG`da`H{k1%){)U?U$ne>R)&(F^f3*esi^3bP zR$a^J!NBkIQ%oo!<49{LTOfz-4p;&|)R- lx;%N(?Xh{6`~gTeumVp_%ONa%qb&dc002ovPDHLkV1i-1b#DLw literal 0 HcmV?d00001 diff --git a/svr/res/image/drawrhomboidfill.png b/svr/res/image/drawrhomboidfill.png new file mode 100644 index 0000000000000000000000000000000000000000..ab3995b5fd749c13f19586df168fbd0487aab03f GIT binary patch literal 255 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}J3U<-Ln7SY zPJ7FHSb@hy|93@4+NM>LO`Y%9t(*|GQk2bos{OwQj1PXwCYXs_58GoecEBh>N?@XN z!|un4wG(XYUdJ+4Fl7kDZ4GCVQThJfZyDRYU$Yt4Yq9^hcz@R>o*mEpH{CwZWU==S z^NTP3yeUuS^ImwG&)D)DgzZ^4PQ+ieXD+zPzd+1k_y5a@DoUC^R|}>*vuE-+ZO`mb zTi5>B!r^~BL*jk?+zm71jgDuo(A&x|t+9w%f1P2X;^&iBPx$xk*GpR9HvFm(gtmAq+&he%wQHl_ghMay`&bA|s3jF9vKrc7Gy83w{jaS>Gew z{5)>1pN;^C=sTtK%ZJE0m%rX81VBWeDWxA(>=}WG0{lU7J~;!i3hw>f3##m2SdfSW z=#_KkYuSDx0GDDTs9gdVz^qVI1uuXpbyS5VKy^GT%0}z%Uds$BurXgd?Rf#HC;1R( z5AM=58mgeyNk+UmH?UnBfYIBy4{!2bxxDVfN|n|$o^}WX;9!wOMLtct>uh{aU13vJ zG6Mm`V4+0YfkTyN0PZl^DbDW@k*Lf*c=G>H0Zy>ua(3|Qu6K*dd&;0q<*p0VOO4W7 zY|x&azwmHY8;TOg5FqQ)ZE@5Uw%< zAP4}MD$cGz(yIU%h54(gXNLv?Mh*dB4z$r*z7^HoPx$MoC0LR9HvNm)#YDFbsvuKG{K?Or1>JA^YeFr{x4`LK0e#7kw!0*ZkaEhIH~X zoP2)T1pojKx&R_hzmX>l006I)(lsACBI4~Z005wa34lM(NF+iL___TIfr#$?+%E{X zFA(l1L;!g1S84Y~!3D5!`%o0T03Tze-w<)MtgQm%o0b-%eJ-r!Ec?=$0`M;XYfv)) zJM?ZnA-Imfs8}aJ4xkoS@G$YUQmh=nn%^cYH2~7{-r-+$%AyGKaOn-P5UW)ebcR?d zrPPK!(ovOZQHUBxLYxt*5;lTRy}}Uy>V*7zfEMbwD+Mh8$h3-)-bz6ec@6;>&4+a^ zi2gv+ftvGOxL`K(X{{#VejQLWK-^4n%X$7+KVG(KfES_3@#fS~G-gK?s(}(~+R*Cn qcz!Ynb%5#(U8dApah`Rj1AGB8l9nO7j2+kj0000i=Kl=>ffF{CekCbe2@T6G<#!}9oEf%4#)_f!tEH@L@s6>78X zTre~0F~isY3=9bjY*3V7!tDL>(bgE(tLih`+PQBnpT2Hs;hLYUAC_K>)@9JUHML6d Ua{19DphFovUHx3vIVCg!0QAgOY5)KL literal 0 HcmV?d00001 diff --git a/svr/res/image/drawtriangle.png b/svr/res/image/drawtriangle.png new file mode 100644 index 0000000000000000000000000000000000000000..610ebbdf6abc73015abb30aeb44b0fae83da0372 GIT binary patch literal 352 zcmV-m0iXVfP)Px$8c9S!R9HvtmR%CUFbIU{$<&jnC)1nhFcX|M;b$Rs`cfV{34AP@qzfG!%fa>O z1ej6aK}44}!Y2{EE90yJaPfOrkRkYcDk=b1B6<CK(p>;1Xnm=4qq5zr1sZpQ+mhr6aU_&AR(vc^9 z4+5(Y0U*Y+RDcW_0f_XO?o)>J05ZmlR4{Ky4}iPpu+BVs=evfq04l~Ssh|PO7%zet z>S+Ko#`DI)qZqu<1N_5ykqR3K?Md|>8`OC44Y>x8?ki^=1slx027s?mw3@PR7_s$N yGf^Ylx*4%`44HJV*!;LgZ^2#=zq}{FslXRcVo4! literal 0 HcmV?d00001 diff --git a/svr/res/image/drawtrianglefill.png b/svr/res/image/drawtrianglefill.png new file mode 100644 index 0000000000000000000000000000000000000000..d5e14ab4ed375e1b6db63fc29820900029ac6e7d GIT binary patch literal 343 zcmV-d0jU0oP)Px$5lKWrR9Hvtmt7LVAPj`l`{WSzWa`Q6A#xub96^eZzc%%yymdN(Zx=SD6F3GU z-T>hGDZLX>dUlP;T7`%g0C?1OL}Z>P*P9CwF)f}T>fv_51kh7oQOrcNSRJ(j^wj4y zT`s5r1odtR3jn9SIBz|WDu5<-(l(p6LIhA+zk;&3paD=>?~Nr3;8CAJv@S>h9`&X~ z3<0*Nx46IoY*DXvp$lM)-KJRn0PJCXL$nalJfiFY>|uSo-mp2X00PvDExHAWP|qI7 z0uZU5i)9TEseb6f8(`e~wX%Tsr7!#opxmJI8EEhM p0iwTC)_+psjVP1^08W6@ffpIvejz3>4Br3%002ovPDHLkV1h8^ja~o% literal 0 HcmV?d00001 diff --git a/svr/res/index.html b/svr/res/index.html index deadd11..0515ce2 100644 --- a/svr/res/index.html +++ b/svr/res/index.html @@ -26,90 +26,85 @@ + - + - + +
@@ -218,7 +179,7 @@
-
+ class="layui-btn tl-rtc-file-send-txt-tool-send">{{lang.send_text}}
@@ -242,13 +203,13 @@ :class="switchData.openCommRoom ? '':'tl-rtc-file-tool-disabled'">
- 公共聊天 + {{lang.chat_comm}}
- 公共聊天 + {{lang.chat_comm}}
@@ -257,88 +218,89 @@ :class="switchData.openScreenShare ? '':'tl-rtc-file-tool-disabled'">
- 屏幕共享 + {{lang.screen_sharing}}
- 屏幕共享 + {{lang.screen_sharing}}
- 视频通话 + {{lang.video_call}}
- 视频通话 + {{lang.video_call}}
- 开启直播 + {{lang.start_live}}
- 开启直播 + {{lang.start_live}}
- 取件号码 + {{lang.pickup_code}}
- 取件号码 + {{lang.pickup_code}} +
+
+ +
+
+ + {{lang.remote_draw}} +
+
+ + {{lang.remote_draw}} +
+
+
+
+ + {{lang.screen_recording}} +
+
+ + {{lang.screen_recording}}
- 密码房间 + {{lang.password_room}}
- 密码房间 -
-
-
-
- - 屏幕录制 -
-
- - 屏幕录制 + {{lang.password_room}}
- ChatGPT + {{lang.chat_gpt}}
- ChatGPT -
-
-
-
- - 远程画笔 -
-
- - 远程画笔 + {{lang.chat_gpt}}
@@ -349,47 +311,29 @@
- - - - - - - - + -
- {{nickName}} - 自己 + + 【{{lang.owner}}】- + {{nickName}} - {{lang.self}} + {{socketId}}
- - + {{Math.min(sendFileRecoderHistoryList.length, 99)}} - - + @@ -405,36 +349,20 @@
- - - - - - - - +
- {{remote.nickName}} - {{remote.id}} + + 【{{lang.owner}}】- + {{remote.nickName}} + + {{remote.langMode}} - {{remote.id}}
- + {{Math.min(remote.receiveChatRoomSingleList.length, 99)}} @@ -450,27 +378,27 @@ width: openRoomInput ? '96%' : '0', paddingLeft: openRoomInput ? (clientWidth < 450 ? '100px' : '155px') : '15px', height: clientWidth < 450 ? '40px' : '48px', - left: clientWidth < 450 ? '4%' : '2%', + left: '2%', }" type="text" maxlength="15" class="layui-input tl-rtc-file-create-room-input" v-model="roomId" - placeholder="输入房间编号"> + :placeholder="lang.input_room_num">
- - -
- 待发送({{chooseFileList.length}})- 共{{Object.keys(remoteMap).length}}人 - 共需发送{{sendFileRecoderList.length}}次 + {{lang.wait_sending}}({{chooseFileList.length}})- {{lang.total}}:{{Object.keys(remoteMap).length}} - + {{lang.wait_sending}}:{{sendFileRecoderList.length}}
-

点击选取文件,或将文件拖拽到此处,支持多文件拖拽发送,重新选择文件后将覆盖之前选取的文件

+

{{lang.click_choose_file}}

-
+
- - - - + + - - - - + + - - - + + - - - - - + + - - + + - - - - - + + - - + + - - - - - + + + + + + + + + +
- 名称: {{file.name}}, 类型: {{file.type === '' ? '未知类型' : file.type}}, 大小: {{getFileSizeStr(file.size)}} + {{lang.name}}: {{file.name}}, {{lang.type}}: {{file.type === '' ? + lang.unknown_type : file.type}}, {{lang.size}}: {{getFileSizeStr(file.size)}} - 发送给: {{file.nickName}} - {{file.id}} - {{file.progress}}% - {{file.cost}}s + {{lang.send_to}}: {{file.nickName}} - {{file.id}} - {{file.progress}}% - + {{file.cost}}s - - - [发送中] + + + [{{lang.sending}}] - + - [发送] - - - - - [发送] + [{{lang.send}}] - + - [已发送] + [{{lang.wait}}] - + + + [{{lang.sent}}] + + + - [预览] + [{{lang.preview}}] - + - [暂存] + [{{lang.save}}] - - - [暂存中] + + + [{{lang.saving}}] - - - [暂存失败] + + + [{{lang.save_failed}}] - - - [已暂存] + + + [{{lang.saved}}] - - + + - [取件码] + [{{lang.view_pickup_code}}]
@@ -658,20 +570,22 @@
-
@@ -681,8 +595,9 @@ bottom: sendFileRecoderHistoryList.length > 0 ? '14%' : '2%' }"> -
已选文件
- +
{{lang.selected_file}}
+ {{Math.min(chooseFileList.length, 99)}} @@ -691,11 +606,11 @@
-
- 当前选择文件列表 - 已选择({{chooseFileList.length}})个文件 + {{lang.cur_selected_file}} - {{lang.total}}({{chooseFileList.length}})
@@ -704,96 +619,59 @@
- - - - + + - - - - + + - - - + + - - - - - + + - - + + - - - - - + + - - + + - - - - - + + + + + + + + + +
- 名称: {{file.name}}, 类型: {{file.type === '' ? '未知类型' : file.type}}, 大小: {{getFileSizeStr(file.size)}} + {{lang.name}}: {{file.name}}, {{lang.type}}: {{file.type === '' ? + lang.unknown_type : file.type}}, {{lang.size}}: {{getFileSizeStr(file.size)}}
@@ -804,11 +682,11 @@
-
- 文件发送历史记录 - 共发送({{sendFileRecoderHistoryList.length}})次 + {{lang.sending_history}} - {{lang.total}}({{sendFileRecoderHistoryList.length}})
@@ -817,99 +695,63 @@
- - - - + + - - - - + + - - - + + - - - - - + + - - + + - - - - - + + - - + + - - - - - + + + + + + + + + +
- 名称: {{file.name}}, 类型: {{file.type === '' ? '未知类型' : file.type}}, 大小: {{getFileSizeStr(file.size)}} + {{lang.name}}: {{file.name}}, {{lang.type}}: {{file.type === '' ? + lang.unknown_type : file.type}}, {{lang.size}}: {{getFileSizeStr(file.size)}} - 发送给: {{file.nickName}} - {{file.id}} - {{file.progress}}% - {{file.cost}}s + {{lang.send_to}}: {{file.nickName}} - {{file.id}} - {{file.progress}}% - + {{file.cost}}s
@@ -924,7 +766,7 @@ :style="{top: receiveFileMaskHeightNum + '%'}">
- 已接收文件列表 - 共接收{{receiveFileRecoderList.length}}个文件 + {{lang.receive_file_list}} - {{lang.total}}:{{receiveFileRecoderList.length}}
@@ -933,107 +775,74 @@
- - - - + + - - - - + + - - - + + - - - - - + + - - + + - - - - - + + - - + + - - - - - + + + + + + + + + + +
- 名称: {{file.name}}, 类型: {{file.type === '' ? '未知类型' : file.type}}, 大小: {{getFileSizeStr(file.size)}} + {{lang.name}}: {{file.name}}, {{lang.type}}: {{file.type === '' ? + lang.unknown_type : file.type}}, {{lang.size}}: {{getFileSizeStr(file.size)}} - 文件来自: {{file.nickName}} - {{file.id}} - {{file.progress}}% - {{file.cost}}s + {{lang.file_from}}: {{file.nickName}} - {{file.id}} - {{file.progress}}% - + {{file.cost}}s - + - [下载] + [{{lang.download}}] - + - [预览] + [{{lang.preview}}]
@@ -1048,11 +857,11 @@
-
- 总共收到暂存文件 - ({{receiveCodeFileList.length}}) 个 + {{lang.total_pickup_file}} - ({{receiveCodeFileList.length}})
@@ -1062,100 +871,67 @@
- - - - + + - - - - + + - - - + + - - - - - + + - - + + - - - - - + + - - + + - - - - - + + + + + + + + + +
- 名称: {{file.name}} - 类型: {{file.type === '' ? '未知类型' : file.type}} - 大小: {{getFileSizeStr(file.size)}} - 取件码: {{file.code}} + {{lang.name}}: {{file.name}} - {{lang.type}}: {{file.type === '' ? + lang.unknown_type : file.type}} - {{lang.size}}: {{getFileSizeStr(file.size)}} - + {{lang.pickup_code}}: {{file.code}} - 来自: {{file.fromRoom}} - {{file.fromNickName}} - 时间: {{file.createTime}} - [点我下载] + {{lang.file_from}}: {{file.fromRoom}} - {{file.fromNickName}} - {{lang.type}}: + {{file.createTime}} + + [{{lang.click_download}}]
@@ -1170,12 +946,12 @@
- 执行日志 - 共 {{filterLogs.length}} 条 + {{lang.log}} - {{lang.total}}:{{filterLogs.length}}
- +
@@ -1183,28 +959,21 @@
{{log.time}}
- - - - - +
- {{log.type}} - {{log.type}} + {{log.type}} + {{log.type}} {{log.msg}}
- {{log.type}} - {{log.type}} + {{log.type}} + {{log.type}} {{log.msg}}
@@ -1218,7 +987,7 @@
- 多人音视频通话 + {{lang.video_call}}
@@ -1226,6 +995,8 @@
+
{{lang.demo_site}} +
@@ -1238,7 +1009,7 @@
- 多人屏幕共享 + {{lang.screen_sharing}}
@@ -1246,6 +1017,8 @@
+
{{lang.demo_site}} +
@@ -1258,7 +1031,7 @@
- 单人直播间 + {{lang.start_live}}
@@ -1266,16 +1039,19 @@
+
{{lang.demo_site}} +
-
+ + @@ -1284,7 +1060,11 @@ diff --git a/svr/res/js/comm.js b/svr/res/js/comm.js index 5ae7491..ceb4e6c 100644 --- a/svr/res/js/comm.js +++ b/svr/res/js/comm.js @@ -1,4 +1,33 @@ +// --------------------------- // +// -- comm.js -- // +// -- version : 1.0.0 -- // +// -- date : 2023-06-22 -- // +// --------------------------- // + window.tlrtcfile = { + addUrlHashParams : function(obj){ + let redirect = window.location.protocol + "//" + window.location.host + "#" + let oldObj = this.getRequestHashArgsObj(); + obj = Object.assign(oldObj,obj); + for(let key in obj){ + redirect += key + "=" + obj[key] + "&"; + } + return redirect; + }, + getRequestHashArgsObj : function () { + let query = decodeURIComponent(window.location.hash.substring(1)); + let args = query.split("&"); + let obj = {}; + for (let i = 0; i < args.length; i++) { + let pair = args[i].split("="); + const key = pair[0]; + const val = pair[1]; + if(key){ + obj[key] = val + } + } + return obj; + }, getRequestHashArgs : function (key) { let query = decodeURIComponent(window.location.hash.substring(1)); let args = query.split("&"); @@ -48,48 +77,59 @@ window.tlrtcfile = { } return getRandomName(4); }, - escapeHtml: function () { - var entityMap = { - escape: { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - "'": ''', - }, - unescape: { - '&': "&", - ''': "'", - '>': ">", - '<': "<", - '"': '"', - } + escapeStr: function (str) { + const entityMap = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + '/': '/', + '`': '`', + '=': '=' }; - var entityReg = { - escape: RegExp('[' + Object.keys(entityMap.escape).join('') + ']', 'g'), - unescape: RegExp('(' + Object.keys(entityMap.unescape).join('|') + ')', 'g') - } - - // 将HTML转义为实体 - function escape(html) { - if (typeof html !== 'string') return '' - return html.replace(entityReg.escape, function (match) { - return entityMap.escape[match] - }) - } - - // 将实体转回为HTML - function unescape(str) { - if (typeof str !== 'string') return '' - return str.replace(entityReg.unescape, function (match) { - return entityMap.unescape[match] - }) - } - - return { - escape: escape, - unescape: unescape - } + const encodedMap = { + '%': '%25', + '!': '%21', + "'": '%27', + '(': '%28', + ')': '%29', + '*': '%2A', + '-': '%2D', + '.': '%2E', + '_': '%5F', + '~': '%7E' + }; + return String(str).replace(/[&<>"'`=\/%!'()*\-._~]/g, function (s) { + return entityMap[s] || encodedMap[s] || ''; + }); + }, + unescapeStr: function (str) { + const entityMap = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + ''': "'", + '/': '/', + '`': '`', + '=': '=' + }; + const encodedMap = { + '%25': '%', + '%21': '!', + '%27': "'", + '%28': '(', + '%29': ')', + '%2A': '*', + '%2D': '-', + '%2E': '.', + '%5F': '_', + '%7E': '~' + }; + return String(str).replace(/&(amp|lt|gt|quot|#39|#x2F|#x60|#x3D);|%(25|21|27|28|29|2A|2D|2E|5F|7E)/g, function (s) { + return entityMap[s] || encodedMap[s] || ''; + }); }, getNetWorkState: function () { let ua = navigator.userAgent; @@ -148,6 +188,32 @@ window.tlrtcfile = { /(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i ); }, + chatKeydown: function (dom, callback) { + if(dom){ + dom.onkeydown = function (e) { + if (e.defaultPrevented) { + return; + } + + if (e.shiftKey) { + // shift+enter 换行 + return; + }else if (e.key !== undefined) { + if (e.key === "Enter") { + // enter键执行 + callback && callback() + e.preventDefault(); + } + } else if (e.keyCode !== undefined) { + if (e.keyCode === 13) { + // enter键执行 + callback && callback() + e.preventDefault(); + } + } + } + } + }, closeFullVideo: function (node, type, from) { let stream = node.srcObject; let nodeId = node.id.substr(0, node.id.length - 5); @@ -221,6 +287,37 @@ window.tlrtcfile = { } }, getWebrtcStats: async function (peerConnection) { + // 候选者对 + "candidate-pair" | + // 证书相关的统计信息 + "certificate" | + // 当前音视频编解码器的统计信息 + "codec" | + // CSRC相关的统计信息 + "csrc" | + // 数据通道的相关统计信息 + "data-channel" | + // 传入数据流的相关统计信息 + "inbound-rtp" | + // 本地候选连接的相关统计信息 + "local-candidate" | + // 媒体源的相关统计信息 + "media-source" | + // 传出数据流的相关统计信息 + "outbound-rtp" | + // 对等连接的相关统计信息 + "peer-connection" | + // 对等连接的相关统计信息 + "remote-candidate" | + // 远程传入数据流的相关统计信息 + "remote-inbound-rtp" | + // 远程传出数据流的相关统计信息 + "remote-outbound-rtp" | + // 媒体轨道的相关统计信息 + "track" | + // 传输协议的相关统计信息 + "transport"; + if (!peerConnection) { return "RTCPeerConnection is not available"; } @@ -294,42 +391,6 @@ window.tlrtcfile = { callback("keyup", event) }) }, - drawMousePath: function (coordinates) { - if (window.layer) { - layer.open({ - type: 1, - area: ["80%", "80%"], - title: "鼠标路径绘制", - content: `
`, - success: function (layero, index) { - document.querySelector(".layui-layer-content").style.borderRadius = "15px" - // 获取 canvas 元素 - const canvas = document.createElement('canvas'); - let dom = document.getElementById("tl-rtc-file-mouse-draw"); - canvas.setAttribute("style","height: 100%; width: 100%;") - canvas.height = document.querySelector(".layui-layer-content").clientHeight; - canvas.width = document.querySelector(".layui-layer-content").clientWidth; - dom.appendChild(canvas); - const context = canvas.getContext("2d"); - - // 设置画笔样式 - context.lineWidth = 1; - context.strokeStyle = "red"; - context.fillStyle = "red"; - - // 开始绘制路径 - context.beginPath(); - context.moveTo(coordinates[0].x, coordinates[0].y); - - for (let i = 1; i < coordinates.length; i++) { - context.lineTo(coordinates[i].x, coordinates[i].y); - } - // 完成路径绘制 - context.stroke(); - } - }); - } - }, scrollToBottom: function (dom, duration, timeout) { let start = dom.scrollTop; let end = dom.scrollHeight - dom.clientHeight; diff --git a/svr/res/js/draw.js b/svr/res/js/draw.js new file mode 100644 index 0000000..6edc064 --- /dev/null +++ b/svr/res/js/draw.js @@ -0,0 +1,1014 @@ +// --------------------------- // +// -- draw.js -- // +// -- version : 1.0.0 -- // +// -- date : 2023-06-22 -- // +// --------------------------- // + +const draw = new Vue({ + el: '#drawApp', + data: function () { + return { + devicePixelRatio: window.devicePixelRatio, //设备像素比 + drawing: false, // 是否正在绘制 + isOpenDraw: false, //是否打开画笔 + remoteDrawIndex: -1, //画笔弹窗index + prePoint: { x: 0, y: 0 }, //上一个点 + drawList: [], // 绘制操作列表, 暂时不存操作数据, 只传输 + drawHistoryList: [], // 绘制历史操作列表, 用于回退 + drawRollbackPoint: 0, // 绘制回退点 + lineWidth: 1, // 画笔线宽 + strokeStyle: "#000000", // 画笔颜色 + //line: 线条, circle: 圆形, rectangle: 矩形, text: 文字, delete: 擦除 + drawMode: "line", // 画笔模式 + circleFill : false, //填充圆模式 + rectangleFill : false, //填充矩形模式 + triangleFill : false, //填充三角形 + starFill : false, //填充星星 + rhomboidFill : false, //填充平行四边形 + hexagonFill : false, //填充六边形 + circleStarPoint: { x: 0, y: 0 }, //圆形开始点 + triangleStartPoint : { x: 0, y: 0 }, //三角形开始点 + starStartPoint : { x: 0, y: 0 }, //星星开始点 + rhomboidStartPoint : { x: 0, y: 0 }, //平行四边形开始点 + hexagonStartPoint : { x: 0, y: 0 }, //六边形边形开始点 + } + }, + watch: { + drawMode: { + handler: function (val) { + if (val !== 'text') { + const parentDom = document.getElementById("tl-rtc-file-mouse-draw-canvas-body"); + const textareaDom = document.getElementById("tl-rtc-file-mouse-draw-canvas-textarea"); + if (parentDom && textareaDom) { + parentDom.removeChild(textareaDom); + } + } + }, + deep: true, + immediate: true + }, + drawRollbackPoint: { + handler: function (val) { + this.toolDisabledHandler(); + }, + deep: true, + immediate: true + }, + drawHistoryList: { + handler: function (val) { + this.toolDisabledHandler(); + }, + deep: true, + immediate: true + } + }, + methods: { + toolDisabledHandler: function () { + + const drawRollbackDom = document.getElementById("drawRollback"); + if (drawRollbackDom) { + //如果回退点为0, 将回退节点禁用 + if (this.drawRollbackPoint === 0) { + drawRollbackDom.style.cursor = "no-drop"; + drawRollbackDom.style.color = "#4c53d926"; + } else { + drawRollbackDom.style.cursor = ""; + drawRollbackDom.style.color = ""; + } + } + + const drawRollupDom = document.getElementById("drawUndoRollback"); + if (drawRollupDom) { + //如果回退点为最后一个, 将前进节点禁用 + if (this.drawRollbackPoint === this.drawHistoryList.length - 1 + || this.drawHistoryList.length === 0) { + drawRollupDom.style.cursor = "no-drop"; + drawRollupDom.style.color = "#4c53d926" + } else { + drawRollupDom.style.cursor = ""; + drawRollupDom.style.color = ""; + } + } + + const drawResetDom = document.getElementById("drawReset"); + if (drawResetDom) { + if (this.drawHistoryList.length === 0) { + drawResetDom.style.cursor = "no-drop"; + drawResetDom.style.color = "#4c53d926" + } else { + drawResetDom.style.cursor = ""; + drawResetDom.style.color = ""; + } + } + }, + openRemoteDraw: function (options) { + //绘制远程画笔时,如果没有打开本地画笔面板,则不允许绘制 + if (!this.isOpenDraw) { + return + } + const canvas = document.getElementById('tl-rtc-file-mouse-draw-canvas'); + options.canvas = canvas; + options.context = canvas.getContext('2d'); + options.fromRemote = true; + + const { drawMode } = options; + + //收到结束标识,保存当前画板到缓存数据中 + if(options.event === 'end'){ + this.endDrawHandler(options) + return + } + + if (drawMode === 'line') { + this.drawLine(options); + } else if (drawMode === 'circle') { + this.drawCircle(options); + } else if (drawMode === 'rectangle') { + this.drawRectangle(options); + } else if (drawMode === 'text') { + this.drawText(options); + } else if(drawMode === 'triangle'){ + this.drawTriangle(options); + } else if(drawMode === 'star'){ + this.drawStar(options); + } else { + console.log("收到远程未知的绘制模式") + } + }, + // 打开/关闭本地画笔 + openDraw: function ({ + openCallback, closeCallback, localDrawCallback + }) { + let that = this; + + if (this.isOpenDraw) { + layer.close(this.remoteDrawIndex); + this.remoteDrawIndex = -1; + this.isOpenDraw = !this.isOpenDraw; + closeCallback && closeCallback(this.drawHistoryList.length); + return + } + + this.remoteDrawIndex = layer.open({ + type: 1, + area: ["90%", "90%"], + scrollbar: false, + title: "远程画笔绘制", + content: ` +
+
+
+
重置:
+ +
+
+
擦除:
+ +
+
+
撤销:
+ + +
+
+
线条:
+ +
+
+
圆形:
+ + +
+
+
矩形:
+ + +
+
+
三角:
+ + + + +
+
+
文字:
+ +
+
+
图像:
+ +
+
+
下载:
+ +
+
+
颜色:
+
+
+
+
画笔粗细:
+
+
+
+
画布比例:
+
+
+
+
+
+ `, + success: function (layero, index) { + that.isOpenDraw = true; + that.toolDisabledHandler(); + + document.querySelector(".layui-layer-content").style.borderRadius = "15px"; + //工具初始化 + colorpicker.render({ + elem: '#tl-rtc-file-mouse-draw-stroke-color', + color: '#00000', + alpha: true, + done: function (color) { + that.strokeStyle = color; + } + }); + + //画笔大小 + let sliderTextObj = slider.render({ + elem: '#tl-rtc-file-mouse-draw-line-size', + min: 1, + max: 23, + step: 1, + showstep: true, + change: function (value) { + that.lineWidth = value * that.devicePixelRatio; + if (value < 10) { + document.getElementById("tl-rtc-file-mouse-draw-line-size-txt").innerText = "0" + value; + } else { + document.getElementById("tl-rtc-file-mouse-draw-line-size-txt").innerText = value; + } + } + }); + sliderTextObj.setValue(1) + + //画布比例 + let sliderDivObj = slider.render({ + elem: '#tl-rtc-file-mouse-draw-div-size', + min: 10, + max: 200, + disabled : true, + change: function (value) { + document.getElementById("tl-rtc-file-mouse-draw-div-size-txt").innerText = value + "%"; + } + }); + sliderDivObj.setValue(90) + + // 创建 canvas 元素 + const canvas = document.createElement('canvas'); + let dom = document.getElementById("tl-rtc-file-mouse-draw-canvas-body"); + canvas.setAttribute("id", "tl-rtc-file-mouse-draw-canvas"); + canvas.setAttribute("class", "tl-rtc-file-mouse-draw-canvas-line"); + + const width = document.querySelector(".tl-rtc-file-mouse-draw-body").clientWidth; + const height = (document.querySelector(".layui-layer-content").clientHeight - + document.querySelector(".tl-rtc-file-mouse-draw-body").clientHeight) - 20; + + //设置画布大小 + canvas.style.width = width + "px" + canvas.style.height = height + "px" + + //设置画布宽高 ,为了保证高清屏下绘制不模糊,需要将画布宽高放大 + canvas.width = width * that.devicePixelRatio; + canvas.height = height * that.devicePixelRatio; + + dom.appendChild(canvas); + let context = canvas.getContext('2d'); + + //初始化一张默认画布 + that.drawHistoryList.push(canvas.toDataURL()) + + if (document.body.ontouchstart === undefined) { + that.pcLocalDraw({ canvas, context, localDrawCallback }); + } else { + that.mobileLocalDraw({ canvas, context, localDrawCallback }); + } + + document.getElementById("drawLine").onclick = function () { + that.drawMode = "line"; + canvas.setAttribute("class", "tl-rtc-file-mouse-draw-canvas-line"); + } + + document.getElementById("drawRectangleFill").onclick = function () { + canvas.setAttribute("class", "tl-rtc-file-mouse-draw-canvas-rectangle-fill"); + that.drawMode = "rectangle"; + that.rectangleFill = true; + } + + document.getElementById("drawCircle").onclick = function () { + canvas.setAttribute("class", "tl-rtc-file-mouse-draw-canvas-circle"); + that.drawMode = "circle"; + that.circleFill = false; + } + + document.getElementById("drawCircleFill").onclick = function () { + canvas.setAttribute("class", "tl-rtc-file-mouse-draw-canvas-circle-fill"); + that.drawMode = "circle"; + that.circleFill = true; + } + + document.getElementById("drawTriangle").onclick = function () { + canvas.setAttribute("class", "tl-rtc-file-mouse-draw-canvas-triangle"); + that.drawMode = "triangle"; + that.triangleFill = false; + } + + document.getElementById("drawTriangleFill").onclick = function () { + canvas.setAttribute("class", "tl-rtc-file-mouse-draw-canvas-triangle-fill"); + that.drawMode = "triangle"; + that.triangleFill = true; + } + + document.getElementById("drawStar").onclick = function () { + canvas.setAttribute("class", "tl-rtc-file-mouse-draw-canvas-star"); + that.drawMode = "star"; + that.starFill = false; + } + + document.getElementById("drawStarFill").onclick = function () { + canvas.setAttribute("class", "tl-rtc-file-mouse-draw-canvas-star-fill"); + that.drawMode = "star"; + that.starFill = true; + } + + document.getElementById("drawRectangle").onclick = function () { + canvas.setAttribute("class", "tl-rtc-file-mouse-draw-canvas-rectangle"); + that.drawMode = "rectangle"; + that.rectangleFill = false; + } + + document.getElementById("drawText").onclick = function () { + canvas.setAttribute("class", "tl-rtc-file-mouse-draw-canvas-text"); + that.drawMode = "text"; + } + + document.getElementById("drawReset").onclick = function () { + that.drawReset({ canvas, context, localDrawCallback }) + } + + document.getElementById("drawDelete").onclick = function () { + that.drawMode = "delete"; + canvas.setAttribute("class", "tl-rtc-file-mouse-draw-canvas-delete"); + } + + document.getElementById("drawRollback").onclick = function () { + that.drawRollback({ canvas, context, localDrawCallback }); + } + + document.getElementById("drawUndoRollback").onclick = function () { + that.drawUndoRollback({ canvas, context, localDrawCallback }); + } + + document.getElementById("drawImage").onclick = function () { + that.drawImage({ canvas, context, localDrawCallback }) + } + + document.getElementById("drawDonwload").onclick = function () { + that.drawDownload({ canvas, context, localDrawCallback }) + } + }, + cancel: function () { + that.isOpenDraw = false; + } + }); + + openCallback && openCallback(); + + return + }, + // pc端画笔渲染处理 + pcLocalDraw: function ({ canvas, context, localDrawCallback }) { + let that = this; + canvas.onmousedown = function (e) { + that.drawing = true; + that.prePoint = { x: e.offsetX * that.devicePixelRatio, y: e.offsetY * that.devicePixelRatio }; + that.startDrawHandler({ canvas, context, localDrawCallback }); + }; + canvas.onmousemove = function (e) { + let curPoint = { x: e.offsetX * that.devicePixelRatio, y: e.offsetY * that.devicePixelRatio }; + that.drawingHandler({ canvas, curPoint, context, localDrawCallback }); + that.prePoint = curPoint; + }; + canvas.onmouseup = function (e) { + that.endDrawHandler({ canvas, curPoint: that.prePoint, context, localDrawCallback }) + that.drawing = false; + }; + }, + // 移动端画笔渲染处理 + mobileLocalDraw: function ({ canvas, context, localDrawCallback }) { + let that = this; + canvas.ontouchstart = function (e) { + that.drawing = true; + that.prePoint = { + x: ( + e.touches[0].clientX - (15 * that.devicePixelRatio) + ) * that.devicePixelRatio, + y: ( + e.touches[0].clientY - + document.querySelector(".tl-rtc-file-mouse-draw-body").clientHeight - + (50 * Math.min(that.devicePixelRatio, 2)) + ) * that.devicePixelRatio + }; + + that.startDrawHandler({ canvas, context, localDrawCallback }); + }; + canvas.ontouchmove = function (e) { + let curPoint = { + x: ( + e.touches[0].clientX - (15 * that.devicePixelRatio) + ) * that.devicePixelRatio, + y: ( + e.touches[0].clientY - + document.querySelector(".tl-rtc-file-mouse-draw-body").clientHeight - + (50 * Math.min(that.devicePixelRatio, 2)) + ) * that.devicePixelRatio + }; + + that.drawingHandler({ canvas, curPoint, context, localDrawCallback }); + that.prePoint = curPoint; + }; + canvas.ontouchend = function (e) { + that.endDrawHandler({ canvas, curPoint: that.prePoint, context, localDrawCallback }) + that.drawing = false; + }; + }, + startDrawHandler: function ({ canvas, context, localDrawCallback }) { + //公共参数 + let commOptions = { + event : "start", + canvas, + context, + localDrawCallback, + drawMode: this.drawMode, + lineWidth: this.lineWidth, + strokeStyle: this.strokeStyle, + fillStyle: this.strokeStyle, + lineCap: "round", + lineJoin: "round" + } + + if (this.drawMode === 'delete') { + this.drawDelete(Object.assign(commOptions, { + prePoint: this.prePoint, + curPoint : this.prePoint + })) + } else if (this.drawMode === 'rectangle') { + //开始的时候固定好矩形的起点 + this.rectangleStartPoint = this.prePoint; + this.drawRectangle(Object.assign(commOptions, { + rectangleStartPoint: this.rectangleStartPoint, + curPoint: this.prePoint, + rectangleFill : this.rectangleFill + })) + } else if (this.drawMode === 'circle') { + //开始的时候固定好圆的起点 + this.circleStartPoint = this.prePoint; + this.drawCircle(Object.assign(commOptions, { + circleStartPoint: this.circleStartPoint, + curPoint: this.prePoint, + circleFill : this.circleFill, + })) + } else if(this.drawMode === 'triangle'){ + //开始的时候固定好三角形的起点 + this.triangleStartPoint = this.prePoint; + this.drawTriangle(Object.assign(commOptions, { + triangleStartPoint: this.triangleStartPoint, + curPoint: this.prePoint, + triangleFill : this.triangleFill + })); + } else if(this.drawMode === 'star'){ + //开始的时候固定好星星的起点 + this.starStartPoint = this.prePoint; + this.drawStar(Object.assign(commOptions, { + starStartPoint: this.starStartPoint, + curPoint: this.prePoint, + starFill : this.starFill + })); + } else if (this.drawMode === 'text') { + this.drawText(Object.assign(commOptions, { + curPoint: this.prePoint, + })) + this.endDrawHandler(Object.assign(commOptions, { + curPoint: this.prePoint, + })) + } else if(this.drawMode === 'line'){ + this.drawLine(Object.assign(commOptions, { + prePoint: this.prePoint, + curPoint: this.prePoint, + })); + } + }, + drawingHandler: function ({ canvas, curPoint, context, localDrawCallback }) { + if (!this.drawing) { + return + } + //公共参数 + let commOptions = { + event : "move", + canvas, + context, + localDrawCallback, + drawMode: this.drawMode, + lineWidth: this.lineWidth, + strokeStyle: this.strokeStyle, + fillStyle: this.strokeStyle, + lineCap: "round", + lineJoin: "round" + } + + if (this.drawMode === 'delete') { + this.drawDelete(Object.assign(commOptions, { + prePoint: this.prePoint, + curPoint + })) + } else if (this.drawMode === 'rectangle') { + this.drawRectangle(Object.assign(commOptions, { + rectangleStartPoint: this.rectangleStartPoint, + curPoint, + rectangleFill : this.rectangleFill + })); + } else if (this.drawMode === 'circle') { + this.drawCircle(Object.assign(commOptions, { + circleStartPoint: this.circleStartPoint, + curPoint, + circleFill : this.circleFill, + })) + } else if(this.drawMode === 'triangle'){ + this.drawTriangle(Object.assign(commOptions, { + triangleStartPoint: this.triangleStartPoint, + curPoint, + triangleFill : this.triangleFill + })); + } else if(this.drawMode === 'star'){ + this.drawStar(Object.assign(commOptions, { + starStartPoint: this.starStartPoint, + curPoint, + starFill : this.starFill + })); + } else if(this.drawMode === 'line'){ + this.drawLine(Object.assign(commOptions, { + prePoint: this.prePoint, + curPoint, + })); + } + }, + endDrawHandler: function ({ canvas, curPoint, context, localDrawCallback }) { + //图像记录,用于回滚撤销操作 + if ( + this.drawMode === 'line' || this.drawMode === 'circle' || + this.drawMode === 'rectangle' || this.drawMode === 'text' || + this.drawMode === 'triangle' || this.drawMode === 'star' + ) { + this.drawHistoryList.push(canvas.toDataURL()); + this.drawRollbackPoint = this.drawHistoryList.length - 1; + } + + //结束的时候通知下远程,可以保存画布到缓存列表中 + localDrawCallback && localDrawCallback({ + event : "end", + drawMode : this.drawMode + }) + }, + //下载画布图片 + drawDownload: function ( options ) { + const { canvas, context, localDrawCallback } = options; + + let image = canvas.toDataURL("image/png").replace("image/png", "image/octet-stream"); + let link = document.createElement('a'); + link.href = image; + link.download = "image.png"; + link.click(); + }, + // 画布重置 + drawReset: function (options) { + const { canvas, context, localDrawCallback } = options; + + context.clearRect(0, 0, canvas.width, canvas.height); + this.drawHistoryList = []; + this.drawRollbackPoint = 0; + }, + // 回退回滚的绘制 + drawUndoRollback: function (options) { + const { canvas, context, localDrawCallback } = options; + //最多前进到最后一条记录 + if (this.drawRollbackPoint < this.drawHistoryList.length - 1) { + this.drawRollbackPoint = this.drawRollbackPoint + 1; + } + + const img = new Image(); + img.src = this.drawHistoryList[this.drawRollbackPoint]; + img.onload = function () { + context.clearRect(0, 0, canvas.width, canvas.height); + context.drawImage(img, 0, 0, canvas.width, canvas.height); + } + }, + // 画布回退 + drawRollback: async function (options) { + const { canvas, context, localDrawCallback } = options; + //最多回退到原点 + if (this.drawRollbackPoint > 0) { + this.drawRollbackPoint = this.drawRollbackPoint - 1; + const img = new Image(); + img.src = this.drawHistoryList[this.drawRollbackPoint]; + img.onload = function () { + context.clearRect(0, 0, canvas.width, canvas.height); + context.drawImage(img, 0, 0, canvas.width, canvas.height); + } + } + }, + // 画笔擦除 + drawDelete: function (options) { + const { canvas, context, prePoint, curPoint, localDrawCallback } = options; + context.lineWidth = this.lineWidth; + //防止移动过快,canvas渲染存在间隔,导致线条断层,在这里补充绘制间隔的点 + let x = prePoint.x; + let y = prePoint.y; + let dx = curPoint.x - prePoint.x; + let dy = curPoint.y - prePoint.y; + let distance = Math.sqrt(dx * dx + dy * dy); + let xUnit = dx / distance; + let yUnit = dy / distance; + let i = 0; + while (i < distance) { + x += xUnit; + y += yUnit; + context.clearRect(x - 20, y - 20, this.lineWidth, this.lineWidth); + i++; + } + }, + // 图片渲染处理 + drawImage: function (options) { + let that = this; + const { canvas, context, localDrawCallback } = options; + let input = document.createElement("input"); + input.setAttribute("type", "file"); + input.setAttribute("accept", "image/*"); + input.click(); + input.onchange = function () { + let file = input.files[0]; + let reader = new FileReader(); + reader.readAsDataURL(file); + reader.onload = function () { + let img = new Image(); + img.src = this.result; + img.onload = function () { + context.drawImage(img, 0, 0, img.width, img.height, 0, 0, canvas.width, canvas.height); + //画完图片,保存操作记录 + that.drawHistoryList.push(canvas.toDataURL()); + that.drawRollbackPoint = that.drawHistoryList.length - 1; + } + } + } + }, + // 画笔渲染处理, 两点式绘制 + drawLine: function (options) { + const { + canvas, context, localDrawCallback, prePoint, curPoint, + lineWidth, strokeStyle, fillStyle, lineCap, lineJoin, fromRemote, + } = options; + + // 设置画笔样式 + context.lineWidth = lineWidth; + context.strokeStyle = strokeStyle; + context.fillStyle = fillStyle; + context.lineCap = lineCap; + context.lineJoin = lineJoin; + + // 开始绘制路径 + context.beginPath(); + + //防止移动过快,canvas渲染存在间隔,导致线条断层,在这里补充绘制间隔的点 + let x = prePoint.x; + let y = prePoint.y; + let dx = curPoint.x - prePoint.x; + let dy = curPoint.y - prePoint.y; + let distance = Math.sqrt(dx * dx + dy * dy); + let xUnit = dx / distance; + let yUnit = dy / distance; + let i = 0; + while (i < distance) { + x += xUnit; + y += yUnit; + context.ellipse(x, y, lineWidth, lineWidth, 0, 0, 2 * Math.PI); + context.fill() + i++; + } + + if (!fromRemote) { //本地的绘制数据回调给远端 + localDrawCallback && localDrawCallback(options); + } + }, + // 星星渲染处理 + drawStar: function (options) { + const { + canvas, context, localDrawCallback, starStartPoint, curPoint, + lineWidth, strokeStyle, fillStyle, lineCap, lineJoin, fromRemote, starFill + } = options; + + // 设置画笔样式 + context.lineWidth = lineWidth; + context.strokeStyle = strokeStyle; + context.fillStyle = fillStyle; + context.lineCap = lineCap; + context.lineJoin = lineJoin; + + const { x, y } = curPoint; + const size = Math.sqrt( + Math.pow(curPoint.x - starStartPoint.x, 2) + Math.pow(curPoint.y - starStartPoint.y, 2) + ) / 2; + + if (this.drawRollbackPoint >= 0) { + const img = new Image(); + img.src = this.drawHistoryList[this.drawRollbackPoint]; + img.onload = function () { + //清理实时移动绘制的五角星 + context.clearRect(0, 0, canvas.width, canvas.height); + //绘制之前的数据 + context.drawImage(img, 0, 0, canvas.width, canvas.height); + + context.beginPath(); + for (let i = 0; i <= 5; i++) { + context.lineTo( + Math.cos((18 + i * 72) / 180 * Math.PI) * size + x, + -Math.sin((18 + i * 72) / 180 * Math.PI) * size + y + ); + context.lineTo( + Math.cos((54 + i * 72) / 180 * Math.PI) * (size / 2) + x, + -Math.sin((54 + i * 72) / 180 * Math.PI) * (size / 2) + y + ); + } + if(starFill){ + context.fill() + } + context.stroke(); + } + } + + if (!fromRemote) { //本地的绘制数据回调给远端 + localDrawCallback && localDrawCallback(options); + } + }, + // 三角形渲染处理 + drawTriangle: function (options) { + const { + canvas, context, localDrawCallback, triangleStartPoint, curPoint, + lineWidth, strokeStyle, fillStyle, lineCap, lineJoin, fromRemote, triangleFill + } = options; + + // 设置画笔样式 + context.lineWidth = lineWidth; + context.strokeStyle = strokeStyle; + context.fillStyle = fillStyle; + context.lineCap = lineCap; + context.lineJoin = lineJoin; + + //根据起点和当前移动的位置,计算三角形三个点进行绘制 + const x1 = triangleStartPoint.x; + const y1 = triangleStartPoint.y; + const x2 = curPoint.x; + const y2 = curPoint.y; + const x3 = triangleStartPoint.x - (curPoint.x - triangleStartPoint.x); + const y3 = curPoint.y; + + if (this.drawRollbackPoint >= 0) { + const img = new Image(); + img.src = this.drawHistoryList[this.drawRollbackPoint]; + img.onload = function () { + //清理实时移动绘制的三角形 + context.clearRect(0, 0, canvas.width, canvas.height); + //绘制之前的数据 + context.drawImage(img, 0, 0, canvas.width, canvas.height); + //绘制新三角形 + context.beginPath(); + + context.moveTo(x1, y1); + context.lineTo(x2, y2); + context.lineTo(x3, y3); + context.lineTo(x1, y1); + + if(triangleFill){ + context.fill() + } + context.stroke(); + } + } + + if (!fromRemote) { //本地的绘制数据回调给远端 + localDrawCallback && localDrawCallback(options); + } + }, + // 圆形渲染处理 + drawCircle: function (options) { + const { + canvas, context, localDrawCallback, circleStartPoint, curPoint, + lineWidth, strokeStyle, fillStyle, lineCap, lineJoin, fromRemote, circleFill + } = options; + + // 设置画笔样式 + context.lineWidth = lineWidth; + context.strokeStyle = strokeStyle; + context.fillStyle = fillStyle; + context.lineCap = lineCap; + context.lineJoin = lineJoin; + + const centerX = (circleStartPoint.x + curPoint.x) / 2; + const centerY = (circleStartPoint.y + curPoint.y) / 2; + const radius = Math.sqrt( + Math.pow(curPoint.x - circleStartPoint.x, 2) + Math.pow(curPoint.y - circleStartPoint.y, 2) + ) / 2; + + if (this.drawRollbackPoint >= 0) { + const img = new Image(); + img.src = this.drawHistoryList[this.drawRollbackPoint]; + img.onload = function () { + //清理实时移动绘制的圆 + context.clearRect(0, 0, canvas.width, canvas.height); + //绘制之前的数据 + context.drawImage(img, 0, 0, canvas.width, canvas.height); + //绘制新圆 + context.beginPath(); + context.ellipse(centerX, centerY, radius, radius, 0, 0, 2 * Math.PI); + if(circleFill){ + context.fill() + } + context.stroke(); + } + } + + if (!fromRemote) { //本地的绘制数据回调给远端 + localDrawCallback && localDrawCallback(options); + } + }, + // 矩形渲染处理 + drawRectangle: function (options) { + const { + canvas, context, localDrawCallback, rectangleStartPoint, curPoint, + lineWidth, strokeStyle, fillStyle, lineCap, lineJoin, fromRemote, rectangleFill + } = options; + + // 设置画笔样式 + context.lineWidth = lineWidth; + context.strokeStyle = strokeStyle; + context.fillStyle = fillStyle; + context.lineCap = lineCap; + context.lineJoin = lineJoin; + + // 计算矩形的位置和尺寸 + const x = Math.min(rectangleStartPoint.x, curPoint.x); + const y = Math.min(rectangleStartPoint.y, curPoint.y); + const width = Math.abs(curPoint.x - rectangleStartPoint.x); + const height = Math.abs(curPoint.y - rectangleStartPoint.y); + + if (this.drawRollbackPoint >= 0) { + const img = new Image(); + img.src = this.drawHistoryList[this.drawRollbackPoint]; + img.onload = function () { + //清理实时移动绘制的矩形 + context.clearRect(0, 0, canvas.width, canvas.height); + //绘制之前的数据 + context.drawImage(img, 0, 0, canvas.width, canvas.height); + //绘制新矩形 + context.beginPath(); + context.rect(x, y, width, height); + if(rectangleFill){ + context.fill(); + } + context.stroke(); + } + } + + if (!fromRemote) { //本地的绘制数据回调给远端 + localDrawCallback && localDrawCallback(options); + } + }, + // 文字渲染处理 + drawText: function (options) { + let { + canvas, context, localDrawCallback, curPoint, text, lineWidth, strokeStyle, + fillStyle, lineCap, lineJoin, fromRemote, + } = options; + + curPoint = { + x : curPoint.x / window.devicePixelRatio, + y : curPoint.y / window.devicePixelRatio + } + + // 设置字体样式 + context.strokeStyle = strokeStyle; + context.font = "28px orbitron"; + context.textBaseline = "middle"; + context.lineCap = lineCap; + context.lineJoin = lineJoin; + context.lineWidth = 3; + + const canvasWidth = parseInt(canvas.style.width); + const canvasHeight = parseInt(canvas.style.height); + + //文字渲染处理 + function drawTextHandler(content){ + const textWidth = context.measureText(content).width; + // 如果文字超出画布宽度,将文字绘制到画布最右边 + let fixPointX = canvasWidth - textWidth > curPoint.x ? curPoint.x : canvasWidth - textWidth; + fixPointX = fixPointX < 10 ? 10 : fixPointX; + // 如果文字超出画布高度,将文字绘制到画布最下边 + let fixPointY = canvasHeight - 20 > curPoint.y ? curPoint.y : canvasHeight - 20; + fixPointY = fixPointY < 10 ? 10 : fixPointY; + context.strokeText(content, fixPointX * window.devicePixelRatio, fixPointY * window.devicePixelRatio); + } + + if(fromRemote){ + drawTextHandler(text); + return + } + + //本地的绘制数据回调给远端 + const parentDom = document.getElementById("tl-rtc-file-mouse-draw-canvas-body"); + const textareaDom = document.getElementById("tl-rtc-file-mouse-draw-canvas-textarea"); + if (textareaDom) { + parentDom.removeChild(textareaDom); + } + + // 创建临时的输入框 + const textarea = document.createElement('textarea'); + textarea.setAttribute("id", "tl-rtc-file-mouse-draw-canvas-textarea"); + textarea.className = "layui-textarea"; + textarea.style.width = '100px'; + textarea.style.height = '30px'; + textarea.style.wordBreak = 'break-all'; + textarea.style.border = "1px dashed"; + textarea.style.position = 'absolute'; + + if(curPoint.x + 90 < canvasWidth){ + textarea.style.left = (curPoint.x + 10) + 'px'; + }else{ + textarea.style.left = (canvasWidth - 90) + 'px'; + } + + if (curPoint.y + 100 > canvasHeight) { + textarea.style.bottom = '10px'; + } else if (curPoint.y < 100) { + textarea.style.bottom = (canvasHeight - 100) + 'px'; + } else { + textarea.style.top = (curPoint.y + 70)+ 'px'; + } + parentDom.appendChild(textarea); + textarea.focus(); + + textarea.addEventListener('blur', function () { + if (textarea.value !== '') { + drawTextHandler(textarea.value); + document.getElementById("drawLine").click() + options.text = textarea.value; + localDrawCallback && localDrawCallback(options); + } + }) + } + }, + mounted: function () { + + //本地画笔 + window.Bus.$on("openDraw", (options) => { + this.openDraw(options) + }); + + //远程画笔 + window.Bus.$on("openRemoteDraw", (options) => { + this.openRemoteDraw(options) + }); + + } +}) \ No newline at end of file diff --git a/svr/res/js/index.js b/svr/res/js/index.js index 59b682b..866576b 100644 --- a/svr/res/js/index.js +++ b/svr/res/js/index.js @@ -1,14 +1,18 @@ +// --------------------------- // +// -- index.js -- // +// -- version : 1.0.0 -- // +// -- date : 2023-06-22 -- // +// --------------------------- // + + // index.js var file = null; -axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { - let resData = initData.data; - // 是否禁用中继 - let notUseRelay = window.localStorage.getItem("tl-rtc-file-not-use-relay"); - notUseRelay = notUseRelay && notUseRelay === 'true' - if (notUseRelay) { - resData.rtcConfig.iceServers = [resData.rtcConfig.iceServers[0]] - } +// 是否禁用中继 +let useTurn = (window.localStorage.getItem("tl-rtc-file-use-relay") || "") === 'true'; + +axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => { + let resData = initData.data; file = new Vue({ el: '#tl-rtc-file-app', @@ -18,6 +22,10 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { socket = io(resData.wsHost); } return { + langMode : "zh", // 默认中文 + lang : {}, // 语言包 + logo : resData.logo, // 打印logo + version : resData.version,// 项目当前版本 socket: socket, // socket config: resData.rtcConfig, // rtc配置 options: resData.options, // rtc配置 @@ -30,8 +38,6 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { showCodeFile: false, // 展示底部取件码文件列表 showLogs: false, // 展示运行日志 showMedia: false, // 展示音视频/屏幕共享/直播 - isScreen: false, //是否在录屏中 - screenTimes: 0, //当前录屏时间 isScreenShare: false, //是否在屏幕共享中 screenShareTimes: 0, //当前屏幕共享时间 isVideoShare: false, //是否在音视频中 @@ -51,6 +57,7 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { isMouseDrag : false, //是否正在拖拽鼠标 isSendAllWaiting : false, //一键发送文件时,有1秒时间间隔,这个记录当前是否是一键发送文件等待中 isShareJoin : false, //是否是分享加入房间 + isRemoteControl : false, // 是否正在进行远程控制 sendFileMaskHeightNum: 150, // 用于控制发送文件列表面板展示 chooseFileMaskHeightNum: 150, // 用于控制选择文件列表面板展示 @@ -88,7 +95,8 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { uploadCodeFileProgress: 0, // 上传暂存文件的进度 previewFileMaxSize : 1024 * 1024 * 5, // 5M以内允许预览 uploadCodeFileMaxSize : 1024 * 1024 * 10, // 10M以内允许暂存 - controlListMaxSize : 100, // 100条控制指令以内,发送到socket + controlListMaxSize : 20, // 100条控制指令以内,发送到socket + mouseMoveUnit : 1, //鼠标移动的最小单位 currentChooseFileRecoder : null, //当前进行发送的文件记录 currentChooseFile: null, //当前发送中的文件 @@ -102,20 +110,19 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { receiveAiChatList: [], //ai对话内容 logs: [], //记录日志 popUpList: [], //消息数据 - mouseMove : [], // 鼠标移动坐标 - controlList : [], // 控制列表 + preMouseMove : {}, //上一次鼠标移动的事件 + controlList : [], // 远程控制操作列表 ips: [], // 记录ip列表,检测是否支持p2p popUpMsgDom : [], // 消息弹窗dom token: "", //登录token manageIframeId: 0, //实现自适应 - useTurn: !notUseRelay, //是否使用中继服务器 + useTurn: useTurn, //是否使用中继服务器 aiAnsweringTxtIntervalId: 0, //实现等待动画 aiAnsweringTxt: "思考中...", //ai思考中的文字 logsFilter: "", //日志过滤参数 - clientWidth : document.body.clientWidth, - preMouseMove : {}, //上一次鼠标移动的事件 + clientWidth : document.body.clientWidth, //页面宽度 } }, computed: { @@ -138,9 +145,11 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { }, filterLogs: function () { return this.logs.filter(item => { - return item.msg.indexOf(this.logsFilter) > -1 + if(item.msg){ + return item.msg.indexOf(this.logsFilter) > -1 || item.time.indexOf(this.logsFilter) > -1 || item.type.indexOf(this.logsFilter) > -1 + } }) }, toolSlidesPerViewCount: function(){ @@ -156,8 +165,8 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { isAiAnswering: function (newV, oldV) { if (newV) { this.aiAnsweringTxtIntervalId = setInterval(() => { - if (this.aiAnsweringTxt === '思考中....') { - this.aiAnsweringTxt = '思考中' + if (this.aiAnsweringTxt === this.lang.ai_thinking + '....') { + this.aiAnsweringTxt = this.lang.ai_thinking } else { this.aiAnsweringTxt += '.' } @@ -193,12 +202,7 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { immediate: true }, controlList: { - handler: function (newV, oldV) { - //如果长度大于100,将数据发送到socket,并清空 - if(newV.length > this.controlListMaxSize){ - console.log("推送鼠标事件") - } - }, + handler: function (newV, oldV) { }, deep: true, immediate: true }, @@ -209,53 +213,75 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { } }, methods: { + consoleLogo : function(){ + window.console.log(`%c____ TL-RTC-FILE-V10.1.5 ____ \n____ FORK ME IN GITHUB ____ \n____ https://github.com/tl-open-source/tl-rtc-file ____`, this.logo) + }, + changeLanguage: function () { + let that = this; + window.dropdown.render({ + elem: '#language', + data: [{ + title: 'Chinese', + id: 'zh' + },{ + type: '-' + },{ + title: 'English', + id: 'en' + }], + className: 'language-mode', + click: function (obj) { + window.location.href = window.tlrtcfile.addUrlHashParams({ + lang: obj.id + }); + window.location.reload() + } + }); + }, openDisclaimer: function(){ - if(window.layer){ - layer.open({ - type: 2, - title : "演示网站/开源项目协议声明", - area: ['100%','100%'], - shade: 0.5, - shadeClose : true, - content: 'disclaimer.html', - success: function(){ - document.querySelector(".layui-layer-title").style.borderTopRightRadius = "8px"; - document.querySelector(".layui-layer-title").style.borderTopLeftRadius = "8px"; - document.querySelector(".layui-layer").style.borderRadius = "8px"; - } - }) - } + layer.open({ + type: 2, + title : this.lang.website_agreement_statement, + area: ['100%','100%'], + shade: 0.5, + shadeClose : true, + content: 'disclaimer.html', + success: function(){ + document.querySelector(".layui-layer-title").style.borderTopRightRadius = "8px"; + document.querySelector(".layui-layer-title").style.borderTopLeftRadius = "8px"; + document.querySelector(".layui-layer").style.borderRadius = "8px"; + } + }) }, // 分享取件码 getCodeFileCode : function(file){ - if (window.layer) { - layer.closeAll(function () { - layer.open({ - type: 1, - closeBtn: 0, - fixed: true, - maxmin: false, - shadeClose: true, - area: ['350px', '380px'], - title: "分享取件码", - success: function (layero, index) { - document.querySelector(".layui-layer-title").style.borderTopRightRadius = "8px"; - document.querySelector(".layui-layer-title").style.borderTopLeftRadius = "8px"; - document.querySelector(".layui-layer").style.borderRadius = "8px"; - if(window.tlrtcfile.getQrCode){ - tlrtcfile.getQrCode("tl-rtc-file-code-share-image", window.location.href + "#c="+file.codeId) - } - }, - content: ` -
-
${file.codeId}
-
-
- ` - }) + let that = this; + layer.closeAll(function () { + layer.open({ + type: 1, + closeBtn: 0, + fixed: true, + maxmin: false, + shadeClose: true, + area: ['350px', '380px'], + title: that.lang.share_pickup_code + "("+that.lang.expires_one_day+")", + success: function (layero, index) { + document.querySelector(".layui-layer-title").style.borderTopRightRadius = "8px"; + document.querySelector(".layui-layer-title").style.borderTopLeftRadius = "8px"; + document.querySelector(".layui-layer").style.borderRadius = "8px"; + if(window.tlrtcfile.getQrCode){ + tlrtcfile.getQrCode("tl-rtc-file-code-share-image", window.location.href + "#c="+file.codeId) + } + }, + content: ` +
+
${file.codeId}
+
+
+ ` }) - } - this.addUserLogs("打开分享取件码窗口") + }) + this.addUserLogs(this.lang.open_share_pickup_code) }, // 暂存取件码文件 prepareCodeFile: function (recoder) { @@ -267,7 +293,7 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { }); if(filterFile.length === 0){ - this.addUserLogs("加载文件失败,文件资源不存在"); + this.addUserLogs(this.lang.file_not_exist); return } @@ -275,7 +301,7 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { if (file.size > this.uploadCodeFileMaxSize) { if(window.layer){ - layer.msg(`最大只能暂存 ${this.uploadCodeFileMaxSize / 1024 / 1024}M的文件`); + layer.msg(`${this.lang.max_saved} ${this.uploadCodeFileMaxSize / 1024 / 1024} ${this.lang.mb_file}`); } return } @@ -300,52 +326,46 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { getCodeFile: function () { let that = this; if (!this.switchData.openGetCodeFile) { - if (window.layer) { - layer.msg("当前功能已暂时关闭,有问题可以加群交流") - } - this.addUserLogs("当前功能已暂时关闭,有问题可以加群交流") + layer.msg(this.lang.feature_close) + this.addUserLogs(this.lang.feature_close) return } - if (window.layer) { - layer.prompt({ - formType: 0, - title: '请输入取件码', - value: this.codeId, - }, function (value, index, elem) { - if(value.length < 30 || tlrtcfile.containSymbol(value) || tlrtcfile.containChinese(value)){ - layer.msg("请输入正确的取件码") - return - } + layer.prompt({ + formType: 0, + title: this.lang.please_enter_code, + value: this.codeId, + }, function (value, index, elem) { + if(value.length < 30 || tlrtcfile.containSymbol(value) || tlrtcfile.containChinese(value)){ + layer.msg(that.lang.please_enter_right_code) + return + } - that.codeId = value; + that.codeId = value; - that.socket.emit('getCodeFile', { - room: that.roomId, - from: that.socketId, - code: that.codeId, - }); - - layer.close(index); - that.addUserLogs("通过取件码获取文件, 取件码=" + value); + that.socket.emit('getCodeFile', { + room: that.roomId, + from: that.socketId, + code: that.codeId, }); - } + + layer.close(index); + that.addUserLogs(that.lang.get_pickup_file + "," + value); + }); }, //点击搜索暂存文件面板 clickCodeFile: function () { this.showCodeFile = !this.showCodeFile; if (this.showCodeFile) { this.codeFileMaskHeightNum = 20; - this.addUserLogs("展开暂存文件面板"); + this.addUserLogs(this.lang.expand_temporary); } else { this.codeFileMaskHeightNum = 150; - this.addUserLogs("收起暂存文件面板"); + this.addUserLogs(this.lang.collapse_temporary); } }, // 单独发送文件给用户 sendFileToSingle: function(recoder){ - if(window.layer){ - layer.msg(`单独发送给用户 ${recoder.id}`) - } + layer.msg(`${this.lang.send_to_user_separately} ${recoder.id}`) this.isSendFileToSingleSocket = true; @@ -355,78 +375,88 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { startChatRoomSingle: function(remote){ this.chatRoomSingleSocketId = remote.id; let that = this; - if (window.layer) { - let options = { - type: 1, - fixed: false, - maxmin: false, - area: ['600px', '600px'], - title: `私聊【${remote.nickName}】-【${remote.id}】`, - success: function (layero, index) { - if (window.layedit) { - that.txtEditId = layedit.build('chating_room_single_value', { - tool: ['strong', 'italic', 'underline', 'del', '|', 'left', 'center', 'right'], - height: 120 - }); - } - that.chatingRoomSingleTpl(); - }, - cancel: function (index, layero) { - this.chatRoomSingleSocketId = ""; - }, - content: ` -
-
- -
-
- - -
- ` - } - if (this.isMobile) { - delete options.area - } - layer.closeAll(function () { - let index = layer.open(options) - if (that.isMobile) { - layer.full(index) + let options = { + type: 1, + fixed: false, + maxmin: false, + shadeClose : true, + area: ['600px', '600px'], + title: `${this.lang.private_chat}【${remote.nickName}】-【${remote.id}】`, + success: function (layero, index) { + if (window.layedit) { + that.txtEditId = layedit.build('chating_room_single_value', { + tool: ['strong', 'italic', 'underline', 'del', '|', 'left', 'center', 'right'], + height: 120 + }); } - }) + that.chatingRoomSingleTpl(); + + if(window.tlrtcfile.chatKeydown){ + let textareaIframe = document.getElementsByTagName("iframe"); + if(textareaIframe && textareaIframe.length === 1){ + tlrtcfile.chatKeydown( + document.getElementsByTagName("iframe")[0].contentDocument.body, + sendChatingRoomSingle + ) + } + } + }, + cancel: function (index, layero) { + this.chatRoomSingleSocketId = ""; + }, + content: ` +
+
+ +
+
+ + shift+enter ${this.lang.enter_send} + +
+ ` } - this.addUserLogs("打开私聊面板") + if (this.isMobile) { + delete options.area + } + layer.closeAll(function () { + let index = layer.open(options) + if (that.isMobile) { + layer.full(index) + } + }) + this.addUserLogs(this.lang.open_private_chat) }, // 私聊渲染 chatingRoomSingleTpl: function () { @@ -469,36 +499,28 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { // 私聊发言 sendChatingRoomSingle: function () { if (!this.isJoined) { - if (window.layer) { - layer.msg("请先加入房间,再发送内容") - } - this.addUserLogs("请先加入房间,再发送内容"); + layer.msg(this.lang.please_join_then_send) + this.addUserLogs(this.lang.please_join_then_send); return } if (!this.hasManInRoom) { - if (window.layer) { - layer.msg("房间内至少需要两个人才能发送内容") - } - this.addUserLogs("房间内至少需要两个人才能发送内容"); + layer.msg(this.lang.room_least_two_can_send_content) + this.addUserLogs(this.lang.room_least_two_can_send_content); return } let realContent = layedit.getContent(this.txtEditId) if (realContent.length <= 0) { - if (window.layer) { - layer.msg("请输入文本内容") - } - this.addUserLogs("请输入文本内容"); + layer.msg(this.lang.please_enter_content) + this.addUserLogs(this.lang.please_enter_content); return } if (realContent.length > 10000) { - if (window.layer) { - layer.msg("文字内容过长,长度最多1w单词!") - } - this.addUserLogs("文字内容过长,长度最多1w单词"); + layer.msg(this.lang.content_max_10000) + this.addUserLogs(this.lang.content_max_10000); return } this.socket.emit('chatingRoom', { - content: encodeURIComponent(realContent), + content: tlrtcfile.escapeStr(realContent), room: this.roomId, from: this.socketId, to : this.chatRoomSingleSocketId, @@ -525,16 +547,45 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { } this.chatingRoomSingleTpl(); - layer.msg("文本内容发送完毕") - this.addUserLogs("文本内容发送完毕"); + layer.msg(this.lang.text_send_done) + this.addUserLogs(this.lang.text_send_done); layedit.setContent(this.txtEditId, "", false) }, // 右上角弹窗 - startPopUpMsg : function(data) { + startPopUpMsg : async function() { + let that = this; + let data = this.popUpList.shift(); + let lengthLevel = {//渐进式弹悬浮时间 + 2 : 1800, // 队列只有两个弹窗排队时, 弹窗悬停时间1800ms + 5 : 1600, + 8 : 1300, + 10 : 900, + 20 : 700 + }; + //轮训是否有弹窗排队中 + if(!data){ + await new Promise(resolve=>{ + setTimeout(async ()=>{ + await this.startPopUpMsg() + resolve() + }, 1000); + }) + return + } + + let levelTime = 1800; + for(let len in lengthLevel){ + if(len > this.popUpList.length){ + levelTime = lengthLevel[len] + break; + } + } + let msgDom = document.createElement('div'); - msgDom.className = 'tl-rtc-file-notification'; - msgDom.innerHTML = ` + msgDom.setAttribute("class","tl-rtc-file-notification") + msgDom.style.opacity = 0; + msgDom.innerHTML = `
@@ -542,27 +593,22 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => {
${data.message}
`; - let msgDomContainer = document.getElementById('notificationContainer'); + msgDomContainer.style.right = "-320px"; msgDomContainer.prepend(msgDom); - msgDom.style.opacity = '1'; - this.popUpMsgDom.unshift(msgDom); - - //如果当前弹出的弹窗超过限制,移除一个,移除的时候注意下动画过渡 - if (this.popUpMsgDom.length > 2) { - let oldMsgDom = this.popUpMsgDom.pop(); - oldMsgDom.style.opacity = '0'; - } - - // 添加自动消失效果,3秒后自动移除通知 setTimeout(() => { - msgDom.style.opacity = '0'; + msgDomContainer.style.right = "10px"; + msgDom.style.opacity = 1; setTimeout(() => { - msgDomContainer.removeChild(msgDom); - this.popUpMsgDom.splice(this.popUpMsgDom.indexOf(msgDom), 1); - }, 500); - }, 1500); + msgDomContainer.style.right = "-320px"; + msgDom.style.opacity = 0; + setTimeout(() => { + msgDomContainer.removeChild(msgDom); + that.startPopUpMsg(); + }, 450); + }, levelTime); + }, 450); }, // 预览发送文件 previewSendFile: async function (index) { @@ -571,7 +617,7 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { }); if(filterFile.length === 0){ - this.addUserLogs("预览文件 【", file.name, "】失败,文件资源不存在"); + this.addUserLogs(this.lang.preview_file + "【", file.name, "】"+ this.lang.failed_find_file); return } await this.previewFile(filterFile[0]) @@ -583,15 +629,13 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { }); if(filterFile.length === 0){ - this.addUserLogs("预览文件 【", file.name, "】失败,文件资源不存在"); + this.addUserLogs(this.lang.preview_file + "【", file.name, "】"+ this.lang.failed_find_file); return } let fileRecorde = filterFile[0]; if (fileRecorde.size > this.previewFileMaxSize) { - if(window.layer){ - layer.msg(`最大只能预览 ${this.previewFileMaxSize / 1024 / 1024}M的文件`); - } + layer.msg(`${this.lang.max_previewed} ${this.previewFileMaxSize / 1024 / 1024} ${mb_file}`); return } @@ -681,10 +725,10 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { } }) } else{ - layer.msg("暂不支持预览此格式"); + layer.msg(this.lang.preview_not_supported); } }catch(e){ - layer.msg("暂不支持预览此格式"); + layer.msg(this.lang.preview_not_supported); } }, // 删除待发送文件 @@ -709,7 +753,7 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { return item.index !== fileindex; }) - layer.msg(`已取消发送【${filename}】`); + layer.msg(`${that.lang.send_cancel}【${filename}】`); }, 600); } }, @@ -721,117 +765,118 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { }, // 打开公告 clickNotice: function(){ - if (window.layer) { - let noticeMsgList = this.switchData.noticeMsgList || [{ - msg : "暂无公告" - }] - let content = ""; - noticeMsgList.forEach(item=>{ - content += `
${item.msg}
`; - }) - layer.open({ - title: '网站公告', - content: content - }); - } + let noticeMsgList = this.switchData.noticeMsgList || [{ + msg : this.lang.no_notice + }] + let content = ""; + noticeMsgList.forEach(item=>{ + content += `
${item.msg}
`; + }) + layer.open({ + title: this.lang.notice, + content: content, + btn : this.lang.confirm, + shadeClose : true + }); }, // 打开ai窗口 openaiChat: function () { if (!this.switchData.openAiChat) { - if (window.layer) { - layer.msg("当前功能已暂时关闭,有问题可以加群交流") - } - this.addUserLogs("当前功能已暂时关闭,有问题可以加群交流") + layer.msg(this.lang.feature_close) + this.addUserLogs(this.lang.feature_close) return } if (!this.isJoined) { - if (window.layer) { - layer.msg("请先加入房间,才能和AI聊天") - } - this.addUserLogs("请先加入房间,才能和AI聊天") + layer.msg(this.lang.please_join_then_chat_with_ai) + this.addUserLogs(this.lang.please_join_then_chat_with_ai) return } let that = this; - if (window.layer) { - let options = { - type: 1, - fixed: false, //不固定 - maxmin: false, - area: ['600px', '600px'], - title: "人工智能对话", - success: function (layero, index) { - document.querySelector(".layui-layer-title").style.borderTopRightRadius = "15px" - document.querySelector(".layui-layer-title").style.borderTopLeftRadius = "15px" - document.querySelector(".layui-layer").style.borderRadius = "15px" - that.openaiChatTpl(); - }, - content: ` -
-
- -
-
- - -
- ` - } - if (this.isMobile) { - delete options.area - } - layer.closeAll(function () { - let index = layer.open(options) - if (that.isMobile) { - layer.full(index) - } - }) - this.addUserLogs("打开了AI聊天窗口") + {{# }); }} + + {{# if(d.isAiAnswering) { }} +
+ img +
+
+ AI: - + ${this.lang.time}: {{d.time}} +
+
{{d.aiAnsweringTxt}}
+
+
+ {{# } }} + +
+ +
+ + shift+enter ${this.lang.enter_send} + +
+ ` } + if (this.isMobile) { + delete options.area + } + layer.closeAll(function () { + let index = layer.open(options) + if (that.isMobile) { + layer.full(index) + } + }) + this.addUserLogs(this.lang.open_ai_chat) }, // ai窗口渲染 openaiChatTpl: function (callback) { @@ -871,27 +916,21 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { // 发送ai问题 sendOpenaiChat: function () { if (this.isAiAnswering) { - if (window.layer) { - layer.msg("AI正在回答你的问题中,请稍后再提问") - } - this.addUserLogs("AI正在回答你的问题中,请稍后再提问") + layer.msg(this.lang.ai_answering) + this.addUserLogs(this.lang.ai_answering) return } let value = document.querySelector("#openaiChat_value").value; if (value === '' || value === undefined) { - if (window.layer) { - layer.msg("请先填写内容哦") - } - this.addUserLogs("请先填写内容哦") + layer.msg(this.lang.please_fill_content) + this.addUserLogs(this.lang.please_fill_content) return } if (value.length > 1000) { - if (window.layer) { - layer.msg("内容太长啦,不能超过1000个字") - } - this.addUserLogs("内容太长啦,不能超过1000个字") + layer.msg(this.lang.content_max_1000) + this.addUserLogs(this.lang.content_max_1000) return } @@ -949,408 +988,313 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { this.openaiChatTpl() - this.addUserLogs("我对AI说 : " + value); + this.addUserLogs(this.lang.i_said_to_ai + value); document.querySelector("#openaiChat_value").value = '' }, // 创建/加入密码房间 startPassword: function () { if (!this.switchData.openPasswordRoom) { - if (window.layer) { - layer.msg("当前功能已暂时关闭,有问题可以加群交流") - } - this.addUserLogs("当前功能已暂时关闭,有问题可以加群交流") + layer.msg(this.lang.feature_close) + this.addUserLogs(this.lang.feature_close) return } if (!this.isPasswordRoom) { if (this.isJoined) { - if (window.layer) { - layer.msg("请先退出房间后,再进入密码房间") - } - this.addUserLogs("请先退出房间后,再进入密码房间") + layer.msg(this.lang.please_exit_then_join_password_room) + this.addUserLogs(this.lang.please_exit_then_join_password_room) return } let that = this; - if (window.layer) { - layer.prompt({ - formType: 0, - title: '请输入密码房间号' - }, function (value, index, elem) { - that.roomId = value; - layer.close(index); - that.isPasswordRoom = !that.isPasswordRoom; + layer.prompt({ + formType: 0, + title: this.lang.please_enter_password + }, function (value, index, elem) { + that.roomId = value; + layer.close(index); + that.isPasswordRoom = !that.isPasswordRoom; - layer.prompt({ - formType: 1, - title: '请输入密码' - }, function (value, index, elem) { - that.createPasswordRoom(value); - layer.close(index); - that.addUserLogs("进入密码房间,房间号:" + that.roomId + ",密码:" + value); - }); + layer.prompt({ + formType: 1, + title: this.lang.please_enter_password + }, function (value, index, elem) { + that.createPasswordRoom(value); + layer.close(index); + that.addUserLogs(this.lang.enter_password_room + that.roomId + `,${this.lang.password}:` + value); }); - } + }); } }, // 打开设置 setting: function () { let that = this; - if (window.layer) { - let options = { - type: 1, - fixed: false, - maxmin: false, - shadeClose: true, - area: ['300px', '350px'], - title: "功能设置", - success: function (layero, index) { - document.querySelector(".layui-layer-title").style.borderTopRightRadius = "15px" - document.querySelector(".layui-layer-title").style.borderTopLeftRadius = "15px" - document.querySelector(".layui-layer").style.borderRadius = "15px" - document.querySelector(".layui-layer-content").style.borderRadius = "15px" - window.form.render() - }, - content: ` -
- + let options = { + type: 1, + fixed: false, + maxmin: false, + shadeClose: true, + area: ['300px', '350px'], + title: this.lang.setting, + success: function (layero, index) { + document.querySelector(".layui-layer-title").style.borderTopRightRadius = "15px" + document.querySelector(".layui-layer-title").style.borderTopLeftRadius = "15px" + document.querySelector(".layui-layer").style.borderRadius = "15px" + document.querySelector(".layui-layer-content").style.borderRadius = "15px" + window.form.render() + }, + content: ` + + ` } - this.addUserLogs("打开设置窗口") + layer.closeAll(function () { + layer.open(options) + }) + this.addUserLogs(this.lang.open_setting) }, // 打开中继设置面板 relaySetting: function () { - let that = this; - if (window.layer) { - let options = { - type: 1, - fixed: false, - maxmin: false, - shadeClose: true, - area: ['300px', '350px'], - title: "中继设置", - success: function (layero, index) { - let active = null; - document.querySelector(".layui-layer-title").style.borderTopRightRadius = "15px" - document.querySelector(".layui-layer-title").style.borderTopLeftRadius = "15px" - document.querySelector(".layui-layer").style.borderRadius = "15px" - document.querySelector(".layui-layer-content").style.borderRadius = "15px" - }, - content: ` -
-
-
-

中继服务器当前已 ${notUseRelay ? '“禁用”' : '“启用”'}

-

启用中继服务器可以保证在复杂的p2p网络环境下,提供保底的数据中转传输,如果禁用,则是强制走p2p(可在设置中进行p2p检测),可能会出现发送失败!

-
-
- - -
+ let options = { + type: 1, + fixed: false, + maxmin: false, + shadeClose: true, + area: ['300px', '350px'], + title: this.lang.relay_setting, + success: function (layero, index) { + let active = null; + document.querySelector(".layui-layer-title").style.borderTopRightRadius = "15px" + document.querySelector(".layui-layer-title").style.borderTopLeftRadius = "15px" + document.querySelector(".layui-layer").style.borderRadius = "15px" + document.querySelector(".layui-layer-content").style.borderRadius = "15px" + }, + content: ` +
+
+
+

${this.lang.relay_server_current} ${useTurn ? this.lang.on : this.lang.off}

+

${this.lang.relay_server_current_detail}

+
+
+ +
- ` - } - layer.closeAll(function () { - layer.open(options) - }) +
+ ` } - this.addUserLogs("打开中继设置窗口") + layer.closeAll(function () { + layer.open(options) + }) + this.addUserLogs(this.lang.open_relay_setting) }, // 创建/加入音视频房间 startVideoShare: function () { if (!this.switchData.openVideoShare) { - if (window.layer) { - layer.msg("当前功能已暂时关闭,有问题可以加群交流") - } - this.addUserLogs("当前功能已暂时关闭,有问题可以加群交流") + layer.msg(this.lang.feature_close) + this.addUserLogs(this.lang.feature_close) return } if (this.isScreenShare) { - if (window.layer) { - layer.msg("当前正在屏幕共享中,退出后再试") - } - this.addUserLogs("当前正在屏幕共享中,退出后再试") + layer.msg(this.lang.in_sharing_screen) + this.addUserLogs(this.lang.in_sharing_screen) return } if (this.isLiveShare) { - if (window.layer) { - layer.msg("当前正在直播中,退出后再试") - } - this.addUserLogs("当前正在直播中,退出后再试") + layer.msg(this.lang.in_living) + this.addUserLogs(this.lang.in_living) return } if (this.isVideoShare) { window.Bus.$emit("stopVideoShare") this.isVideoShare = !this.isVideoShare; - this.addUserLogs("结束音视频通话"); + this.addUserLogs(this.lang.end_video_call); return } if (this.isJoined) { - if (window.layer) { - layer.msg("请先退出房间后,再发起音视频通话") - } - this.addUserLogs("请先退出房间后,再发起音视频通话") + layer.msg(this.lang.please_exit_then_join_video) + this.addUserLogs(this.lang.please_exit_then_join_video) return } let that = this; - if (window.layer) { - if(that.isShareJoin){ //分享进入 + if(that.isShareJoin){ //分享进入 + that.createMediaRoom("video"); + that.socket.emit('message', { + emitType: "startVideoShare", + room: that.roomId, + to : that.socketId + }); + that.clickMediaVideo(); + that.isVideoShare = !that.isVideoShare; + that.addUserLogs(this.lang.start_video_call); + }else{ + layer.prompt({ + formType: 1, + title: this.lang.please_enter_video_call_room_num + }, function (value, index, elem) { + that.roomId = value; that.createMediaRoom("video"); + layer.close(index) + that.socket.emit('message', { emitType: "startVideoShare", room: that.roomId, + to : that.socketId }); that.clickMediaVideo(); that.isVideoShare = !that.isVideoShare; - that.addUserLogs("开始音视频通话"); - }else{ - layer.prompt({ - formType: 1, - title: '请输入音视频通话房间号' - }, function (value, index, elem) { - that.roomId = value; - that.createMediaRoom("video"); - layer.close(index) - - that.socket.emit('message', { - emitType: "startVideoShare", - room: that.roomId, - }); - that.clickMediaVideo(); - that.isVideoShare = !that.isVideoShare; - that.addUserLogs("开始音视频通话"); - }); - } + that.addUserLogs(this.lang.start_video_call); + }); } }, // 创建/加入屏幕共享房间 startScreenShare: function () { if (!this.switchData.openScreenShare) { - if (window.layer) { - layer.msg("当前功能已暂时关闭,有问题可以加群交流") - } - this.addUserLogs("当前功能已暂时关闭,有问题可以加群交流") + layer.msg(this.lang.feature_close) + this.addUserLogs(this.lang.feature_close) return } if (this.isVideoShare) { - if (window.layer) { - layer.msg("当前正在音视频通话中,退出后再试") - } - this.addUserLogs("当前正在音视频通话中,退出后再试") + layer.msg(this.lang.in_videoing) + this.addUserLogs(this.lang.in_videoing) return } if (this.isLiveShare) { - if (window.layer) { - layer.msg("当前正在直播中,退出后再试") - } - this.addUserLogs("当前正在直播中,退出后再试") + layer.msg(this.lang.in_living) + this.addUserLogs(this.lang.in_living) return } if (this.isScreenShare) { window.Bus.$emit("stopScreenShare") this.isScreenShare = !this.isScreenShare; - this.addUserLogs("结束远程屏幕共享"); + this.addUserLogs(this.lang.end_screen_sharing); return } if (this.isJoined) { - if (window.layer) { - layer.msg("请先退出房间后,再发起屏幕共享") - } - this.addUserLogs("请先退出房间后,再发起屏幕共享") + layer.msg(this.lang.please_exit_then_join_screen) + this.addUserLogs(this.lang.please_exit_then_join_screen) return } let that = this; - if (window.layer) { - if(that.isShareJoin){ //分享进入 + if(that.isShareJoin){ //分享进入 + that.createMediaRoom("screen"); + that.socket.emit('message', { + emitType: "startScreenShare", + room: that.roomId, + to : that.socketId + }); + that.clickMediaScreen(); + that.isScreenShare = !that.isScreenShare; + that.addUserLogs(this.lang.start_screen_sharing); + }else{ + layer.prompt({ + formType: 1, + title: this.lang.please_enter_screen_sharing_room_num, + }, function (value, index, elem) { + that.roomId = value; that.createMediaRoom("screen"); + layer.close(index) + that.socket.emit('message', { emitType: "startScreenShare", room: that.roomId, + to : that.socketId }); that.clickMediaScreen(); that.isScreenShare = !that.isScreenShare; - that.addUserLogs("开始远程屏幕共享"); - }else{ - layer.prompt({ - formType: 1, - title: '请输入屏幕共享房间号', - }, function (value, index, elem) { - that.roomId = value; - that.createMediaRoom("screen"); - layer.close(index) - - that.socket.emit('message', { - emitType: "startScreenShare", - room: that.roomId, - }); - that.clickMediaScreen(); - that.isScreenShare = !that.isScreenShare; - that.addUserLogs("开始远程屏幕共享"); - }); - } + that.addUserLogs(this.lang.this.lang.start_screen_sharing); + }); } }, // 创建/加入直播房间 startLiveShare: function () { if (!this.switchData.openLiveShare) { - if (window.layer) { - layer.msg("当前功能已暂时关闭,有问题可以加群交流") - } - this.addUserLogs("当前功能已暂时关闭,有问题可以加群交流") + layer.msg(this.lang.feature_close) + this.addUserLogs(this.lang.feature_close) return } if (this.isVideoShare) { - if (window.layer) { - layer.msg("当前正在音视频通话中,退出后再试") - } - this.addUserLogs("当前正在音视频通话中,退出后再试") + layer.msg(this.lang.in_videoing) + this.addUserLogs(this.lang.in_videoing) return } if (this.isScreenShare) { - if (window.layer) { - layer.msg("当前正在屏幕共享中,退出后再试") - } - this.addUserLogs("当前正在屏幕共享中,退出后再试") + layer.msg(this.lang.in_sharing_screen) + this.addUserLogs(this.lang.in_sharing_screen) return } if (this.isLiveShare) { window.Bus.$emit("stopLiveShare") this.isLiveShare = !this.isLiveShare; - this.addUserLogs("结束直播"); + this.addUserLogs(this.lang.end_live); return } - if (this.isJoined) { - if (window.layer) { - layer.msg("请先退出房间后,再进入直播") - } - this.addUserLogs("请先退出房间后,再进入直播") + layer.msg(this.lang.please_exit_then_join_live) + this.addUserLogs(this.lang.please_exit_then_join_live) return } let that = this; @@ -1360,14 +1304,15 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { that.socket.emit('message', { emitType: "startLiveShare", room: that.roomId, + to : that.socketId }); that.clickMediaLive(); that.isLiveShare = !that.isLiveShare; - that.addUserLogs("进入直播"); + that.addUserLogs(this.lang.start_live); }else{ layer.prompt({ formType: 1, - title: '请输入直播房间号', + title: this.lang.please_enter_live_room_num, }, function (value, index, elem) { that.roomId = value; that.createMediaRoom("live"); @@ -1376,59 +1321,89 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { that.socket.emit('message', { emitType: "startLiveShare", room: that.roomId, + to : that.socketId }); that.clickMediaLive(); that.isLiveShare = !that.isLiveShare; - that.addUserLogs("进入直播"); + that.addUserLogs(this.lang.start_live); }); } } }, - // 创建/加入远程画笔房间 - startRemoteDraw : function(){ + // 打开画笔 + openRemoteDraw : function(){ if (!this.switchData.openRemoteDraw) { - if (window.layer) { - layer.msg("当前功能已暂时关闭,有问题可以加群交流") - } - this.addUserLogs("当前功能已暂时关闭,有问题可以加群交流") + layer.msg(this.lang.feature_close) + this.addUserLogs(this.lang.feature_close) return } + + if (!this.isJoined) { + layer.msg(this.lang.please_join_then_draw) + this.addUserLogs(this.lang.please_join_then_draw) + return + } + + // 触发draw.js中的方法 + window.Bus.$emit("openDraw", { + openCallback: () => { + this.socket.emit('message', { + emitType: "startRemoteDraw", + room: this.roomId, + to: this.socketId + }); + }, + closeCallback: (drawCount) => { + this.socket.emit('message', { + emitType: "stopRemoteDraw", + room: this.roomId, + to: this.socketId, + drawCount : drawCount + }); + }, + localDrawCallback : (data) => { + Object.entries(this.remoteMap).forEach(([id, remote]) => { + if(remote && remote.sendDataChannel){ + const sendDataChannel = remote.sendDataChannel; + if (!sendDataChannel || sendDataChannel.readyState !== 'open') { + this.addSysLogs("sendDataChannel error in draw") + return; + } + sendDataChannel.send(JSON.stringify(data)); + } + }); + } + }) }, // 开始本地录制 - startScreen: function () { + openLocalScreen: function () { + let that = this; + if (!this.switchData.openScreen) { - if (window.layer) { - layer.msg("当前功能已暂时关闭,有问题可以加群交流") - } - this.addUserLogs("当前功能已暂时关闭,有问题可以加群交流") + layer.msg(this.lang.feature_close) + this.addUserLogs(this.lang.feature_close) return } + if (this.isMobile) { - if (window.layer) { - layer.msg("移动端暂不支持屏幕录制") - } - this.addUserLogs("移动端暂不支持屏幕录制") + layer.msg(this.lang.mobile_not_support_recording) + this.addUserLogs(this.lang.mobile_not_support_recording) return } - if (!this.isScreen) { - let that = this; - if (window.layer) { - layer.confirm("是否进行本地屏幕录制", (index) => { - window.Bus.$emit("startScreen") - that.socket.emit('message', { - emitType: "startScreen", - room: this.roomId, - }); - that.addUserLogs("开始本地屏幕录制"); - }, (index) => { - this.isScreen = !this.isScreen; - layer.close(index) - }) - } - } else { - window.Bus.$emit("stopScreen", (res) => { + + // 触发screen.js中的方法 + window.Bus.$emit("openLocalScreen", { + openCallback : () => { + that.socket.emit('message', { + emitType: "startScreen", + room: this.roomId, + to : this.socketId + }); + that.addUserLogs(this.lang.start_local_screen_recording); + }, + closeCallback : (res) => { this.receiveFileRecoderList.push({ - id: "网页录屏", + id: this.lang.web_screen_recording, nickName : this.nickName, href: res.src, style: 'color: #ff5722;text-decoration: underline;', @@ -1442,72 +1417,74 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { }) this.socket.emit('message', { emitType: "stopScreen", + to : this.socketId, room: this.roomId, size: res.size, cost: res.times }); - this.addUserLogs("结束本地屏幕录制"); - }) - } - this.isScreen = !this.isScreen; + this.addUserLogs(this.lang.end_local_screen_recording); + } + }); }, // 打开公共聊天室 openChatingComm: function () { if (!this.switchData.openCommRoom) { - if (window.layer) { - layer.msg("当前功能已暂时关闭,有问题可以加群交流") - } - this.addUserLogs("当前功能已暂时关闭,有问题可以加群交流") + layer.msg(this.lang.feature_close) + this.addUserLogs(this.lang.feature_close) return } let that = this; - if (window.layer) { - let options = { - type: 1, - fixed: false, //不固定 - maxmin: false, - area: ['600px', '600px'], - title: "公共聊天频道", - success: function (layero, index) { - let lIndex = layer.load(1); - setTimeout(() => { - layer.close(lIndex) - that.chatingCommTpl(); - }, 300); - }, - content: ` -
-
- -
-
- - -
- ` - } - if (this.isMobile) { - delete options.area - } - layer.closeAll(function () { - let index = layer.open(options) - if (that.isMobile) { - layer.full(index) + let options = { + type: 1, + fixed: false, //不固定 + maxmin: false, + shadeClose : true, + area: ['600px', '600px'], + title: this.lang.public_chat_channel, + success: function (layero, index) { + let lIndex = layer.load(1); + setTimeout(() => { + layer.close(lIndex) + that.chatingCommTpl(); + }, 300); + + if(window.tlrtcfile.chatKeydown){ + tlrtcfile.chatKeydown(document.getElementById("chating_comm_value"), sendChatingComm) } - }) + }, + content: ` +
+
+ +
+
+ + shift+enter ${this.lang.enter_send} + +
+ ` } - this.addUserLogs("打开公共聊天面板") + if (this.isMobile) { + delete options.area + } + layer.closeAll(function () { + let index = layer.open(options) + if (that.isMobile) { + layer.full(index) + } + }) + this.addUserLogs(this.lang.open_public_chat_panel) }, // 公共聊天室渲染数据 chatingCommTpl: function () { @@ -1555,34 +1532,28 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { // 发送公共聊天室消息 sendChatingComm: function () { if (!this.isJoined) { - if (window.layer) { - layer.msg("请先加入房间,才能发言哦") - } - this.addUserLogs("请先加入房间,才能发言哦") + layer.msg(this.lang.please_join_then_send) + this.addUserLogs(this.lang.please_join_then_send) return } let content = document.querySelector("#chating_comm_value").value; if (content === '' || content === undefined) { - if (window.layer) { - layer.msg("请先填写内容哦") - } - this.addUserLogs("请先填写内容哦") + layer.msg(this.lang.please_fill_content) + this.addUserLogs(this.lang.please_fill_content) return } if (content.length > 1000) { - if (window.layer) { - layer.msg("内容太长啦,不能超过1000个字") - } - this.addUserLogs("内容太长啦,不能超过1000个字") + layer.msg(this.lang.content_max_1000) + this.addUserLogs(this.lang.content_max_1000) return } this.socket.emit('chatingComm', { - msg: encodeURIComponent(content), + msg: tlrtcfile.escapeStr(content), room: this.roomId, socketId: this.socketId, }); - this.addUserLogs("公共频道发言成功"); + this.addUserLogs(this.lang.public_channel_send_done); document.querySelector("#chating_comm_value").value = '' }, @@ -1594,8 +1565,9 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { type: 1, fixed: false, //不固定 maxmin: false, + shadeClose : true, area: ['600px', '600px'], - title: `【${this.roomId}】` + "聊天频道", + title: `【${this.roomId}】` + this.lang.chat_channel, success: function (layero, index) { if (window.layer && window.layui && window.layedit) { that.txtEditId = layedit.build('chating_room_value', { @@ -1603,7 +1575,18 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { height: 120 }); } + that.chatingRoomTpl(); + + if(window.tlrtcfile.chatKeydown){ + let textareaIframe = document.getElementsByTagName("iframe"); + if(textareaIframe && textareaIframe.length === 1){ + tlrtcfile.chatKeydown( + document.getElementsByTagName("iframe")[0].contentDocument.body, + sendChatingRoom + ) + } + } }, content: `
@@ -1615,9 +1598,9 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { img
- 用户: {{info.nickName}} - + ${this.lang.user}: {{info.nickName}} - id: {{info.socketId}} - - 时间: {{info.timeAgo}} + ${this.lang.time}: {{info.timeAgo}}
{{- info.content}} @@ -1628,8 +1611,8 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => {
- 我: {{info.nickName}} - - 时间: {{info.timeAgo}} + ${this.lang.self}: {{info.nickName}} - + ${this.lang.time}: {{info.timeAgo}}
{{- info.content}} @@ -1641,9 +1624,10 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { {{# }); }}
-
- - +
+ + shift+enter ${this.lang.enter_send} +
` } @@ -1657,7 +1641,7 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { } }) } - this.addUserLogs("打开房间聊天面板") + this.addUserLogs(this.lang.open_room_chat_panel) }, // 房间内群聊渲染 chatingRoomTpl: function () { @@ -1693,37 +1677,29 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { // 房间内群聊发言 sendChatingRoom: function () { if (!this.isJoined) { - if (window.layer) { - layer.msg("请先加入房间,再发送内容") - } - this.addUserLogs("请先加入房间,再发送内容"); + layer.msg(this.lang.please_join_then_send) + this.addUserLogs(this.lang.please_join_then_send); return } if (!this.hasManInRoom) { - if (window.layer) { - layer.msg("房间内至少需要两个人才能发送内容") - } - this.addUserLogs("房间内至少需要两个人才能发送内容"); + layer.msg(this.lang.room_least_two_can_send_content) + this.addUserLogs(this.lang.room_least_two_can_send_content); return } let realContent = layedit.getContent(this.txtEditId) if (realContent.length <= 0) { - if (window.layer) { - layer.msg("请输入文本内容") - } - this.addUserLogs("请输入文本内容"); + layer.msg(this.lang.please_enter_content) + this.addUserLogs(this.lang.please_enter_content); return } if (realContent.length > 10000) { - if (window.layer) { - layer.msg("文字内容过长,长度最多1w单词!") - } - this.addUserLogs("文字内容过长,长度最多1w单词"); + layer.msg(this.lang.content_max_10000) + this.addUserLogs(this.lang.content_max_10000); return } this.socket.emit('chatingRoom', { - content: encodeURIComponent(realContent), + content: tlrtcfile.escapeStr(realContent), room: this.roomId, from: this.socketId, nickName : this.nickName, @@ -1741,24 +1717,20 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { this.chatingRoomTpl(); - layer.msg("文本内容发送完毕") - this.addUserLogs("文本内容发送完毕"); + layer.msg(this.lang.text_send_done) + this.addUserLogs(this.lang.text_send_done); layedit.setContent(this.txtEditId, "", false) }, // 中继信息提示 useTurnMsg: function () { - if (window.layer) { - layer.msg("当前已启用中继服务器,更多信息请到设置查看") - } - this.addUserLogs("当前已启用中继服务器,更多信息请到设置查看") + layer.msg(this.lang.relay_on) + this.addUserLogs(this.lang.relay_on) }, // 当前网络状态 networkMsg: function () { - if (window.layer) { - layer.msg("当前网络状态为" + (this.network !== 'wifi' ? '移动流量' : this.network)) - } - this.addUserLogs("当前网络状态为" + (this.network !== 'wifi' ? '移动流量' : this.network)) + layer.msg(this.lang.current_network + (this.network !== 'wifi' ? this.lang.mobile_data : this.network)) + this.addUserLogs(this.lang.current_network + (this.network !== 'wifi' ? this.lang.mobile_data : this.network)) }, // 添加弹窗 addPopup: function (msg) { @@ -1769,11 +1741,11 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { }, // 记录系统日志 addSysLogs: function (msg) { - this.addLogs(msg, "【系统日志】: ") + this.addLogs(msg, "【"+this.lang.sys_log+"】: ") }, // 记录用户操作日志 addUserLogs: function (msg) { - this.addLogs(msg, "【操作日志】: ") + this.addLogs(msg, "【"+this.lang.op_log+"】: ") }, // 记录日志 addLogs: function (msg, type) { @@ -1789,88 +1761,88 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { // 清空日志 cleanLogs: function () { this.logs = [] - this.addSysLogs("清空日志") + this.addSysLogs(this.lang.clear_log) }, // 发送建议反馈 sendBugs: function () { - if (window.layer) { - let that = this; - $("#sendBugs").removeClass("layui-anim-rotate") - setTimeout(() => { - $("#sendBugs").addClass("layui-anim-rotate") - }, 50) - setTimeout(() => { - layer.prompt({ - formType: 2, - title: '请描述您需要反馈的问题', - }, function (value, index, elem) { - that.socket.emit('message', { - emitType: "sendBugs", - msg: value, - room: that.roomId, - }); - layer.msg("问题反馈成功,更多问题可以加群交流,将更快解决") - layer.close(index); - that.addUserLogs("问题反馈成功,更多问题可以加群交流,将更快解决 ,问题:" + value); + let that = this; + $("#sendBugs").removeClass("layui-anim-rotate") + setTimeout(() => { + $("#sendBugs").addClass("layui-anim-rotate") + }, 50) + setTimeout(() => { + layer.prompt({ + formType: 2, + title: that.lang.please_describe_your_feedback, + }, function (value, index, elem) { + that.socket.emit('message', { + emitType: "sendBugs", + msg: value, + room: that.roomId, + to: that.socketId }); - }, 500); - } + layer.msg(that.lang.send_bug_info_ok) + layer.close(index); + that.addUserLogs(that.lang.send_bug_info_ok + ", " + value); + }); + }, 500); }, // 随机刷新房间号 refleshRoom: function () { if (!this.isJoined) { this.roomId = parseInt(Math.random() * 100000); this.addPopup({ - title : "刷新房间", - msg : "你刷新了房间号, 当前房间号为 " + this.roomId + title : this.lang.refresh_room, + msg : this.lang.you_refresh_room + this.roomId }); - this.addUserLogs("你刷新了房间号, 当前房间号为 " + this.roomId); + this.addUserLogs(this.lang.you_refresh_room + this.roomId); } }, // 复制分享房间url shareUrl: function () { let that = this; - if (window.layer) { - layer.closeAll(function () { - layer.open({ - type: 1, - closeBtn: 0, - fixed: true, - maxmin: false, - shadeClose: true, - area: ['350px', '380px'], - title: "分享加入房间", - success: function (layero, index) { - let content = window.location.href + "#r="+that.roomId+"&t="+that.roomType; - document.querySelector(".layui-layer-title").style.borderTopRightRadius = "8px"; - document.querySelector(".layui-layer-title").style.borderTopLeftRadius = "8px"; - document.querySelector(".layui-layer").style.borderRadius = "8px"; - if(window.tlrtcfile.getQrCode){ - tlrtcfile.getQrCode("tl-rtc-file-room-share-image", content) - } + layer.closeAll(function () { + layer.open({ + type: 1, + closeBtn: 0, + fixed: true, + maxmin: false, + shadeClose: true, + area: ['350px', '380px'], + title: that.lang.share_join_room, + success: function (layero, index) { + let content = window.tlrtcfile.addUrlHashParams({ + r : that.roomId, + t : that.roomType + }); + document.querySelector(".layui-layer-title").style.borderTopRightRadius = "8px"; + document.querySelector(".layui-layer-title").style.borderTopLeftRadius = "8px"; + document.querySelector(".layui-layer").style.borderRadius = "8px"; + if(window.tlrtcfile.getQrCode){ + tlrtcfile.getQrCode("tl-rtc-file-room-share-image", content) + } - document.querySelector("#shareUrl").setAttribute("data-clipboard-text", content); - let clipboard = new ClipboardJS('#shareUrl'); - clipboard.on('success', function (e) { - e.clearSelection(); - setTimeout(() => { - layer.msg("复制房间链接成功!") - }, 500); - }); - that.addUserLogs("复制房间链接成功"); - }, - content: ` -
-
分享自动加入房间链接已复制 - -
+ document.querySelector("#shareUrl").setAttribute("data-clipboard-text", content); + let clipboard = new ClipboardJS('#shareUrl'); + clipboard.on('success', function (e) { + e.clearSelection(); + setTimeout(() => { + layer.msg(that.lang.copy_room_link) + }, 500); + }); + that.addUserLogs(that.lang.copy_room_link); + }, + content: ` +
+
${that.lang.share_join_room_done} +
-
- ` - }) +
+
+ ` }) - } - this.addUserLogs("打开分享房间窗口") + }) + this.addUserLogs(this.lang.open_share_join_room) }, // 获取分享的取件码文件 handlerGetCodeFile: function () { @@ -1880,22 +1852,20 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { let codeIdArgs = hash.split("c="); if (codeIdArgs && codeIdArgs.length > 1) { this.codeId = (codeIdArgs[1] + "").replace(/\s*/g, "").substring(0, 40); - if (window.layer) { - layer.confirm("是否取件码取件", (index) => { - window.location.hash = ""; - layer.close(index) - that.getCodeFile(); - }, (index) => { - that.codeId = ""; - window.location.hash = ""; - layer.close(index) - }) - } + layer.confirm(this.lang.is_pickup_code, (index) => { + window.location.hash = ""; + layer.close(index) + that.getCodeFile(); + }, (index) => { + that.codeId = ""; + window.location.hash = ""; + layer.close(index) + }) this.addPopup({ - title : "分享取件码文件", - msg : "你通过分享获取取件码文件 " + this.codeId + title : this.lang.share_pickup_code_file, + msg : this.lang.get_pickup_file + this.codeId }); - this.addUserLogs("你通过分享获取取件码文件 " + this.codeId); + this.addUserLogs(this.lang.get_pickup_file + this.codeId); } } }, @@ -1913,7 +1883,7 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { let typeArgs = tlrtcfile.getRequestHashArgs("t") this.roomId = (roomIdArgs + "").replace(/\s*/g, "").substring(0, 15); if (window.layer) { - layer.confirm("进入房间" + this.roomId, (index) => { + layer.confirm(this.lang.join_room + this.roomId, (index) => { window.location.hash = ""; layer.close(index) that.openRoomInput = true; @@ -1936,101 +1906,91 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { }) } this.addPopup({ - title : "分享房间", - msg : "你通过分享加入了房间号为 " + this.roomId + title : this.lang.share_join_room, + msg : this.lang.you_join_room + this.roomId }); - this.addUserLogs("你通过分享加入了房间号为 " + this.roomId); + this.addUserLogs(this.lang.you_join_room + this.roomId); } }, // 赞助面板 coffee: function () { - if (window.layer) { - let options = { - type: 1, - fixed: false, - maxmin: false, - shadeClose: true, - area: ['300px', '350px'], - title: "赞助一下,为爱发电", - success: function (layero, index) { - document.querySelector(".layui-layer-title").style.borderTopRightRadius = "8px"; - document.querySelector(".layui-layer-title").style.borderTopLeftRadius = "8px"; - document.querySelector(".layui-layer").style.borderRadius = "8px"; - }, - content: `img ` - } - layer.closeAll(function () { - layer.open(options) - }) + let options = { + type: 1, + fixed: false, + maxmin: false, + shadeClose: true, + area: ['300px', '350px'], + title: this.lang.donate, + success: function (layero, index) { + document.querySelector(".layui-layer-title").style.borderTopRightRadius = "8px"; + document.querySelector(".layui-layer-title").style.borderTopLeftRadius = "8px"; + document.querySelector(".layui-layer").style.borderRadius = "8px"; + }, + content: `img ` } - this.addUserLogs("打开赞助窗口") + layer.closeAll(function () { + layer.open(options) + }) + this.addUserLogs(this.lang.open_donate) }, //点击下载文件面板 clickReceiveFile: function () { if(this.receiveFileRecoderList.length === 0){ - if(window.layer){ - layer.msg("暂时没有收到文件") - } + layer.msg(this.lang.no_received_file) return } this.showReceiveFile = !this.showReceiveFile; if (this.showReceiveFile) { - this.addUserLogs("展开已接收文件面板"); + this.addUserLogs(this.lang.expand_receive_file); this.receiveFileMaskHeightNum = 20; } else { this.receiveFileMaskHeightNum = 150; - this.addUserLogs("收起已接收文件面板"); + this.addUserLogs(this.lang.collapse_receive_file); } }, //点击已选文件面板 clickChooseFile: function () { if(!this.hasManInRoom && !this.showChooseFile){ - if(window.layer){ - layer.msg("房间内至少需要两个人才能发送文件") - } + layer.msg(this.lang.room_least_two_can_send_content) return } this.showChooseFile = !this.showChooseFile; if (this.showChooseFile) { this.chooseFileMaskHeightNum = 20; - this.addUserLogs("展开已选文件面板"); + this.addUserLogs(this.lang.expand_selected_file); } else { this.chooseFileMaskHeightNum = 150; - this.addUserLogs("收起已选文件面板"); + this.addUserLogs(this.lang.collapse_selected_file); } }, //点击待发送文件面板 clickSendFile: function () { if(!this.hasManInRoom && !this.showSendFile){ - if(window.layer){ - layer.msg("房间内至少需要两个人才能发送文件") - } + layer.msg(this.lang.room_least_two_can_send_content) return } this.showSendFile = !this.showSendFile; if (this.showSendFile) { this.sendFileMaskHeightNum = 20; - this.addUserLogs("展开待发送文件面板"); + this.addUserLogs(this.lang.expand_wait_send_file); } else { this.sendFileMaskHeightNum = 150; - this.addUserLogs("收起待发送文件面板"); + this.addUserLogs(this.lang.collapse_wait_send_file); } }, //点击发送文件历史记录面板 clickSendFileHistory: function () { if(this.sendFileRecoderHistoryList.length === 0){ - if(window.layer){ - layer.msg("暂时没有发送过文件") - } + layer.msg(this.lang.no_send_file) return } this.showSendFileHistory = !this.showSendFileHistory; if (this.showSendFileHistory) { this.sendFileHistoryMaskHeightNum = 20; - this.addUserLogs("展开发送文件记录面板"); + this.addUserLogs(this.lang.expand_send_file_record); } else { this.sendFileHistoryMaskHeightNum = 150; - this.addUserLogs("收起发送文件记录面板"); + this.addUserLogs(this.lang.collapse_send_file_record); } }, //点击查看日志面板 @@ -2038,10 +1998,10 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { this.showLogs = !this.showLogs; this.touchResize(); if (this.showLogs) { - this.addUserLogs("展开日志面板"); + this.addUserLogs(this.lang.expand_log); this.logMaskHeightNum = 0; } else { - this.addUserLogs("收起日志面板"); + this.addUserLogs(this.lang.collapse_log); this.logMaskHeightNum = -150; } }, @@ -2050,7 +2010,7 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { this.showMedia = !this.showMedia; this.touchResize(); if (this.showMedia) { - this.addUserLogs("展开音视频面板"); + this.addUserLogs(this.lang.expand_video); this.mediaVideoMaskHeightNum = 0; if(this.clientWidth < 500){ document.getElementById("iamtsm").style.marginLeft = '0'; @@ -2058,7 +2018,7 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { document.getElementById("iamtsm").style.marginLeft = "50%"; } } else { - this.addUserLogs("收起音视频面板"); + this.addUserLogs(this.lang.collapse_video); this.mediaVideoMaskHeightNum = -150; document.getElementById("iamtsm").style.marginLeft = "0"; } @@ -2068,7 +2028,7 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { this.showMedia = !this.showMedia; this.touchResize(); if (this.showMedia) { - this.addUserLogs("展开屏幕共享面板"); + this.addUserLogs(this.lang.expand_screen_sharing); this.mediaScreenMaskHeightNum = 0; if(this.clientWidth < 500){ document.getElementById("iamtsm").style.marginLeft = "0"; @@ -2076,7 +2036,7 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { document.getElementById("iamtsm").style.marginLeft = "50%"; } } else { - this.addUserLogs("收起屏幕共享面板"); + this.addUserLogs(this.lang.collapse_screen_sharing); this.mediaScreenMaskHeightNum = -150; document.getElementById("iamtsm").style.marginLeft = "0"; } @@ -2086,7 +2046,7 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { this.showMedia = !this.showMedia; this.touchResize(); if (this.showMedia) { - this.addUserLogs("展开直播面板"); + this.addUserLogs(this.lang.expand_live); if(this.clientWidth < 500){ document.getElementById("iamtsm").style.marginLeft = "0"; }else{ @@ -2094,7 +2054,7 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { } this.mediaLiveMaskHeightNum = 0; } else { - this.addUserLogs("收起直播面板"); + this.addUserLogs(this.lang.collapse_live); this.mediaLiveMaskHeightNum = -150; document.getElementById("iamtsm").style.marginLeft = "0"; } @@ -2131,141 +2091,99 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { this.roomId = this.roomId.toString().replace(/\s*/g, "") if (this.roomId === null || this.roomId === undefined || this.roomId === '') { - if (window.layer) { - layer.msg("请先填写房间号") - } else { - alert("请先填写房间号") - } - this.addUserLogs("请先填写房间号"); + layer.msg(this.lang.please_enter_room_num) + this.addUserLogs(this.lang.please_enter_room_num); return; } if (!this.switchData.allowChinese && window.tlrtcfile.containChinese(this.roomId)) { - if (window.layer) { - layer.msg("房间号不允许中文") - } else { - alert("房间号不允许中文") - } - this.addUserLogs("房间号不允许中文"); + layer.msg(this.lang.room_num_no_zh) + this.addUserLogs(this.lang.room_num_no_zh); return; } if (!this.switchData.allowNumber && window.tlrtcfile.containNumber(this.roomId)) { - if (window.layer) { - layer.msg("房间号不允许数字") - } else { - alert("房间号不允许数字") - } - this.addUserLogs("房间号不允许数字"); + layer.msg(this.lang.room_num_no_number) + this.addUserLogs(this.lang.room_num_no_number); return; } if (!this.switchData.allowSymbol && window.tlrtcfile.containSymbol(this.roomId)) { - if (window.layer) { - layer.msg("房间号不允许特殊符号") - } else { - alert("房间号不允许特殊符号") - } - this.addUserLogs("房间号不允许特殊符号"); + layer.msg(this.lang.room_num_no_special_symbols) + this.addUserLogs(this.lang.room_num_no_special_symbols); return; } if (this.chooseFileList.length > 0) { - if (window.layer) { - layer.msg("请先加入房间再选文件") - } else { - alert("请先加入房间再选文件") - } - this.addUserLogs("请先加入房间再选文件"); + layer.msg(this.lang.please_join_then_choose_file) + this.addUserLogs(this.lang.please_join_then_choose_file); return; } if (this.roomId) { if (this.roomId.toString().length > 15) { - if (window.layer) { - layer.msg("房间号太长啦") - } else { - alert("房间号太长啦") - } - this.addUserLogs("房间号太长啦"); + layer.msg(this.lang.room_num_too_long) + this.addUserLogs(this.lang.room_num_too_long); return; } this.setNickName(); this.socket.emit('createAndJoin', { room: this.roomId, type : 'password', - password : '', - nickName : this.nickName + password : '', + nickName : this.nickName, + langMode : this.langMode }); this.isJoined = true; this.addPopup({ - title : "文件房间", - msg : "你进入了文件房间" + this.roomId + title : this.lang.file_room, + msg : this.lang.you_enter_file_room + this.roomId }); - this.addUserLogs("你进入了文件房间" + this.roomId); + this.addUserLogs( this.lang.you_enter_file_room + this.roomId); } }, //创建流媒体房间 createMediaRoom: function (type) { this.roomId = this.roomId.toString().replace(/\s*/g, "") if (this.roomId === null || this.roomId === undefined || this.roomId === '') { - if (window.layer) { - layer.msg("请先填写房间号") - } else { - alert("请先填写房间号") - } - this.addUserLogs("请先填写房间号"); + layer.msg(this.lang.please_enter_room_num) + this.addUserLogs(this.lang.please_enter_room_num); return; } if (this.roomId) { if (this.roomId.toString().length > 15) { - if (window.layer) { - layer.msg("房间号太长啦") - } else { - alert("房间号太长啦") - } - this.addUserLogs("房间号太长啦"); + layer.msg(this.lang.room_num_too_long) + this.addUserLogs(this.lang.room_num_too_long); return; } this.setNickName(); this.socket.emit('createAndJoin', { room: this.roomId, type: type, - nickName : this.nickName + nickName : this.nickName, + langMode : this.langMode }); this.isJoined = true; this.roomType = type; this.addPopup({ - title : "流媒体房间", - msg : "你进入了流媒体房间" + this.roomId + title : this.lang.stream_room, + msg : this.lang.you_enter_stream_room + this.roomId }); - this.addUserLogs("你进入了流媒体房间" + this.roomId); + this.addUserLogs(this.lang.you_enter_stream_room + this.roomId); } }, //创建密码房间 createPasswordRoom: function (password) { this.roomId = this.roomId.toString().replace(/\s*/g, "") if (this.roomId === null || this.roomId === undefined || this.roomId === '') { - if (window.layer) { - layer.msg("请先填写房间号") - } else { - alert("请先填写房间号") - } - this.addUserLogs("请先填写房间号"); + layer.msg(this.lang.please_enter_room_num) + this.addUserLogs(this.lang.please_enter_room_num); return; } if (this.roomId) { if (this.roomId.toString().length > 15) { - if (window.layer) { - layer.msg("房间号太长啦") - } else { - alert("房间号太长啦") - } - this.addUserLogs("房间号太长啦"); + layer.msg(this.lang.room_num_too_long) + this.addUserLogs(this.lang.room_num_too_long); return; } if (password.toString().length > 15) { - if (window.layer) { - layer.msg("密码太长啦") - } else { - alert("密码太长啦") - } - this.addUserLogs("密码太长啦"); + layer.msg(this.lang.password_too_long) + this.addUserLogs(this.lang.password_too_long); return; } this.setNickName(); @@ -2273,14 +2191,15 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { room: this.roomId, type : 'password', password: password, - nickName : this.nickName + nickName : this.nickName, + langMode : this.langMode }); this.isJoined = true; this.addPopup({ - title : "密码房间", - msg : "你进入了密码房间" + this.roomId + title : this.lang.password_room, + msg : this.lang.you_enter_password_room + this.roomId }); - this.addUserLogs("你进入了密码房间" + this.roomId); + this.addUserLogs(this.lang.you_enter_password_room + this.roomId); } }, //退出房间 @@ -2314,7 +2233,7 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { }; rtcConnect.oniceconnectionstatechange = (e) => { - this.addSysLogs("iceConnectionState: " + rtcConnect.iceConnectionState); + that.addSysLogs("iceConnectionState: " + rtcConnect.iceConnectionState); } //保存peer连接 @@ -2373,36 +2292,57 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { initSendDataChannel: function (id) { let that = this; - let sendChannel = this.rtcConns[id].createDataChannel('sendDataChannel'); - sendChannel.binaryType = 'arraybuffer'; - - sendChannel.addEventListener('open', (event) => { - if (sendChannel.readyState === 'open') { - that.addSysLogs("建立连接 : channel open") + //文件发送数据通道 + let sendFileDataChannel = this.rtcConns[id].createDataChannel('sendFileDataChannel'); + sendFileDataChannel.binaryType = 'arraybuffer'; + sendFileDataChannel.addEventListener('open', (event) => { + if (sendFileDataChannel.readyState === 'open') { + that.addSysLogs(that.lang.establish_connection) } }); - sendChannel.addEventListener('close', (event) => { - if (sendChannel.readyState === 'close') { - that.addSysLogs("连接关闭 : channel close") + sendFileDataChannel.addEventListener('close', (event) => { + if (sendFileDataChannel.readyState === 'close') { + that.addSysLogs(that.lang.connection_closed) } }); - sendChannel.addEventListener('error', (error) => { + sendFileDataChannel.addEventListener('error', (error) => { console.error(error.error) - that.addSysLogs("连接断开 : " + error) + that.addSysLogs(that.lang.connection_disconnected + ",file:e=" + error) that.removeStream(null, id, null) }); + + //自定义数据发送通道 + let sendDataChannel = this.rtcConns[id].createDataChannel('sendDataChannel'); + sendDataChannel.binaryType = 'arraybuffer'; + sendDataChannel.addEventListener('open', (event) => { + if (sendDataChannel.readyState === 'open') { + that.addSysLogs(that.lang.establish_connection) + } + }); + sendDataChannel.addEventListener('close', (event) => { + if (sendDataChannel.readyState === 'close') { + that.addSysLogs(that.lang.connection_closed) + } + }); + sendDataChannel.addEventListener('error', (error) => { + console.error(error.error) + that.addSysLogs(that.lang.connection_disconnected + ",cus:e=" + error) + that.removeStream(null, id, null) + }); + this.rtcConns[id].addEventListener('datachannel', (event) => { that.initReceiveDataChannel(event, id); }); - this.setRemoteInfo(id, { sendChannel: sendChannel }); + this.setRemoteInfo(id, { + sendFileDataChannel: sendFileDataChannel, + sendDataChannel : sendDataChannel + }); }, // 初始发送 // pickRecoder : 指定发送记录进行发送 initSendFile: function (pickRecoder) { if(!this.hasManInRoom){ - if(window.layer){ - layer.msg("房间内至少需要两个人才能发送文件") - } + layer.msg(this.lang.room_least_two_can_send_content) return } //选中一个记录进行发送 @@ -2419,7 +2359,7 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { chooseFileRecoder = pickRecoder; }else{ - this.addSysLogs("选择待发送记录中...") + this.addSysLogs(this.lang.select_wait_send_record) for (let i = 0; i < this.sendFileRecoderList.length; i++) { let recoder = this.sendFileRecoderList[i] if (!recoder.done) { @@ -2432,10 +2372,10 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { this.chooseFileList = [] this.sendFileRecoderList = [] this.addPopup({ - title : "文件发送", - msg : "文件全部发送完毕" + title : this.lang.send_file, + msg : this.lang.file_send_done }); - this.addSysLogs("文件全部发送完毕") + this.addSysLogs(this.lang.file_send_done) this.isSending = false; this.allSended = true; return @@ -2448,19 +2388,15 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { }); if(filterFile.length === 0){ - this.addUserLogs("文件读取失败,文件资源不存在"); - if(window.layer){ - layer.msg("文件读取失败,文件资源不存在"); - } + this.addUserLogs(this.lang.failed_find_file); + layer.msg(this.lang.failed_find_file); return } chooseFile = filterFile[0]; if(chooseFile == null){ - this.addUserLogs("文件读取失败,文件资源不存在"); - if(window.layer){ - layer.msg("文件读取失败,文件资源不存在"); - } + this.addUserLogs(this.lang.failed_find_file); + layer.msg(this.lang.failed_find_file); return } @@ -2488,11 +2424,11 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { fileReader.addEventListener('loadend', this.sendFileToRemoteByLoop); fileReader.addEventListener('error', error => { - that.addSysLogs("读取文件错误 : " + error); + that.addSysLogs(this.lang.read_file_error + " : " + error); }); fileReader.addEventListener('abort', event => { - that.addSysLogs("读取文件中断 : " + event); + that.addSysLogs(this.lang.read_file_interrupt + " : " + event); }); this.readSlice(0); @@ -2507,9 +2443,9 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { let remote = this.remoteMap[this.currentChooseFileRecoder.id]; let fileOffset = remote[this.currentChooseFile.index + "offset"] - let sendChannel = remote.sendChannel; - if (!sendChannel || sendChannel.readyState !== 'open') { - this.addSysLogs("sendChannel 出错") + let sendFileDataChannel = remote.sendFileDataChannel; + if (!sendFileDataChannel || sendFileDataChannel.readyState !== 'open') { + this.addSysLogs(this.lang.file_send_channel_not_establish) return; } @@ -2517,7 +2453,7 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { // 还不能进行发送,等一下 if (!sendFileInfoAck) { - this.addSysLogs("等待ack回执中...") + this.addSysLogs(this.lang.wait_ack) setTimeout(() => { that.sendFileToRemoteByLoop(event) }, 500); @@ -2531,28 +2467,28 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { // 开始发送通知 if (fileOffset === 0) { this.addPopup({ - title : "文件发送", - msg : "正在发送给" + this.currentChooseFileRecoder.id.substr(0, 4) + ",0%。" + title : this.lang.send_file, + msg : this.lang.sending_to + this.currentChooseFileRecoder.id.substr(0, 4) + ",0%。" }); - this.addSysLogs("正在发送给" + this.currentChooseFileRecoder.id.substr(0, 4) + ",0%。") + this.addSysLogs(this.lang.sending_to + this.currentChooseFileRecoder.id.substr(0, 4) + ",0%。") this.updateSendFileRecoderProgress(this.currentChooseFileRecoder.id, { start: Date.now() }) } // 缓冲区満了 - if (sendChannel.bufferedAmount > sendChannel.bufferedAmountLowThreshold) { - this.addSysLogs("sendChannel缓冲区已满,等待中...") - sendChannel.onbufferedamountlow = () => { - this.addSysLogs("sendChannel缓冲区已恢复,继续发送中...") - sendChannel.onbufferedamountlow = null; + if (sendFileDataChannel.bufferedAmount > sendFileDataChannel.bufferedAmountLowThreshold) { + this.addSysLogs(this.lang.file_send_channel_buffer_full) + sendFileDataChannel.onbufferedamountlow = () => { + this.addSysLogs(this.lang.file_send_channel_buffer_recover) + sendFileDataChannel.onbufferedamountlow = null; that.sendFileToRemoteByLoop(event); } return; } // 发送数据 - sendChannel.send(event.target.result); + sendFileDataChannel.send(event.target.result); fileOffset += event.target.result.byteLength; remote[this.currentChooseFile.index + "offset"] = fileOffset this.currentSendAllSize += event.target.result.byteLength; @@ -2565,10 +2501,10 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { //发送完一份重置相关数据 if (fileOffset === this.currentChooseFile.size) { this.addPopup({ - title : "文件发送", - msg : "正在发送给" + this.currentChooseFileRecoder.id.substr(0, 4) + ",100%。" + title : this.lang.send_file, + msg : this.lang.sending_to + this.currentChooseFileRecoder.id.substr(0, 4) + ",100%。" }); - this.addSysLogs("正在发送给" + this.currentChooseFileRecoder.id.substr(0, 4) + ",100%。") + this.addSysLogs(this.lang.sending_to + this.currentChooseFileRecoder.id.substr(0, 4) + ",100%。") this.socket.emit('message', { emitType: "sendDone", room: this.roomId, @@ -2608,10 +2544,10 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { this.chooseFileList = [] this.sendFileRecoderList = [] this.addPopup({ - title : "文件发送", - msg : "文件全部发送完毕" + title : this.lang.send_file, + msg : this.lang.file_send_done }); - this.addSysLogs("文件全部发送完毕") + this.addSysLogs(this.lang.file_send_done) this.allSended = true; return } @@ -2642,31 +2578,59 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { fileReader.readAsArrayBuffer(slice); } }, - //创建接收文件事件 + //初始化接收数据事件 initReceiveDataChannel: function (event, id) { if (!id || !event) { return; } let currentRtc = this.getRemoteInfo(id); - if (currentRtc) { - let receiveChannel = event.channel; + if (!currentRtc) { + return + } + + let receiveChannel = event.channel; + + //文件接收 + if(receiveChannel.label === 'sendFileDataChannel'){ receiveChannel.binaryType = 'arraybuffer'; - receiveChannel.onmessage = (env) => { - this.receiveData(env, id); + receiveChannel.onmessage = (evt) => { + this.receiveFileData(evt, id); }; receiveChannel.onopen = () => { const readyState = receiveChannel.readyState; - this.addSysLogs("receiveChannel 已就绪, readyState:" + readyState) + this.addSysLogs(this.lang.file_receive_channel_ready + readyState) }; receiveChannel.onclose = () => { const readyState = receiveChannel.readyState; - this.addSysLogs("receiveChannel 已关闭 readyState:" + readyState) + this.addSysLogs(this.lang.file_receive_channel_closed + readyState) }; - this.setRemoteInfo(id, { receiveChannel: receiveChannel }); + this.setRemoteInfo(id, { receiveFileDataChannel: receiveChannel }); + } + + //自定义数据接收 + if(receiveChannel.label === 'sendDataChannel'){ + receiveChannel.binaryType = 'arraybuffer'; + receiveChannel.onmessage = (evt) => { + //接收自定义数据 , 暂时用做远程画笔数据接收 + if (!evt || !id) { + return; + } + let data = JSON.parse(evt.data) || {}; + window.Bus.$emit("openRemoteDraw", data) + } + receiveChannel.onopen = () => { + const readyState = receiveChannel.readyState; + this.addSysLogs(this.lang.custom_data_receive_channel_ready + readyState) + }; + receiveChannel.onclose = () => { + const readyState = receiveChannel.readyState; + this.addSysLogs(this.lang.custom_data_receive_channel_closed + readyState) + }; + this.setRemoteInfo(id, { receiveDataChannel: receiveChannel }); } }, //接收文件 - receiveData: function (event, id) { + receiveFileData: function (event, id) { if (!event || !id) { return; } @@ -2692,10 +2656,10 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { }); if (receivedSize === size) { - this.addSysLogs(name + " 接收完毕"); + this.addSysLogs(name + this.lang.receive_done); this.addPopup({ - title : "文件接收", - msg : "文件[ " + name + " ]接收完毕,可点击右下角查看。" + title : this.lang.file_receive, + msg : "[ " + name + " ]" + this.lang.receive_done }); //更新接收进度 @@ -2714,13 +2678,24 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { closeDataChannels: function () { for (let remote in this.remoteMap) { let id = remote.id; - let sendChannel = remote.sendChannel; - let receiveChannel = remote.receiveChannel; - if (!id || !sendChannel || !receiveChannel) { - continue; + if(!id) continue; + + let sendFileDataChannel = remote.sendFileDataChannel; + if(sendFileDataChannel){ + sendFileDataChannel.close(); + } + let sendDataChannel = remote.sendDataChannel; + if(sendDataChannel){ + sendDataChannel.close(); + } + let receiveFileDataChannel = remote.receiveFileDataChannel; + if(receiveFileDataChannel){ + receiveFileDataChannel.close(); + } + let receiveDataChannel = remote.receiveDataChannel; + if(receiveDataChannel){ + receiveDataChannel.close(); } - sendChannel.close(); - receiveChannel.close(); } }, //设置rtc缓存远程连接数据 @@ -2826,7 +2801,7 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { }, // offer offerFailed: function (rtcConnect, id, error) { - this.addSysLogs("offer失败," + error); + this.addSysLogs(this.lang.offer_failed + error); }, // answer answerSuccess: function (rtcConnect, id, offer) { @@ -2841,15 +2816,15 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { }, // answer answerFailed: function (rtcConnect, id, error) { - this.addSysLogs("answer失败," + error); + this.addSysLogs(this.lang.answer_failed + error); }, //ice addIceCandidateSuccess: function (res) { - this.addSysLogs("addIceCandidateSuccess成功"); + this.addSysLogs(this.lang.add_ice_candidate_success); }, //ice addIceCandidateFailed: function (err) { - this.addSysLogs("addIceCandidate失败," + err); + this.addSysLogs(this.lang.add_ice_candidate_failed + err); }, socketListener: function () { let that = this; @@ -2858,7 +2833,7 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { // 1. 对于screen, video房间来说,是双方都需要传输各自的媒体流 // 2. 对于live房间来说,只有房主需要获取媒体流 this.socket.on('created', async function (data) { - that.addSysLogs("创建房间," + JSON.stringify(data)); + that.addSysLogs(that.lang.receive_create_room_event + JSON.stringify(data)); that.socketId = data.id; that.roomId = data.room; that.recoderId = data.recoderId; @@ -2879,9 +2854,15 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { for (let i = 0; i < data.peers.length; i++) { let otherSocketId = data.peers[i].id; let otherSocketIdNickName = data.peers[i].nickName; + let otherSocketIdLangMode = data.peers[i].langMode; + let otherSocketIdOwner = data.peers[i].owner; let rtcConnect = that.getOrCreateRtcConnect(otherSocketId); // 处理完连接后,更新下昵称 - that.setRemoteInfo(otherSocketId, { nickName : otherSocketIdNickName }) + that.setRemoteInfo(otherSocketId, { + nickName : otherSocketIdNickName, + langMode : otherSocketIdLangMode, + owner : otherSocketIdOwner + }) await new Promise(resolve => { // 处理音视频情况 @@ -2915,11 +2896,16 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { // join的作用是通知其他人,我加入进来了 this.socket.on('joined', function (data) { - that.addSysLogs("加入房间," + JSON.stringify(data)); + that.addSysLogs(that.lang.receive_join_room_event + JSON.stringify(data)); that.recoderId = data.recoderId; let rtcConnect = that.getOrCreateRtcConnect(data.id); // 处理完连接后,更新下昵称 - that.setRemoteInfo(data.id, { nickName : data.nickName }) + that.setRemoteInfo(data.id, { + nickName : data.nickName, + owner : data.owner, + langMode : data.langMode, + owner : false + }) // 处理音视频逻辑 if (data.type === 'screen') { window.Bus.$emit("getScreenShareTrackAndStream", (track, stream) => { @@ -2937,13 +2923,13 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { }); } that.addPopup({ - title : "加入房间", - msg : data.nickName + " 加入了房间。" + title : that.lang.join_room, + msg : data.nickName + that.lang.join_room }); }); this.socket.on('offer', function (data) { - that.addSysLogs("offer," + JSON.stringify(data)); + that.addSysLogs(that.lang.receive_offer_event + JSON.stringify(data)); let rtcConnect = that.getOrCreateRtcConnect(data.from); let rtcDescription = { type: 'offer', sdp: data.sdp }; rtcConnect.setRemoteDescription(new RTCSessionDescription(rtcDescription)).then(r => { }); @@ -2955,14 +2941,14 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { }); this.socket.on('answer', function (data) { - that.addSysLogs("answer," + JSON.stringify(data)); + that.addSysLogs(that.lang.receive_answer_event + JSON.stringify(data)); let rtcConnect = that.getOrCreateRtcConnect(data.from); let rtcDescription = { type: 'answer', sdp: data.sdp }; rtcConnect.setRemoteDescription(new RTCSessionDescription(rtcDescription)).then(r => { }); }); this.socket.on('candidate', function (data) { - that.addSysLogs("candidate," + JSON.stringify(data)); + that.addSysLogs(that.lang.receive_candidate_event + JSON.stringify(data)); let rtcConnect = that.getOrCreateRtcConnect(data.from); let rtcIceCandidate = new RTCIceCandidate({ candidate: data.sdp, @@ -2982,10 +2968,10 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { return; } else { that.addPopup({ - title : "退出房间", - msg : data.from + "退出了房间。" + title : that.lang.exit_room, + msg : data.from + that.lang.exit_room }); - that.addSysLogs("退出房间," + JSON.stringify(data)); + that.addSysLogs(that.lang.exit_room + JSON.stringify(data)); that.getOrCreateRtcConnect(data.from).close; delete that.rtcConns[data.from]; Vue.delete(that.remoteMap, data.from); @@ -2998,10 +2984,10 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { let fromId = data.from; that.setRemoteInfo(fromId, { receiveFiles: data }); that.addPopup({ - title : "文件准备", - msg : data.from + "选择了文件 [ " + data.name + " ],即将发送。" + title : that.lang.send_file, + msg : data.from + that.lang.selected_file + "[ " + data.name + " ], "+that.lang.will_send }); - that.addSysLogs(data.from + "选择了文件 [ " + data.name + " ],即将发送。"); + that.addSysLogs(data.from + that.lang.selected_file + "[ " + data.name + " ], "+that.lang.will_send); that.receiveFileRecoderList.push({ id: fromId, @@ -3033,7 +3019,7 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { let to = data.to; let fromId = data.from; if (to === that.socketId) { // 是自己发出去的文件ack回执 - that.addSysLogs("收到ack回执,准备发送给" + fromId) + that.addSysLogs(that.lang.receive_ack + fromId) that.setRemoteInfo(fromId, { [that.currentChooseFile.index + "ack"]: true }) @@ -3043,9 +3029,7 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { //获取取件码文件 this.socket.on('getCodeFile', function (data) { if(!data.download){ - if(window.layer){ - layer.msg("此取件码暂无文件记录") - } + layer.msg(that.lang.no_code_file) return } that.receiveCodeFileList = [data]; @@ -3054,34 +3038,27 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { //暂存成功通知 this.socket.on('addCodeFile', function (data) { - if(window.layer){ - layer.msg("暂存成功"); - } + layer.msg(that.lang.save_ok); }) //收到暂存链接 this.socket.on('prepareCodeFile', async function (data) { let index = data.index; - - that.addSysLogs("收到暂存链接"); + that.addSysLogs(that.lang.receive_temporary_link); let filterFile = that.chooseFileList.filter(item=>{ return item.index === index; }); if(filterFile.length === 0){ - if(window.layer){ - layer.msg("加载文件失败,文件资源不存在"); - } - that.addUserLogs("加载文件失败,文件资源不存在"); + layer.msg(that.lang.file_not_exist); + that.addUserLogs(file_not_exist); return } if(!data.uploadLink){ - if(window.layer){ - layer.msg("暂存失败"); - } - that.addSysLogs("文件暂存失败, 上传链接为空, ",file.name); + layer.msg(that.lang.save_fail); + that.addSysLogs(that.lang.temporary_link_empty + file.name); return } @@ -3105,10 +3082,8 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { upload : 'fail' }) - if(window.layer){ - layer.msg("暂存失败"); - } - that.addSysLogs("文件暂存失败, name=",file.name); + layer.msg(that.lang.save_fail); + that.addSysLogs(that.lang.save_fail + file.name); return } @@ -3140,10 +3115,8 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { upload : 'fail' }) - if(window.layer){ - layer.msg("暂存失败"); - } - that.addSysLogs("文件暂存失败, name=",file.name); + layer.msg(that.lang.save_fail); + that.addSysLogs(that.lang.save_fail + file.name); return } }) @@ -3152,15 +3125,15 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { this.socket.on('chatingRoom', function (data) { let fromId = data.from; that.addPopup({ - title : "文本", - msg : data.from + "发送了文字 [ " + data.content.substr(0, 10) + " ]" + title : that.lang.send_text, + msg : data.from + that.lang.send_text + "[ " + data.content.substr(0, 10) + " ]" }); - that.addSysLogs(data.from + "发送了文字 [ " + data.content.substr(0, 10) + " ]"); + that.addSysLogs(data.from + that.lang.send_text + "[ " + data.content.substr(0, 10) + " ]"); try { - data.content = decodeURIComponent(data.content) + data.content = tlrtcfile.unescapeStr(data.content) } catch (e) { - that.addSysLogs("decode msg err : " + data.content); + that.addSysLogs(that.lang.text_decode_failed + data.content); } let now = new Date().toLocaleString(); @@ -3200,7 +3173,7 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { //在线数量 this.socket.on('count', function (data) { that.allManCount = data.mc; - that.addSysLogs("当前人数 : " + data.mc + "人在线") + that.addSysLogs(that.lang.current_number + ":" + data.mc + that.lang.online_number) }); //提示 @@ -3257,8 +3230,8 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { that.receiveAiChatList.push(data) that.addSysLogs("AI : " + data.content) that.addPopup({ - title : "AI回复", - msg : "AI回复了你,快点聊起来吧~" + title : that.lang.ai_reply, + msg : that.lang.ai_reply_you }); that.receiveAiChatList.forEach(item => { item.timeAgo = window.util ? util.timeAgo(item.time) : item.time; @@ -3283,9 +3256,9 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { if(data.chatingCommData){ data.chatingCommData.forEach(elem => { try { - elem.msg = decodeURIComponent(elem.msg) + elem.msg = tlrtcfile.unescapeStr(elem.msg) } catch (e) { - that.addSysLogs("decode msg err : " + elem.msg); + that.addSysLogs(that.lang.text_decode_failed + elem.msg); } that.receiveChatCommList.push(elem) }) @@ -3297,11 +3270,11 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { //公共聊天频道 this.socket.on('chatingComm', function (data) { - that.addSysLogs(data.room + "频道的" + data.socketId + "发言: [ " + data.msg + " ]"); + that.addSysLogs(data.room + ":" + data.socketId + that.lang.send_text + ": [ " + data.msg + " ]"); try { - data.msg = decodeURIComponent(data.msg) + data.msg = tlrtcfile.unescapeStr(data.msg) } catch (e) { - that.addSysLogs("decode msg err : " + data.msg); + that.addSysLogs(that.lang.text_decode_failed + data.msg); } that.receiveChatCommList.push(data); if (that.receiveChatCommList.length > 10) { @@ -3313,63 +3286,59 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { that.chatingCommTpl() that.addPopup({ - title : "公共聊天", - msg : "公共聊天频道有人互动啦,快去瞧瞧" + title : that.lang.chat_comm, + msg : that.lang.public_chat_channel_someone_interact }); }); this.socket.on('manageCheck', function (data) { - if (window.layer) { - layer.prompt({ - formType: 1, - title: '请输入', - }, function (value, index, elem) { - that.socket.emit('manageConfirm', { - room: that.roomId, - value: value - }); - layer.close(index) + layer.prompt({ + formType: 1, + title: that.lang.please_enter, + }, function (value, index, elem) { + that.socket.emit('manageConfirm', { + room: that.roomId, + value: value }); - } + layer.close(index) + }); }); this.socket.on('manage', function (data) { - if (window.layer) { - if (data.socketId !== that.socketId) { - layer.msg("非法触发事件") - return - } - layer.closeAll(); - that.token = data.token; - layer.load(2, { - time: 1000, - shade: [0.8, '#000000'], - success: function (layero) { - layer.setTop(layero); //重点2 - } - }) - setTimeout(() => { - that.manageIframeId = layer.tab({ - area: ['100%', '100%'], - shade: [0.8, '#393D49'], - closeBtn : 0, - tab: [{ - title: data.content[0].title, - content: data.content[0].html - }, { - title: data.content[1].title, - content: data.content[1].html - }, { - title: data.content[2].title, - content: data.content[2].html - }], - cancel: function (index, layero) { - that.manageIframeId = 0; - }, - }) - layer.full(that.manageIframeId) - }, 500); + if (data.socketId !== that.socketId) { + layer.msg(that.lang.illegal_event) + return } + layer.closeAll(); + that.token = data.token; + layer.load(2, { + time: 1000, + shade: [0.8, '#000000'], + success: function (layero) { + layer.setTop(layero); //重点2 + } + }) + setTimeout(() => { + that.manageIframeId = layer.tab({ + area: ['100%', '100%'], + shade: [0.8, '#393D49'], + closeBtn : 0, + tab: [{ + title: data.content[0].title, + content: data.content[0].html + }, { + title: data.content[1].title, + content: data.content[1].html + }, { + title: data.content[2].title, + content: data.content[2].html + }], + cancel: function (index, layero) { + that.manageIframeId = 0; + }, + }) + layer.full(that.manageIframeId) + }, 500); }); }, // 检测浏览器是支持webrtc @@ -3380,75 +3349,63 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { setTimeout(() => { $("#rtcCheck").addClass("layui-anim-rotate") let rtcCheck = tlrtcfile.supposeWebrtc(); - if (window.layer) { - layer.msg(`你的浏览器${rtcCheck ? '支持' : '不支持'}webrtc`) - } - that.addUserLogs(`你的浏览器${rtcCheck ? '支持' : '不支持'}webrtc`) + layer.msg(`${that.lang.your_browser}${rtcCheck ? that.lang.support : that.lang.not_support}webrtc`) + that.addUserLogs(`${that.lang.your_browser}${rtcCheck ? that.lang.support : that.lang.not_support}webrtc`) }, 50) } }, // 打开p2p检测面板 p2pCheck: function () { let that = this; - if (window.layer) { - $("#p2pCheck").removeClass("layui-anim-rotate") - setTimeout(() => { - $("#p2pCheck").addClass("layui-anim-rotate") - let msg = "

p2p检测原理:

" - msg += "

本项目是基于webrtc实现的,webrtc的p2p受限于连接 双方的网络NAT类型和浏览器限制

" - msg += "

对称NAT网络类型或者浏览器不支持获取内网ip的情况是不支持p2p的

" - msg += "

自检步骤:

" - msg += "

在验证p2p之前, 请先关闭中继服务开关后 ,双方进入后房间,再进行自检

" - msg += "

双方加入房间后,如果客户端可以获取到房间内双方的内网IP,大概率就可以进行p2p传输

" - msg += "

如果是chrome电脑版,可以打开 chrome://flags/ , 然后搜索 'mdns' 关键字,打开开关后重启即可

" - msg += "

具体是否有获取到双方内网IP,请自行在执行日志中搜索关键字 “IP”,查看是否有类似内网格式的IP即可

" - layer.confirm(msg, (index) => { - layer.closeAll(() => { - that.clickLogs() - }) - }, (index) => { - layer.close(index) + $("#p2pCheck").removeClass("layui-anim-rotate") + setTimeout(() => { + $("#p2pCheck").addClass("layui-anim-rotate") + let msg = "

"+that.lang.p2p_check_principle+":

" + msg += "

"+that.lang.p2p_check_principle_detail+" "+that.lang.p2p_check_principle_detail_2+"

" + msg += "

"+that.lang.p2p_check_principle_detail_3+":

" + msg += "

"+that.lang.p2p_check_principle_detail_4+" "+that.lang.p2p_check_principle_detail_5+" "+that.lang.p2p_check_principle_detail_6+"

" + msg += "

"+that.lang.p2p_check_principle_detail_7+"

" + msg += "

"+that.lang.p2p_check_principle_detail_8+" chrome://flags/ , "+that.lang.p2p_check_principle_detail_9+"

" + msg += "

"+that.lang.p2p_check_principle_detail_10+"

" + layer.confirm(msg, (index) => { + layer.closeAll(() => { + that.clickLogs() }) - that.addUserLogs(`你的IP列表为 : ${JSON.stringify(this.ips)}`) - }, 50) - } + }, (index) => { + layer.close(index) + }) + that.addUserLogs(`${that.lang.your_ip_list} : ${JSON.stringify(this.ips)}`) + }, 50) }, initOpEvent : function(){ let that = this; if (window.tlrtcfile) { tlrtcfile.getOpEventData((type, event) => { if(type === 'click'){ - that.controlList.push({type : 'click', x : event.x * 0.8, y : event.y * 0.7}) + if(that.isRemoteControl){ + // that.controlList.push({type : 'click', x : event.x * 0.8, y : event.y * 0.7}) + } }else if(type === 'contextmenu'){ - that.controlList.push({type : 'rightclick', x : event.x * 0.8, y : event.y * 0.7}) + if(that.isRemoteControl){ + // that.controlList.push({type : 'rightclick', x : event.x * 0.8, y : event.y * 0.7}) + } }else if(type === 'mousemove'){ - //没有移动 - if (that.preMouseMove.clientX === event.clientX && - that.preMouseMove.clientY === event.clientY){ - return; - } //移动距离太小 - if (Math.abs(that.preMouseMove.clientX - event.clientX) < 10 && - Math.abs(that.preMouseMove.clientY - event.clientY) < 10){ + if (Math.abs(that.preMouseMove.clientX - event.clientX) < that.mouseMoveUnit && + Math.abs(that.preMouseMove.clientY - event.clientY) < that.mouseMoveUnit){ return; } - //鼠标拖拽 - if(that.isMouseDrag){ - that.controlList.push({type : 'mousedrag', x : event.x * 0.8, y : event.y * 0.7}) - }else{ - //鼠标移动 - that.controlList.push({type : 'mousemove', x : event.x * 0.8, y : event.y * 0.7}) - } - //画笔移动监测记录 - let { x, y } = event; - let pre = that.mouseMove.length > 0 ? that.mouseMove[that.mouseMove.length - 1] : {x:0,y:0}; - if(Math.abs(pre.x - x) > 10 || Math.abs(pre.y - y) > 10){ - if(that.mouseMove.length > 3000){ // 超过3000,丢弃最开始的2000,保留最新的1000 - that.mouseMove = that.mouseMove.slice(0, 1000) - console.log("slice mouse arr done") + + if(that.isMouseDrag){ //鼠标拖拽 + if(that.isRemoteControl){ + // that.controlList.push({type : 'mousedrag', x : event.x * 0.8, y : event.y * 0.7}) + } + }else{//鼠标移动 + if(that.isRemoteControl){ + // that.controlList.push({type : 'mousemove', x : event.x * 0.8, y : event.y * 0.7}) } - that.mouseMove.push({ x: x * 0.8, y : y * 0.7 }) } + //记录上一次移动的位置 that.preMouseMove = { clientX : event.clientX, @@ -3457,26 +3414,30 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { } }else if(type === 'mousedown'){ that.isMouseDrag = true; - that.controlList.push({type : 'mousedown'}) + if(that.isRemoteControl){ + // that.controlList.push({type : 'mousedown'}) + } }else if(type === 'mouseup'){ that.isMouseDrag = false; - that.controlList.push({type : 'mouseup'}) + if(that.isRemoteControl){ + // that.controlList.push({type : 'mouseup'}) + } }else if(type === 'wheel'){ - that.controlList.push({type : 'wheel', x : event.x * 0.8, y : event.y * 0.7, deltaY : event.deltaY}) + if(that.isRemoteControl){ + // that.controlList.push({type : 'wheel', x : event.x * 0.8, y : event.y * 0.7, deltaY : event.deltaY}) + } }else if(type === 'keydown'){ - that.controlList.push({type : 'keydown', key : event.key}) + if(that.isRemoteControl){ + // that.controlList.push({type : 'keydown', key : event.key}) + } }else if(type === 'keyup'){ - that.controlList.push({type : 'keyup', key : event.key}) + if(that.isRemoteControl){ + // that.controlList.push({type : 'keyup', key : event.key}) + } } }) } }, - // 画笔轨迹绘制 - initDrawMousePath : function(){ - if (window.tlrtcfile) { - tlrtcfile.drawMousePath(this.mouseMove) - } - }, // 自动监听窗口变化,更新css reCaculateWindowSize: function () { this.clientWidth = document.body.clientWidth; @@ -3500,10 +3461,6 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { if (window.layer && this.manageIframeId !== 0) { layer.full(this.manageIframeId) } - - if(this.clientWidth < 300){ - - } }, // 自动监听窗口变化,更新css touchResize: function (e) { @@ -3529,12 +3486,6 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { }, // 定义事件到window上 windowOnBusEvent: function () { - window.Bus.$on("changeScreenState", (res) => { - this.isScreen = res - }) - window.Bus.$on("changeScreenTimes", (res) => { - this.screenTimes = res - }) window.Bus.$on("changeScreenShareState", (res) => { if(!res){//状态失败,收起面板 this.clickMediaScreen(); @@ -3547,7 +3498,8 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { emitType: "stopScreenShare", id: this.socketId, room: this.roomId, - cost: this.screenShareTimes + cost: this.screenShareTimes, + to : this.socketId }); } this.screenShareTimes = res @@ -3564,7 +3516,8 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { emitType: "stopVideoShare", id: this.socketId, room: this.roomId, - cost: this.videoShareTimes + cost: this.videoShareTimes, + to : this.socketId }); } this.videoShareTimes = res @@ -3582,7 +3535,8 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { id: this.socketId, room: this.roomId, cost: this.liveShareTimes, - owner : this.owner + owner : this.owner, + to : this.socketId }); } this.liveShareTimes = res @@ -3601,10 +3555,8 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { }) window.Bus.$on("sendOpenaiChatWithContext", () => { this.openaiSendContext = !this.openaiSendContext; - if (window.layer) { - layer.msg(`AI智能理解上下文开关${this.openaiSendContext ? '已开启' : '已关闭'}`) - this.addUserLogs(`AI智能理解上下文开关${this.openaiSendContext ? '已开启' : '已关闭'} `) - } + layer.msg(`${this.lang.ai_switch}${this.openaiSendContext ? this.lang.on : this.lang.off}`) + this.addUserLogs(`${this.lang.ai_switch}${this.openaiSendContext ? this.lang.on : this.lang.off}`) $("#aiContext").removeClass("layui-anim-rotate") setTimeout(() => { $("#aiContext").addClass("layui-anim-rotate") @@ -3638,9 +3590,6 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { window.Bus.$on("relaySetting", (res) => { this.relaySetting() }) - window.Bus.$on("initDrawMousePath", () => { - this.initDrawMousePath() - }) }, // 初始化选择文件面板 renderChooseFileComp: function () { @@ -3674,7 +3623,7 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { //如果文件已经存在,就不再添加了 if(hasChooseFile){ - that.addUserLogs(`选择的文件已经存在相同的文件,不再重复添加 : ${file.name}, 大小 : ${that.getFileSizeStr(file.size)}, 类型 : ${file.type}`); + that.addUserLogs(`${that.lang.selected_file_exist} : ${file.name}, ${that.lang.size} : ${that.getFileSizeStr(file.size)}, ${that.lang.type} : ${file.type}`); continue } @@ -3695,7 +3644,7 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { //如果已经存在记录了,就不再添加了 if (hasFileRecoder) { - that.addUserLogs(`已经存在相同的文件记录,不再重复添加 : ${file.name}, 发送给 : ${that.remoteMap[remoteId].nickName}`); + that.addUserLogs(`${that.lang.send_file_record_exist} : ${file.name} : ${that.remoteMap[remoteId].nickName}`); continue } @@ -3720,7 +3669,7 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { upload : 'wait' }); - that.addUserLogs(`生成文件发送记录 : ${file.name}, 大小 : ${that.getFileSizeStr(file.size)}, 类型 : ${file.type}, 发送给 : ${that.remoteMap[remoteId].nickName}`); + that.addUserLogs(`${that.lang.generate_send_file_record} : ${file.name}, ${that.lang.size} : ${that.getFileSizeStr(file.size)}, ${that.lang.type} : ${file.type}, : ${that.remoteMap[remoteId].nickName}`); } } } @@ -3750,61 +3699,74 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { }, }, mounted: function () { - this.addSysLogs("刷新随机房间号 初始化中..."); + let langArgs = tlrtcfile.getRequestHashArgs("lang") + if (langArgs && ['zh','en'].includes(langArgs)) { + this.langMode = langArgs; + } + this.lang = window.local_lang[this.langMode]; + this.addSysLogs(this.lang.init_language_done); + + this.addSysLogs(this.lang.print_logo); + this.consoleLogo(); + + this.addSysLogs(this.lang.refresh_random_room_num_init); this.refleshRoom() - this.addSysLogs("刷新随机房间号完成"); + this.addSysLogs(this.lang.refresh_random_room_num_init_done); - this.addSysLogs("滑动组件 初始化中..."); + this.addSysLogs(this.lang.slider_init); this.initSwiper(); - this.addSysLogs("滑动组件 初始化完成"); + this.addSysLogs(this.lang.slider_init_done); - this.addSysLogs("SOCKET监听 初始化中..."); + this.addSysLogs(this.lang.socket_init); this.socketListener(); - this.addSysLogs("SOCKET监听 初始化完成"); + this.addSysLogs(this.lang.socket_init_done); - this.addSysLogs("基础数据 获取中..."); + this.addSysLogs(this.lang.basic_data_get); this.socket.emit('getCommData', {}); - this.addSysLogs("基础数据 初始化完成"); + this.addSysLogs(this.lang.basic_data_get_done); - this.addSysLogs("窗口事件监听 初始化中..."); - this.addSysLogs("消息弹窗 初始化中..."); + this.addSysLogs(this.lang.window_event_init); window.onresize = this.touchResize; setInterval(() => { this.touchResize() - let msgData = this.popUpList.shift(); - if(msgData){ - this.startPopUpMsg(msgData) - } }, 1000); - this.addSysLogs("消息弹窗 初始化完成"); - this.addSysLogs("窗口事件监听 初始化完成"); + this.addSysLogs(this.lang.window_event_init_done); - this.addSysLogs("分享组件 初始化中..."); + this.addSysLogs(this.lang.message_box_init); + this.startPopUpMsg() + this.addSysLogs(this.lang.message_box_init_done); + + this.addSysLogs(this.lang.share_init); this.handlerJoinShareRoom(); this.handlerGetCodeFile(); - this.addSysLogs("分享组件 初始化完成"); + this.addSysLogs(this.lang.share_init_done); - this.addSysLogs("公共事件监听 初始化中..."); + this.addSysLogs(this.lang.common_event_init); this.windowOnBusEvent(); - this.addSysLogs("公共事件监听 初始化完成"); + this.addSysLogs(this.lang.common_event_init_done); setTimeout(() => { - this.addSysLogs("文件选择组件 初始化中..."); + this.addSysLogs(this.lang.file_select_init); this.renderChooseFileComp(); - this.addSysLogs("文件选择组件 初始化完成"); + this.addSysLogs(this.lang.file_select_init_done); + + this.addSysLogs(this.lang.language_select_init); + this.changeLanguage() + this.addSysLogs(this.lang.language_select_init_done); }, 2000); - this.addSysLogs("DEBUG组件 初始化中..."); + this.addSysLogs(this.lang.debug_init); this.loadVConsoleJs(); - this.addSysLogs("DEBUG组件 初始化中完成"); + this.addSysLogs(this.lang.debug_init_done); - this.addSysLogs("当前中继服务状态 : " + (this.useTurn ? '启用中' : '已禁用')) + this.addSysLogs(this.lang.current_relay_status + (this.useTurn ? this.lang.on : this.lang.off)) + + // this.addSysLogs(this.lang.event_init); + // this.initOpEvent(); + // this.addSysLogs(this.lang.event_init_done); } }); - window.initDrawMousePath = function () { - window.Bus.$emit("initDrawMousePath") - } window.manageReload = function (data) { window.Bus.$emit("manageReload", data) } @@ -3840,13 +3802,14 @@ axios.get(window.prefix + "/api/comm/initData", {}).then((initData) => { window.Bus.$emit("relaySetting", {}) }); } - window.notUseRelay = function () { - let notUseRelay = window.localStorage.getItem("tl-rtc-file-not-use-relay"); - if (notUseRelay && notUseRelay === 'true') { - window.localStorage.setItem("tl-rtc-file-not-use-relay", false) + window.useTurn = function () { + if ((window.localStorage.getItem("tl-rtc-file-use-relay") || "") === 'true') { + window.localStorage.setItem("tl-rtc-file-use-relay", false) } else { - window.localStorage.setItem("tl-rtc-file-not-use-relay", true) + window.localStorage.setItem("tl-rtc-file-use-relay", true) } window.location.reload() } -}) \ No newline at end of file +}) + + diff --git a/svr/res/js/language.js b/svr/res/js/language.js new file mode 100644 index 0000000..6e19fbd --- /dev/null +++ b/svr/res/js/language.js @@ -0,0 +1,628 @@ +// --------------------------- // +// -- lang.js -- // +// -- version : 1.0.0 -- // +// -- date : 2023-06-22 -- // +// --------------------------- // + +//以内容val输出 key:value形式输出数据,并且注意key不能和之前存在重复, 并且key的长度控制在四个单词以内, val=请输入密码房间密码, key=英文翻译简称, value=英文翻译详情 + +const local_lang = { + "en": { + "add_ice_candidate_failed": "AddIceCandidate failed", + "add_ice_candidate_success": "AddIceCandidateSuccess success", + "ai_answering": "AI is answering your question, please ask again later", + "ai_chat": "Artificial intelligence dialogue", + "ai_chat_record": "AI chat record", + "ai_reply": "AI reply", + "ai_reply_you": "AI replied to you, let's chat~", + "ai_setting": "AI setting", + "ai_switch": "AI intelligent understanding of context switch", + "ai_thinking": "AI is thinking...", + "answer_failed": "Answer failed", + "basic_data_get": "Basic data acquisition", + "basic_data_get_done": "Basic data acquisition completed", + "blog": "Blog", + "chat_channel": "Chat channel", + "chat_comm": "Chat", + "chat_gpt": "ChatGPT", + "clear_log": "Clear log", + "click_choose_file": "Click to select a file, or drag the file here to support multi-file drag and drop sending. After re-selecting the file, the previously selected file will be overwritten", + "click_download": "Click me to download", + "click_to_stop_live": "Start live, click the button again to end the live", + "click_to_stop_recording": "Start recording, click to stop recording again", + "click_to_stop_sharing": "Start screen sharing, click the button again to stop sharing", + "click_to_stop_video": "Start audio and video calls, click the button again to hang up", + "collapse_live": "Collapse live panel", + "collapse_log": "Collapse log panel", + "collapse_receive_file": "Collapse receive file panel", + "collapse_screen_sharing": "Collapse screen sharing panel", + "collapse_selected_file": "Collapse selected file panel", + "collapse_send_file_record": "Collapse send file record panel", + "collapse_temporary": "Collapse the temporary file panel", + "collapse_video": "Collapse video panel", + "collapse_wait_send_file": "Collapse wait send file panel", + "common_event_init": "Common event initialization", + "common_event_init_done": "Common event initialization completed", + "communication_rational": "Civilized speech, rational communication", + "confirm": "Confirm", + "connection_closed": "Connection closed", + "connection_disconnected": "Connection disconnected", + "content_max_1000": "The content is too long, it cannot exceed 1000 characters", + "content_max_10000": "The text content is too long, the length is up to 10000 words", + "copy_room_link": "Copy room link successfully", + "create_join_room": "Create/join room", + "cur_selected_file": "Current selected file list", + "current_network": "The current network status is", + "current_number": "Current number", + "current_relay_status": "Current relay service status", + "custom_data_receive_channel_closed": "The custom data receive channel is closed", + "custom_data_receive_channel_ready": "The custom data receive channel is ready", + "debug_init": "Debug initialization", + "debug_init_done": "Debug initialization completed", + "demo_site": "This website is a demo site, only provides availability demonstration, duration 15 seconds, automatic end of demonstration, if you need to use please deploy it yourself", + "disclaimer": "Disclaimer", + "donate": "Donate", + "download": "Download", + "end_live": "End live", + "end_local_screen_recording": "End local screen recording", + "end_screen_sharing": "End screen sharing", + "end_video_call": "End video call", + "enter_password_room": "Enter the password room, room number", + "enter_send": "ctrl+enter New line | Enter to send", + "establish_connection": "Establish connection", + "event_init": "Event initialization", + "event_init_done": "Event initialization completed", + "expires_one_day" : "Expires after one day", + "exit_room": "Exit room", + "expand_live": "Expand live panel", + "expand_log": "Expand log panel", + "expand_receive_file": "Expand receive file panel", + "expand_screen_sharing": "Expand screen sharing panel", + "expand_selected_file": "Expand selected file panel", + "expand_send_file_record": "Expand send file record panel", + "expand_temporary": "Expand the temporary file panel", + "expand_video": "Expand video panel", + "expand_wait_send_file": "Expand wait send file panel", + "failed_find_file": "Failed, file resource does not exist", + "feature_close": "The current function has been temporarily closed. If you have any questions, you can add a group to communicate", + "feedback": "Feedback", + "file_box": "File box", + "file_from": "File from", + "file_not_exist": "File read failed, file resource does not exist", + "file_receive": "Receive file", + "file_receive_channel_closed": "The file receive channel is closed", + "file_receive_channel_ready": "The file receive channel is ready", + "file_room": "File room", + "file_select_init": "File select initialization", + "file_select_init_done": "File select initialization completed", + "file_send_channel_buffer_full": "The file send channel buffer is full, waiting...", + "file_send_channel_buffer_recover": "The file send channel buffer has been restored, continue to send", + "file_send_channel_not_establish": "When sending a file, the file sending channel is not established", + "file_send_done": "File send done", + "file_send_record": "File sending record", + "generate_send_file_record": "Generate send file record", + "get_device_failed": "Failed to get device recording permission", + "get_pickup_file": "Get files through pickup code", + "give_coffee": "Buy me a coffee", + "home": "Official website homepage", + "history_msg" : " History messages", + "i_said_to_ai": "I said to AI", + "illegal_event": "Illegal trigger event", + "in_living": "Currently live, please try again after exiting", + "in_sharing_screen": "Currently sharing the screen, please try again after exiting", + "in_videoing": "Currently in a video call, please try again after exiting", + "init_language_done": "Initialize the language version", + "input_room_num": "Input room number", + "is_pickup_code": "Whether to pick up the pickup code", + "is_screen_recording": "Whether to perform local screen recording", + "join_room": "Join room", + "language_select_init": "Language select initialization", + "language_select_init_done": "Language select initialization completed", + "live_done": "The live broadcast is over, the live broadcast time is ", + "living": "Living", + "log": "Execution log", + "max_previewed": "The maximum can only be previewed", + "max_saved": "The maximum can only be temporarily stored", + "mb_file": "MB's file", + "message_box_init": "Message box initialization", + "message_box_init_done": "Message box initialization completed", + "mobile_data": "Mobile data", + "mobile_not_support_recording": "Mobile does not support screen recording for the time being", + "name": "Name", + "no_code_file": "This pickup code has no file record temporarily", + "no_device": "No camera or microphone detected", + "no_notice": "No announcement", + "no_received_file": "No files received temporarily", + "no_send_file": "No files have been sent temporarily", + "not_support": "Not support", + "note_website_for_learing": "Note: The sample site is for learning purposes only, please do not use it for other purposes", + "notice": "notice", + "off": "Off", + "offer_failed": "Offer failed", + "on": "On", + "online": "Current online number", + "online_number": "Online number", + "only_show_10_history_msg": "Only show 10 history messages", + "only_show" : "Only show ", + "op_log": "Operation log", + "open_ai_chat": "Open AI chat window", + "open_ai_switch": "The synchronization context switch has been turned on, and AI can better understand your questions, but it may also cause the answer to become unpredictable, and you can turn it off in the settings", + "open_donate": "Open donate window", + "open_private_chat": "Open private chat panel", + "open_public_chat_panel": "Open public chat panel", + "open_relay_setting": "Open relay setting window", + "open_room_chat_panel": "Open room chat panel", + "open_setting": "Open setting window", + "open_share_join_room": "Open share join room window", + "open_share_pickup_code": "Open the window to share the pickup code", + "other_language": "Other language", + "owner" : "Owner", + "p2p_check": "P2p check", + "p2p_check_principle": "P2p detection principle", + "p2p_check_principle_detail": "This project is based on webrtc, and webrtc's p2p is limited by the connection", + "p2p_check_principle_detail_10": "Please search for the keyword 'IP' in the execution log to see if there is a similar intranet format IP", + "p2p_check_principle_detail_2": "The network NAT type and browser restrictions of both parties", + "p2p_check_principle_detail_3": "Self-check steps", + "p2p_check_principle_detail_4": "Before verifying p2p,", + "p2p_check_principle_detail_5": "Please turn off the relay service switch first", + "p2p_check_principle_detail_6": ", Both parties enter the room, and then perform self-check", + "p2p_check_principle_detail_7": "After both parties join the room, if the client can obtain the intranet IP of both parties in the room, it is highly probable that p2p transmission can be performed", + "p2p_check_principle_detail_8": "If it is chrome PC version, you can open", + "p2p_check_principle_detail_9": "Then search for the keyword 'mdns', turn on the switch and restart", + "password": "Password", + "password_room": "Password", + "password_too_long": "The password is too long", + "pickup_code": "Code", + "please_describe_your_feedback": "Please describe the problem you need to feedback", + "please_enter": "Please enter", + "please_enter_code": "Please enter the pickup code", + "please_enter_content": "Please enter text content", + "please_enter_live_room_num": "Please enter the live room number", + "please_enter_password": "Please enter the password room password", + "please_enter_right_code": "Please enter the correct pickup code", + "please_enter_room_num": "Please fill in the room number first", + "please_enter_screen_sharing_room_num": "Please enter the screen sharing room number", + "please_enter_video_call_room_num": "Please enter the audio and video call room number", + "please_exit_then_join_live": "Please exit the room first and then enter the live room", + "please_exit_then_join_password_room": "Please exit the room first and then enter the password room", + "please_exit_then_join_screen": "Please exit the room first and then initiate screen sharing", + "please_exit_then_join_video": "Please exit the room first and then initiate a video call", + "please_fill_content": "Please fill in the content first", + "please_join_then_chat": "Please join the room first and then speak", + "please_join_then_chat_with_ai": "Please join the room first and then chat with AI", + "please_join_then_choose_file": "Please join the room first and then select the file", + "please_join_then_draw": "Please join the room first and then open the remote whiteboard", + "please_join_then_send": "Please join the room first and then send the content", + "preview": "Preview", + "preview_file": "Preview file", + "preview_not_supported": "This format file is not supported for preview", + "print_logo": "Print logo", + "private_chat": "Private chat", + "public_channel_send_done": "Public channel send successfully", + "public_chat_channel": "Public chat channel", + "public_chat_channel_someone_interact": "Someone interacted in the public chat channel, go and see", + "qq": "QQ communication group", + "query_log": "Keyword query log", + "read_file_error": "Read file error", + "read_file_interrupt": "Read file interrupt", + "receive_ack": "Receive ack, ready to send to", + "receive_answer_event": "Receive answer event", + "receive_candidate_event": "Receive candidate event", + "receive_create_room_event": "Receive create room event", + "receive_done": "Receive done", + "receive_file_list": "Received file list", + "receive_join_room_event": "Receive join room event", + "receive_offer_event": "Receive offer event", + "receive_temporary_link": "Receive temporary link", + "received": "Received", + "recording_done": "Recording completed, please check in the received file list", + "recording_incomplete": "Screen recording is complete! It is detected that the recording is incomplete. If you need to stop recording, please click the stop button on this page to stop recording", + "refresh_random_room_num_init": "Refresh random room number initialization", + "refresh_random_room_num_init_done": "Refresh random room number initialization completed", + "refresh_room": "Refresh room", + "relay_on": "The relay server is currently enabled, for more information, please go to settings to view", + "relay_on_and_more_info_in_setting": "The relay server is currently enabled, for more information, please go to settings to view", + "relay_server_current": "The relay server is currently", + "relay_server_current_detail": "Enabling the relay server can ensure that the data is transferred in a complex p2p network environment. If it is disabled, it will be forced to go through p2p (p2p detection can be performed in the settings), which may cause the transmission to fail!", + "relay_setting": "Relay setting", + "remote_draw": "Paint", + "room": "Room", + "room_least_two_can_send_content": "At least two people are required in the room to send content", + "room_least_two_can_send_file": "At least two people are required in the room to send files", + "room_num_no_number": "Room number is not allowed in number", + "room_num_no_special_symbols": "Room number is not allowed in special symbols", + "room_num_no_zh": "Room number is not allowed in Chinese", + "room_num_too_long": "The room number is too long", + "save": "Temporarily save", + "save_fail": "Temporarily saved failed", + "save_failed": "Temporarily save failed", + "save_ok": "Temporarily saved successfully", + "saved": "Temporarily saved", + "saving": "Temporarily save", + "screen_recording": "Record", + "screen_sharing": "Screen", + "second": "second", + "select_wait_send_record": "Select wait send record...", + "selected_file": "Selected file", + "selected_file_exist": "The selected file already exists with the same file and will not be added again", + "self": "Myself", + "send": "Send", + "send_all": "Send all", + "send_alone": "Send alone", + "send_bug_info_ok": "The feedback was successful, and more questions can be added to the group to communicate, which will solve your problem faster", + "send_cancel": "Send canceled", + "send_chat": "Chat", + "send_file": "Send file", + "send_file_record_exist": "The same file record already exists and will not be added again", + "send_text": "Send text", + "send_to": "Send to", + "send_to_user_separately": "Send to user separately", + "sending": "Sending", + "sending_history": "File sending history", + "sending_to": "Sending to", + "sent": "Sent", + "setting": "Setting", + "share_init": "Share initialization", + "share_init_done": "Share initialization completed", + "share_join_room": "Share join room", + "share_join_room_done": "Share auto join room link copied", + "share_link": "Share room link", + "share_pickup_code": "Share pickup code", + "share_pickup_code_file": "Share pickup code file", + "sharing": "Sharing", + "sharing_done": "Screen sharing is over, this sharing time is ", + "size": "Size", + "slider_init": "Slider initialization", + "slider_init_done": "Slider initialization completed", + "socket_init": "Socket initialization", + "socket_init_done": "Socket initialization completed", + "start_live": "Live", + "start_local_screen_recording": "Start local screen recording", + "start_screen_sharing": "Start screen sharing", + "start_video_call": "Start video call", + "stream_room": "Stream room", + "support": "Support", + "sys_log": "System log", + "temporary_link_empty": "Temporary link empty", + "text_decode_failed": "Text decode failed", + "text_send_done": "Text content sent", + "time": "Time", + "timer": "Timer", + "total": "Total", + "total_pickup_file": "Total received temporary files", + "try_open_ai_switch": "You can try to turn on the synchronization context switch in the settings to help AI better understand your questions coherently", + "type": "Type", + "unknown_type": "Unknown type", + "user": "User", + "video_call": "Video", + "video_done": "Audio and video calls are over, this call time is ", + "videoing": "Videoing", + "view_pickup_code": "View pickup code", + "wait": "Waiting", + "wait_ack": "Waiting for ack...", + "wait_sending": "Pending", + "web_screen_recording": "Web screen recording", + "webrtc_check": "Webrtc check", + "website_agreement_statement": "Demo website/open source project agreement statement", + "will_send": "Will send", + "window_event_init": "Window event initialization", + "window_event_init_done": "Window event initialization completed", + "you_enter_file_room": "You entered the file room", + "you_enter_password_room": "You entered the password room", + "you_enter_stream_room": "You entered the stream room", + "you_join_room": "You joined the room number through sharing", + "you_refresh_room": "You refreshed the room number, the current room number is", + "your_browser": "Your browser", + "your_ip_list": "Your IP list is", + }, + "zh": { + "add_ice_candidate_failed": "addIceCandidate失败", + "add_ice_candidate_success": "addIceCandidateSuccess成功", + "ai_answering": "AI正在回答您的问题,请稍后再问", + "ai_chat": "AI智能对话", + "ai_chat_record": "AI聊天记录", + "ai_reply": "AI回复", + "ai_reply_you": "AI回复了你,快点聊起来吧~", + "ai_setting": "智能理解", + "ai_switch": "AI智能理解上下文开关", + "ai_thinking": "AI思考中", + "answer_failed": "answer失败", + "basic_data_get": "基础数据 获取中", + "basic_data_get_done": "基础数据 获取完成", + "blog": "博客", + "chat_channel": "聊天频道", + "chat_comm": "公共聊天", + "chat_gpt": "ChatGPT", + "clear_log": "清空日志", + "click_choose_file": "点击选择文件,或将文件拖到此处支持多文件拖放发送。重新选择文件后,之前选择的文件将被覆盖", + "click_download": "点击下载", + "click_to_stop_live": "开始直播,再次点击按钮结束直播", + "click_to_stop_recording": "开始录制,再次点击停止录制", + "click_to_stop_sharing": "开始屏幕共享,再次点击按钮停止共享", + "click_to_stop_video": "开始音视频通话,再次点击按钮挂断通话", + "collapse_live": "收起直播面板", + "collapse_log": "收起日志面板", + "collapse_receive_file": "收起已接收文件面板", + "collapse_screen_sharing": "收起屏幕共享面板", + "collapse_selected_file": "收起已选文件面板", + "collapse_send_file_record": "收起发送文件记录面板", + "collapse_temporary": "折叠临时文件面板", + "collapse_video": "收起音视频面板", + "collapse_wait_send_file": "收起待发送文件面板", + "common_event_init": "公共事件监听 初始化中", + "common_event_init_done": "公共事件监听 初始化完成", + "communication_rational": "文明发言,理性交流", + "confirm": "确定", + "connection_closed": "连接关闭", + "connection_disconnected": "连接断开", + "content_max_1000": "内容过长,不能超过1000个字符", + "content_max_10000": "文本内容过长,长度最多为10000字", + "copy_room_link": "房间链接已成功复制", + "create_join_room": "创建/加入房间", + "cur_selected_file": "当前选择的文件列表", + "current_network": "当前网络状态为", + "current_number": "当前人数", + "current_relay_status": "当前中继服务状态", + "custom_data_receive_channel_closed": "自定义数据接收管道已关闭", + "custom_data_receive_channel_ready": "自定义数据接收管道已就绪", + "debug_init": "DEBUG组件 初始化中", + "debug_init_done": "DEBUG组件 初始化完成", + "demo_site": "本网站为演示站点,仅提供可用性演示,时长15秒,自动结束演示,如需使用请自行部署使用", + "disclaimer": "免责声明", + "donate": "捐赠", + "download": "下载", + "end_live": "结束直播", + "end_local_screen_recording": "结束本地屏幕录制", + "end_screen_sharing": "结束远程屏幕共享", + "end_video_call": "结束音视频通话", + "enter_password_room": "进入密码房间,房间号", + "enter_send": "ctrl+enter 换行 | Enter 发送", + "establish_connection": "建立连接", + "event_init": "事件监听组件 初始化中", + "event_init_done": "事件监听组件 初始化完成", + "expires_one_day" : "一天后过期", + "exit_room": "退出房间", + "expand_live": "展开直播面板", + "expand_log": "展开日志面板", + "expand_receive_file": "展开已接收文件面板", + "expand_screen_sharing": "展开屏幕共享面板", + "expand_selected_file": "展开已选文件面板", + "expand_send_file_record": "展开发送文件记录面板", + "expand_temporary": "展开临时文件面板", + "expand_video": "展开音视频面板", + "expand_wait_send_file": "展开待发送文件面板", + "failed_find_file": "失败,文件资源不存在", + "feature_close": "当前功能暂时关闭。如果您有任何问题,可以加入群组进行交流", + "feedback": "反馈问题", + "file_box": "文件箱", + "file_from": "文件来自", + "file_not_exist": "文件读取失败,文件资源不存在", + "file_receive": "接收文件", + "file_receive_channel_closed": "文件接收管道已关闭", + "file_receive_channel_ready": "文件接收管道已就绪", + "file_room": "文件房间", + "file_select_init": "文件选择组件 初始化中", + "file_select_init_done": "文件选择组件 初始化完成", + "file_send_channel_buffer_full": "文件发送管道缓冲区已满,等待中", + "file_send_channel_buffer_recover": "文件发送管道缓冲区已恢复,继续发送中", + "file_send_channel_not_establish": "发送文件时,文件发送管道未建立", + "file_send_done": "文件全部发送完毕", + "file_send_record": "文件发送记录", + "generate_send_file_record": "生成文件发送记录", + "get_device_failed": "获取设备录制权限失败", + "get_pickup_file": "通过取件码获取文件", + "give_coffee": "赞助一杯咖啡", + "history_msg" : " 条历史消息", + "home": "官网首页", + "i_said_to_ai": "我对AI说", + "illegal_event": "非法触发事件", + "in_living": "正在直播中,请退出后再试", + "in_sharing_screen": "正在共享屏幕,请退出后再试", + "in_videoing": "正在视频通话中,请退出后再试", + "init_language_done": "初始化语言版本完成", + "input_room_num": "输入房间编号", + "is_pickup_code": "是否取件码取件", + "is_screen_recording": "是否进行本地屏幕录制", + "join_room": "加入房间", + "language_select_init": "语言选择初始化", + "language_select_init_done": "语言选择初始化完成", + "live_done": "直播已结束,直播时间为", + "living": "直播中", + "log": "执行日志", + "max_previewed": "最多只能预览", + "max_saved": "最多只能临时存储", + "mb_file": "MB的文件", + "message_box_init": "消息弹窗 初始化中", + "message_box_init_done": "消息弹窗 初始化完成", + "mobile_data": "移动数据", + "mobile_not_support_recording": "移动设备暂不支持屏幕录制", + "name": "名称", + "no_code_file": "此取件码暂无文件记录", + "no_device": "未检测到摄像头或麦克风", + "no_notice": "暂无公告", + "no_received_file": "暂时未收到文件", + "no_send_file": "暂时没有发送过文件", + "not_support": "不支持", + "note_website_for_learing": "注意:示例网站仅用于学习演示,请勿他用", + "notice": "通知", + "off": "已关闭", + "offer_failed": "offer失败", + "on": "已开启", + "online": "当前在线人数", + "online_number": "人在线", + "only_show" : "仅展示 ", + "only_show_10_history_msg": "仅展示10条历史消息", + "op_log": "操作日志", + "open_ai_chat": "打开AI聊天窗口", + "open_ai_switch": "已开启同步上下文开关,AI可以更好地理解您的问题,但也可能导致答案变得不可预测,您可以在设置中关闭", + "open_donate": "打开赞助窗口", + "open_private_chat": "打开私聊面板", + "open_public_chat_panel": "打开公共聊天面板", + "open_relay_setting": "打开中继设置窗口", + "open_room_chat_panel": "打开房间聊天面板", + "open_setting": "打开设置窗口", + "open_share_join_room": "打开分享房间窗口", + "open_share_pickup_code": "打开分享取件码窗口", + "other_language": "其他语言", + "owner" : "房主", + "p2p_check": "P2p检测", + "p2p_check_principle": "p2p检测原理", + "p2p_check_principle_detail": "本项目是基于webrtc实现的,webrtc的p2p受限于连接", + "p2p_check_principle_detail_10": "具体是否有获取到双方内网IP,请自行在执行日志中搜索关键字 “IP”,查看是否有类似内网格式的IP即可", + "p2p_check_principle_detail_2": "双方的网络NAT类型和浏览器限制", + "p2p_check_principle_detail_3": "自检步骤", + "p2p_check_principle_detail_4": "在验证p2p之前,", + "p2p_check_principle_detail_5": "请先关闭中继服务开关后", + "p2p_check_principle_detail_6": ",双方进入后房间,再进行自检", + "p2p_check_principle_detail_7": "双方加入房间后,如果客户端可以获取到房间内双方的内网IP,大概率就可以进行p2p传输", + "p2p_check_principle_detail_8": "如果是chrome电脑版,可以打开", + "p2p_check_principle_detail_9": "然后搜索 'mdns' 关键字,打开开关后重启即可", + "password": "密码", + "password_room": "密码房间", + "password_too_long": "密码过长", + "pickup_code": "取件号码", + "please_describe_your_feedback": "请描述您需要反馈的问题", + "please_enter": "请输入", + "please_enter_code": "请输入取件码", + "please_enter_content": "请输入文本内容", + "please_enter_live_room_num": "请输入直播房间号", + "please_enter_password": "请输入密码房间密码", + "please_enter_right_code": "请输入正确的取件码", + "please_enter_room_num": "请先填写房间号", + "please_enter_screen_sharing_room_num": "请输入屏幕共享房间号", + "please_enter_video_call_room_num": "请输入音视频通话房间号", + "please_exit_then_join_live": "请先退出房间,然后进入直播间", + "please_exit_then_join_password_room": "请先退出房间,然后进入密码房间", + "please_exit_then_join_screen": "请先退出房间,然后发起屏幕共享", + "please_exit_then_join_video": "请先退出房间,然后发起视频通话", + "please_fill_content": "请先填写内容", + "please_join_then_chat": "请先加入房间,然后发言", + "please_join_then_chat_with_ai": "请先加入房间,然后与AI聊天", + "please_join_then_choose_file": "请先加入房间,然后选择文件", + "please_join_then_draw": "请先加入房间,然后打开远程白板", + "please_join_then_send": "请先加入房间,然后发送内容", + "preview": "预览", + "preview_file": "预览文件", + "preview_not_supported": "不支持此格式文件的预览", + "print_logo": "打印logo", + "private_chat": "私聊", + "public_channel_send_done": "公共频道发言成功", + "public_chat_channel": "公共聊天频道", + "public_chat_channel_someone_interact": "公共聊天频道有人互动啦,快去瞧瞧", + "qq": "QQ交流群", + "query_log": "关键词查询日志", + "read_file_error": "读取文件错误", + "read_file_interrupt": "读取文件中断", + "receive_ack": "收到ack回执,准备发送给", + "receive_answer_event": "收到answer事件", + "receive_candidate_event": "收到candidate事件", + "receive_create_room_event": "收到创建房间事件", + "receive_done": "接收完毕", + "receive_file_list": "接收文件列表", + "receive_join_room_event": "收到加入房间事件", + "receive_offer_event": "收到offer事件", + "receive_temporary_link": "收到暂存链接", + "received": "已接收", + "recording_done": "录制完成,请在接收文件列表中查看", + "recording_incomplete": "屏幕录制已完成!检测到录制不完整,如需停止录制,请点击本页面上的停止按钮停止录制", + "refresh_random_room_num_init": "刷新随机房间号 初始化中", + "refresh_random_room_num_init_done": "刷新随机房间号初始化完成", + "refresh_room": "刷新房间", + "relay_on": "当前已启用中继服务器,有关更多信息,请前往设置查看", + "relay_on_and_more_info_in_setting": "当前已启用中继服务器,有关更多信息,请前往设置查看", + "relay_server_current": "中继服务器当前已", + "relay_server_current_detail": "启用中继服务器可以保证在复杂的p2p网络环境下,提供保底的数据中转传输,如果禁用,则是强制走p2p(可在设置中进行p2p检测),可能会出现发送失败!", + "relay_setting": "中继设置", + "remote_draw": "远程画笔", + "room": "房间", + "room_least_two_can_send_content": "房间内至少需要两人才能发送内容", + "room_least_two_can_send_file": "房间内至少需要两人才能发送文件", + "room_num_no_number": "房间号不允许包含数字", + "room_num_no_special_symbols": "房间号不允许包含特殊符号", + "room_num_no_zh": "房间号不允许包含中文", + "room_num_too_long": "房间号过长", + "save": "暂存", + "save_fail": "临时保存失败", + "save_failed": "暂存失败", + "save_ok": "临时保存成功", + "saved": "已暂存", + "saving": "暂存中", + "screen_recording": "屏幕录制", + "screen_sharing": "屏幕共享", + "second": "秒", + "select_wait_send_record": "选择待发送记录中", + "selected_file": "已选择文件", + "selected_file_exist": "选择的文件已经存在相同的文件,不再重复添加", + "self": "我自己", + "send": "发送", + "send_all": "一键发送", + "send_alone": "单独发送", + "send_bug_info_ok": "反馈成功,更多问题可添加群组进行交流,将更快地解决您的问题", + "send_cancel": "发送已取消", + "send_chat": "发言", + "send_file": "发送文件", + "send_file_record_exist": "已经存在相同的文件记录,不再重复添加", + "send_text": "发送文本", + "send_to": "发送至", + "send_to_user_separately": "分别发送给用户", + "sending": "发送中", + "sending_history": "文件发送历史", + "sending_to": "正在发送给", + "sent": "已发送", + "setting": "设置", + "share_init": "分享组件 初始化中", + "share_init_done": "分享组件 初始化完成", + "share_join_room": "分享加入房间", + "share_join_room_done": "分享自动加入房间链接已复制", + "share_link": "分享房间链接", + "share_pickup_code": "分享取件码", + "share_pickup_code_file": "分享取件码文件", + "sharing": "共享中", + "sharing_done": "屏幕共享已结束,本次共享时间为", + "size": "大小", + "slider_init": "滑动组件 初始化中", + "slider_init_done": "滑动组件 初始化完成", + "socket_init": "SOCKET监听 初始化中", + "socket_init_done": "SOCKET监听 初始化完成", + "start_live": "开始直播", + "start_local_screen_recording": "开始本地屏幕录制", + "start_screen_sharing": "开始远程屏幕共享", + "start_video_call": "开始音视频通话", + "stream_room": "流媒体房间", + "support": "支持", + "sys_log": "系统日志", + "temporary_link_empty": "文件暂存失败, 上传链接为空", + "text_decode_failed": "文本内容解码失败", + "text_send_done": "文本内容已发送", + "time": "时间", + "timer": "计时器", + "total": "总计", + "total_pickup_file": "总计接收的暂存文件", + "try_open_ai_switch": "您可以尝试在设置中打开同步上下文开关,帮助AI更好地理解您的问题的连贯性", + "type": "类型", + "unknown_type": "未知类型", + "user": "用户", + "video_call": "视频通话", + "video_done": "音视频通话已结束,本次通话时间为", + "videoing": "视频中", + "view_pickup_code": "查看取件码", + "wait": "等待中", + "wait_ack": "等待ack回执中", + "wait_sending": "待发送", + "web_screen_recording": "网页录屏", + "webrtc_check": "Webrtc检测", + "website_agreement_statement": "演示网站/开源项目协议声明", + "will_send": "即将发送", + "window_event_init": "窗口事件监听 初始化中", + "window_event_init_done": "窗口事件监听 初始化完成", + "you_enter_file_room": "你进入了文件房间", + "you_enter_password_room": "你进入了密码房间", + "you_enter_stream_room": "你进入了流媒体房间", + "you_join_room": "你通过分享加入了房间号为", + "you_refresh_room": "你刷新了房间号, 当前房间号为", + "your_browser": "您的浏览器", + "your_ip_list": "你的IP列表为" + } +} + +window.local_lang = local_lang; \ No newline at end of file diff --git a/svr/res/js/liveShare.js b/svr/res/js/liveShare.js index 1f44615..d8be7fd 100644 --- a/svr/res/js/liveShare.js +++ b/svr/res/js/liveShare.js @@ -1,3 +1,9 @@ +// --------------------------- // +// -- liveShare.js -- // +// -- version : 1.0.0 -- // +// -- date : 2023-06-22 -- // +// --------------------------- // + var liveShare = new Vue({ el: '#liveShareApp', data: function () { @@ -106,9 +112,17 @@ var liveShare = new Vue({ $("#liveShareIcon").css("color", "#fb0404") $("#liveShareTimes").css("color", "#fb0404") setTimeout(() => { - $("#liveShareIcon").css("color", "#ffffff") - $("#liveShareTimes").css("color", "#ffffff") + $("#liveShareIcon").css("color", "#000000") + $("#liveShareTimes").css("color", "#000000") }, 500) + + if(that.times >= 15){ + that.stopLiveShare(); + setTimeout(() => { + window.location.reload(); + }, 1000); + return + } }, 1000); if (window.layer) { diff --git a/svr/res/js/screen.js b/svr/res/js/screen.js index 2cb25c9..8ce4ffe 100644 --- a/svr/res/js/screen.js +++ b/svr/res/js/screen.js @@ -1,14 +1,30 @@ -var screen = new Vue({ +// --------------------------- // +// -- screen.js -- // +// -- version : 1.0.0 -- // +// -- date : 2023-06-22 -- // +// --------------------------- // + +const screen = new Vue({ el: '#screenApp', data: function () { return { - stream: null, - chunks: [], - mediaRecorder: null, - recording: null, - times: 0, - interverlId: 0, - size: 0, + stream: null, //录制流 + chunks: [], //录制数据 + mediaRecorder: null, //录制对象 + recording: null, //录制文件 + times: 0, //录制时间 + interverlId: 0, //计时器id + size: 0, //录制文件大小 + isScreen : false, //是否正在录制 + } + }, + watch: { + isScreen: function (val, oldVal) { + if (val) { + $("#screenTimes").css("display", "contents"); + } else { + $("#screenTimes").css("display", "none"); + } } }, methods: { @@ -26,6 +42,22 @@ var screen = new Vue({ }) } }, + openLocalScreen : async function({ + openCallback, closeCallback + }){ + if(!this.isScreen){ + layer.confirm("是否进行本地屏幕录制", (index) => { + this.startScreen(); + this.isScreen = !this.isScreen; + openCallback && openCallback(); + }, (index) => { + layer.close(index) + }) + }else{ + this.stopScreen(closeCallback ? closeCallback : ()=>{}); + this.isScreen = !this.isScreen; + } + }, startScreen: async function () { let that = this; if (this.recording) { @@ -42,10 +74,8 @@ var screen = new Vue({ } if (this.stream == null) { - if (window.layer) { - layer.msg("获取设备录制权限失败") - } - window.Bus.$emit("changeScreenState", false) + layer.msg("获取设备录制权限失败") + this.isScreen = false return; } @@ -61,7 +91,11 @@ var screen = new Vue({ //计算时间 this.interverlId = setInterval(() => { that.times += 1; - window.Bus.$emit("changeScreenTimes", that.times) + if(that.times < 10){ + $("#screenTimes").text("录制中: 0" + that.times + "秒") + }else{ + $("#screenTimes").text("录制中: "+that.times + "秒") + } $("#screenIcon").css("color","#fb0404") $("#screenTimes").css("color","#fb0404") setTimeout(() => { @@ -80,9 +114,7 @@ var screen = new Vue({ try { this.mediaRecorder.stop(); } catch (e) { - if (window.layer) { - layer.msg("屏幕录制完毕! 检测到录制不完整,如需停止录制,请点击本页面的停止按钮来停止录制") - } + layer.msg("屏幕录制完毕! 检测到录制不完整,如需停止录制,请点击本页面的停止按钮来停止录制") hasErr = true } @@ -109,7 +141,7 @@ var screen = new Vue({ callback(data) - if (window.layer && !hasErr) { + if (!hasErr) { layer.msg("录制完成,请在接收文件列表查看") } @@ -121,7 +153,6 @@ var screen = new Vue({ }, }, mounted: function () { - window.Bus.$on("startScreen", this.startScreen); - window.Bus.$on("stopScreen", this.stopScreen); + window.Bus.$on("openLocalScreen", this.openLocalScreen); } }) \ No newline at end of file diff --git a/svr/res/js/screenShare.js b/svr/res/js/screenShare.js index 5169617..15a127d 100644 --- a/svr/res/js/screenShare.js +++ b/svr/res/js/screenShare.js @@ -1,3 +1,10 @@ +// --------------------------- // +// -- screenShare.js -- // +// -- version : 1.0.0 -- // +// -- date : 2023-06-22 -- // +// --------------------------- // + + var screenShare = new Vue({ el: '#screenShareApp', data: function () { @@ -75,9 +82,17 @@ var screenShare = new Vue({ $("#screenShareIcon").css("color","#fb0404") $("#screenShareTimes").css("color","#fb0404") setTimeout(() => { - $("#screenShareIcon").css("color","#ffffff") - $("#screenShareTimes").css("color","#ffffff") + $("#screenShareIcon").css("color","#000000") + $("#screenShareTimes").css("color","#000000") }, 500) + + if(that.times >= 15){ + that.stopScreenShare(); + setTimeout(() => { + window.location.reload(); + }, 1000); + return + } }, 1000); if (window.layer) { diff --git a/svr/res/js/videoShare.js b/svr/res/js/videoShare.js index 3ffc4d8..e104595 100644 --- a/svr/res/js/videoShare.js +++ b/svr/res/js/videoShare.js @@ -1,3 +1,9 @@ +// --------------------------- // +// -- videoShare.js -- // +// -- version : 1.0.0 -- // +// -- date : 2023-06-22 -- // +// --------------------------- // + var videoShare = new Vue({ el: '#videoShareApp', data: function () { @@ -106,9 +112,17 @@ var videoShare = new Vue({ $("#videoShareIcon").css("color", "#fb0404") $("#videoShareTimes").css("color", "#fb0404") setTimeout(() => { - $("#videoShareIcon").css("color", "#ffffff") - $("#videoShareTimes").css("color", "#ffffff") + $("#videoShareIcon").css("color", "#000000") + $("#videoShareTimes").css("color", "#000000") }, 500) + + if(that.times >= 15){ + that.stopVideoShare(); + setTimeout(() => { + window.location.reload(); + }, 1000); + return + } }, 1000); if (window.layer) { diff --git a/svr/res/pay.html b/svr/res/pay.html index 91aa7ea..e338466 100644 --- a/svr/res/pay.html +++ b/svr/res/pay.html @@ -48,19 +48,19 @@

GitHub:https://github.com/iamtsm

项目定制服务

- -

1. 项目功能定制

+ +

1. 定制开发支持

+
    +
  • 服务内容:提供定制开发技术支持,可协助部署安装相关事项,或协助自行开发,细节问题答疑
  • +
  • 免费:非常乐意为各位使用的小伙伴提供帮助,大家觉得好用的同时可以点击start支持下
  • +
+ +

2. 项目功能定制

  • 服务内容:对项目进行功能定制或扩展
  • 价格:按功能大小,紧急程度,耗时,定制内容是否允许开源,等情况收费
-

2. 定制开发支持

-
    -
  • 服务内容:提供定制开发技术支持,可协助部署安装相关事项,或协助自行开发,细节问题答疑
  • -
  • 价格:一杯咖啡
  • -
-

收费模式

  • 按小时计费:根据实际工作时间计算费用,目前个人定制功能2小时起,每小时200~300,企业定制另谈
  • diff --git a/svr/src/bussiness/manage/settingPage.js b/svr/src/bussiness/manage/settingPage.js index 9c7d57b..db79573 100644 --- a/svr/src/bussiness/manage/settingPage.js +++ b/svr/src/bussiness/manage/settingPage.js @@ -79,6 +79,11 @@ async function getSettingPageHtml(data) {
+
+
+ +
+
@@ -175,22 +180,29 @@ async function getSettingPageHtml(data) {
-
数据传输公告设置
+
其他设置
-
- - +
+
数据传输公告设置:
+
+
+
+
+
公共聊天记录数量:
+ +
+
+
+
-
@@ -209,7 +221,8 @@ async function getSettingPageHtml(data) { noticeMsg = switchData.noticeMsgList[0].msg } form.val("notice-form",{ - noticeMsg : noticeMsg + noticeMsg : noticeMsg, + chatingCommCount : switchData.chatingCommCount }) form.on('checkbox()', function(data){ @@ -226,6 +239,7 @@ async function getSettingPageHtml(data) { switchData.noticeMsgList = [{ msg : data.field.noticeMsg }] + switchData.chatingCommCount = parseInt(data.field.chatingCommCount) window.manageChange({ id : ${resData.id}, content : switchData diff --git a/svr/src/bussiness/notify/notifyHandler.js b/svr/src/bussiness/notify/notifyHandler.js index 1091d68..8fa2172 100644 --- a/svr/src/bussiness/notify/notifyHandler.js +++ b/svr/src/bussiness/notify/notifyHandler.js @@ -12,7 +12,7 @@ function sendChatingNotify(data) { `库记录ID: ${data.recoderId}\n` + `消息体ID: ${data.msgRecoderId}\n` + `发送方ID: ${data.socketId}\n` + - `文本内容: ${decodeURIComponent(data.msg)}\n` + + `文本内容: ${utils.unescapeStr(data.msg)}\n` + `当前时间: ${utils.formateDateTime(new Date(), "yyyy-MM-dd hh:mm:ss")}\n` + `访问IP: ${data.ip}\n` + `访问设备: ${data.userAgent}\n`; @@ -67,7 +67,7 @@ function sendChatingRoomNotify(data) { ` - ${data.room}\n` + `库记录ID: ${data.recoderId}\n` + `发送方ID: ${data.from}\n` + - `文本内容: ${decodeURIComponent(data.content)}\n` + + `文本内容: ${utils.unescapeStr(data.content)}\n` + `当前时间: ${utils.formateDateTime(new Date(), "yyyy-MM-dd hh:mm:ss")}\n` + `访问IP: ${data.ip}\n` + `访问设备: ${data.userAgent}\n`; @@ -415,6 +415,35 @@ function sendSystemErrorMsg(data) { } +/** + * 发送开始远程画笔通知 + * @param {*} data + */ +function sendStartRemoteDrawNotify(data) { + let notifyMsg = `## 文件传输通知 - ${data.title}` + + ` - ${data.room}\n` + + `当前时间: ${utils.formateDateTime(new Date(), "yyyy-MM-dd hh:mm:ss")}\n` + + `访问IP: ${data.ip}\n` + + `访问设备: ${data.userAgent}\n`; + notify.requestMsg(notifyMsg) +} + + +/** + * 发送停止远程画笔通知 + * @param {*} data + */ +function sendStopRemoteDrawNotify(data) { + let notifyMsg = `## 文件传输通知 - ${data.title}` + + ` - ${data.room}\n` + + `画笔记录: ${data.drawCount}条\n` + + `当前时间: ${utils.formateDateTime(new Date(), "yyyy-MM-dd hh:mm:ss")}\n` + + `访问IP: ${data.ip}\n` + + `访问设备: ${data.userAgent}\n`; + notify.requestMsg(notifyMsg) +} + + module.exports = { sendExitRoomNotify, sendCreateJoinRoomNotify, @@ -441,5 +470,7 @@ module.exports = { addCodeFileNotify, getCodeFileNotify, prepareCodeFileNotify, - sendSystemErrorMsg + sendSystemErrorMsg, + sendStartRemoteDrawNotify, + sendStopRemoteDrawNotify } \ No newline at end of file diff --git a/svr/src/bussiness/oss/oss.js b/svr/src/bussiness/oss/oss.js index e69de29..39d0fe9 100644 --- a/svr/src/bussiness/oss/oss.js +++ b/svr/src/bussiness/oss/oss.js @@ -0,0 +1,33 @@ +const aly = require('./aly'); +const tx = require('./tx'); +const qiniu = require('./qiniu'); +const seafile = require('./seafile'); +const cfg = require('./../../../conf/cfg.json'); + +const oss = { + aly, + tx, + qiniu, + seafile, +} + +/** + * 获取上传token + */ +const getUploadToken = async function(){ + +} + +/** + * 获取上传url + */ +const getUploadUrl = async function(){ + +} + +/** + * 获取下载url + */ +const getDownLoadUrl = async function(){ + +} \ No newline at end of file diff --git a/svr/src/bussiness/oss/seafile.js b/svr/src/bussiness/oss/seafile.js index 6ec419a..6d36751 100644 --- a/svr/src/bussiness/oss/seafile.js +++ b/svr/src/bussiness/oss/seafile.js @@ -9,8 +9,8 @@ const seafile = require('../../../conf/cfg.json').oss.seafile /** * 获取token */ -function seafileGetToken() { - return new Promise(resolve => { +async function seafileGetToken() { + return await new Promise(resolve => { request({ url: `${seafile.host}/api2/auth-token/`, method: "POST", @@ -31,32 +31,14 @@ function seafileGetToken() { }) } -/** - * 服务是否正常 - * @param {*} token - * @returns - */ -function seafilePingPong(token) { - return new Promise(resolve => { - request({ - url: `${seafile.host}/api2/ping/`, - method: "GET", - headers: { - "Authorization": `Token ${token}` - }, - }, function (error, response, body) { - resolve(body) - }); - }) -} /** * 获取上传链接 * @param {*} token * @returns */ -function seafileGetUploadLink(token) { - return new Promise(resolve => { +async function seafileGetUploadLink(token) { + return await new Promise(resolve => { request({ url: `${seafile.host}/api2/repos/${seafile.repoid}/upload-link/`, method: "GET", @@ -69,45 +51,15 @@ function seafileGetUploadLink(token) { }) } -/** - * 上传文件 - * @param {*} token - * @param {*} link - * @returns - */ -function seafileUpload(token, options) { - return new Promise(resolve => { - request({ - url: `${options.link}?ret-json=1`, - method: "POST", - headers: { - "content-type": "application/json", - "Authorization": `Token ${token}` - }, - body: JSON.stringify({ - replace: options.replace, - file: options.file, - parent_dir: options.parent_dir - }) - }, function (error, response, body) { - if (body) { - resolve(JSON.parse(body)) - } else { - resolve(undefined) - } - }); - }) -} - /** - * 创建分享链接 + * 获取直接下载链接 * @param {*} token - * @param {*} name + * @param {*} options * @returns */ -function seafileCreateShareLink(token, options) { - return new Promise(resolve => { +async function seafileGetDownLoadLink(token, options) { + return await new Promise(resolve => { request({ url: `${seafile.host}/api/v2.1/share-links/`, method: "POST", @@ -126,7 +78,14 @@ function seafileCreateShareLink(token, options) { }) }, function (error, response, body) { if (body) { - resolve(JSON.parse(body)) + let data = JSON.parse(body); + if(data){ + resolve({ + downloadLink : `${seafile.host}/f/${data.token}/?dl=1`, + }) + }else{ + resolve(undefined) + } } else { resolve(undefined) } @@ -134,45 +93,8 @@ function seafileCreateShareLink(token, options) { }) } - -/** - * 删除分享链接 - * @param {*} token - * @param {*} name - * @returns - */ -function seafileDeleteShareLink(token, shareLinkToken) { - return new Promise(resolve => { - request({ - url: `${seafile.host}/api/v2.1/share-links/${shareLinkToken}/`, - method: "POST", - headers: { - "Authorization": `Token ${token}` - }, - }, function (error, response, body) { - resolve(body) - }); - }) -} - - -/** - * 获取直接下载链接 - * @param {*} token - * @param {*} name - * @returns - */ -function seafileGetDownLoadLink(shareLinkToken) { - return `${seafile.host}/f/${shareLinkToken}/?dl=1`; -} - - module.exports = { seafileGetToken, - seafilePingPong, - seafileCreateShareLink, - seafileGetDownLoadLink, - seafileDeleteShareLink, seafileGetUploadLink, - seafileUpload + seafileGetDownLoadLink, } \ No newline at end of file diff --git a/svr/src/bussiness/oss/tx.js b/svr/src/bussiness/oss/tx.js new file mode 100644 index 0000000..8e56d37 --- /dev/null +++ b/svr/src/bussiness/oss/tx.js @@ -0,0 +1,4 @@ +/** + * oss tx api + * @author iamtsm + */ \ No newline at end of file diff --git a/svr/src/controller/check/check.js b/svr/src/controller/check/check.js new file mode 100644 index 0000000..fab2667 --- /dev/null +++ b/svr/src/controller/check/check.js @@ -0,0 +1,32 @@ +const check = require("../../utils/check/content"); + +/** + * 检查内容 + * @param {*} req + * @param {*} res + * @returns + */ +function checkContent(req, res) { + try { + let content = req.query.content; + if(content.length > 1000){ + res.json({ + content: "内容过长" + }) + return; + } + res.json({ + content: check.contentFilter(content) + }) + } catch (err) { + console.log(err); + res.json({ + content: "", + err : "系统繁忙" + }) + } +} + +module.exports = { + checkContent +} \ No newline at end of file diff --git a/svr/src/controller/check/index.js b/svr/src/controller/check/index.js new file mode 100644 index 0000000..52b47ff --- /dev/null +++ b/svr/src/controller/check/index.js @@ -0,0 +1,11 @@ +const express = require('express'); +const check = require("./check"); + + +module.exports = function () { + const router = express.Router(); + + router.get("/check", check.checkContent); + + return router; +} \ No newline at end of file diff --git a/svr/src/controller/comm/comm.js b/svr/src/controller/comm/comm.js index d395ae2..29c420a 100644 --- a/svr/src/controller/comm/comm.js +++ b/svr/src/controller/comm/comm.js @@ -8,6 +8,13 @@ const webrtcConf = conf.webrtc; * @param {*} res */ function initData(req, res) { + //是否开启turn + const openTurn = (req.query.turn || "") === 'true'; + //使用的账号模式, true : 有效账号模式, false : 固定账号 + const useSecret = (req.query.secret || "") === 'true'; + + //ice服务器配置 + const iceServers = utils.genTurnServerIceServersConfig(openTurn, useSecret, "tlrtcfile"); if(process.env.ENV_MODE === 'local'){ @@ -21,18 +28,22 @@ function initData(req, res) { } let data = { + version : conf.version, wsHost: conf.ws.host || ip, - rtcConfig: { iceServers: webrtcConf.iceServers }, - options: webrtcConf.options + rtcConfig: { iceServers }, + options: webrtcConf.options, + logo : utils.genClientLogo(), }; res.json(data) }else if(process.env.ENV_MODE === 'server'){ let data = { + version : conf.version, wsHost: conf.wss.host, - rtcConfig: { iceServers: webrtcConf.iceServers }, - options: webrtcConf.options + rtcConfig: { iceServers }, + options: webrtcConf.options, + logo : utils.genClientLogo(), }; res.json(data) diff --git a/svr/src/dao/dog/dog.js b/svr/src/dao/dog/dog.js index 7716501..3848c66 100644 --- a/svr/src/dao/dog/dog.js +++ b/svr/src/dao/dog/dog.js @@ -98,7 +98,6 @@ async function getDogManageInfo(params, tables, dbClient) { }) data.transferFileSizeTodady = parseInt(data.transferFileSizeTodady / 1024 / 1024) - //发送文本内容 let txtTransferList = transferListToday.filter(element => { return element.name === '发送文本内容' @@ -108,7 +107,7 @@ async function getDogManageInfo(params, tables, dbClient) { let content = JSON.parse(element.content); data.txtList.push({ room: element.room_id || content.room, - content: decodeURIComponent(content.content), + content: utils.unescapeStr(content.content), size: content.content.length, createTime: utils.formateDateTime(new Date(element.created_at), "yyyy-MM-dd hh:mm:ss"), }) @@ -184,7 +183,7 @@ async function getDogManageInfo(params, tables, dbClient) { * @param {*} dbClient * @returns */ -async function getDogChating10Info(params, tables, dbClient) { +async function getDogChatingCommInfo(params, tables, dbClient) { try{ if(!tables || !dbClient){ return []; @@ -220,7 +219,7 @@ async function getDogChating10Info(params, tables, dbClient) { module.exports = dbOpen ? { addDogData, getDogManageInfo, - getDogChating10Info, + getDogChatingCommInfo, } : { addDogData : () => { return {} @@ -228,7 +227,7 @@ module.exports = dbOpen ? { getDogManageInfo : () => { return {} }, - getDogChating10Info : () => { + getDogChatingCommInfo : () => { return []; }, } \ No newline at end of file diff --git a/svr/src/dao/room/room.js b/svr/src/dao/room/room.js index 5750687..18cd28d 100644 --- a/svr/src/dao/room/room.js +++ b/svr/src/dao/room/room.js @@ -14,6 +14,7 @@ const defaultSwitchData = { openGetCodeFile: true, openVideoShare: true, openLiveShare: true, + openRemoteDraw: true, openPasswordRoom: true, openScreenShare: true, openFileTransfer: true, @@ -28,6 +29,7 @@ const defaultSwitchData = { allowChinese: true, allowSymbol: true, noticeMsgList: [], + chatingCommCount : 10, } diff --git a/svr/src/socket/rtcChatingComm/chatingComm.js b/svr/src/socket/rtcChatingComm/chatingComm.js index b57b545..012d27c 100644 --- a/svr/src/socket/rtcChatingComm/chatingComm.js +++ b/svr/src/socket/rtcChatingComm/chatingComm.js @@ -4,7 +4,7 @@ const rtcCommData = require("../rtcCommData/commData"); const utils = require("../../utils/utils"); const rtcConstant = require("../rtcConstant"); const rtcClientEvent = rtcConstant.rtcClientEvent - +const check = require("../../utils/check/content"); /** * 公共聊天频道 * @param {*} io socketio对象 @@ -16,6 +16,8 @@ const rtcClientEvent = rtcConstant.rtcClientEvent */ async function chatingComm(io, socket, tables, dbClient, data){ try { + data.msg = check.contentFilter(data.msg); + let cacheSwitchData = rtcCommData.getCacheSwitchData() let chatingComm = rtcCommData.getChatingComm() @@ -30,7 +32,7 @@ async function chatingComm(io, socket, tables, dbClient, data){ data.time = new Date().toLocaleString() - if (chatingComm.length < 10) { + if (chatingComm.length < (cacheSwitchData.chatingCommCount || 10)) { chatingComm.push(data) } else { chatingComm.shift() @@ -48,7 +50,7 @@ async function chatingComm(io, socket, tables, dbClient, data){ socketId: data.socketId, device: userAgent, flag: 0, - content: decodeURIComponent(data.msg), + content: utils.unescapeStr(data.msg), handshake: JSON.stringify(handshake), ip: ip }, tables, dbClient); @@ -59,7 +61,7 @@ async function chatingComm(io, socket, tables, dbClient, data){ recoderId: recoderId, msgRecoderId: recoderId, socketId: data.socketId, - msg: decodeURIComponent(data.msg), + msg: utils.unescapeStr(data.msg), userAgent: userAgent, ip: ip }) @@ -72,6 +74,7 @@ async function chatingComm(io, socket, tables, dbClient, data){ }); bussinessNotify.sendSystemErrorMsg({ title: "socket-chatingComm", + data: JSON.stringify(data), room: data.room, from : socket.id, msg : JSON.stringify({ diff --git a/svr/src/socket/rtcChatingRoom/chatingRoom.js b/svr/src/socket/rtcChatingRoom/chatingRoom.js index 5e29167..43e3bb9 100644 --- a/svr/src/socket/rtcChatingRoom/chatingRoom.js +++ b/svr/src/socket/rtcChatingRoom/chatingRoom.js @@ -3,6 +3,7 @@ const bussinessNotify = require("./../../bussiness/notify/notifyHandler") const utils = require("./../../utils/utils"); const rtcConstant = require("../rtcConstant"); const rtcClientEvent = rtcConstant.rtcClientEvent +const check = require("./../../utils/check/content"); /** * 房间内聊天 群聊/私聊 @@ -17,7 +18,6 @@ const rtcClientEvent = rtcConstant.rtcClientEvent */ async function chatingRoom(io, socket, tables, dbClient, data){ try { - let {handshake, userAgent, ip} = utils.getSocketClientInfo(socket); await daoDog.addDogData({ @@ -76,6 +76,7 @@ async function chatingRoom(io, socket, tables, dbClient, data){ }); bussinessNotify.sendSystemErrorMsg({ title: "socket-chatingRoom", + data: JSON.stringify(data), room: data.room, from : socket.id, msg : JSON.stringify({ diff --git a/svr/src/socket/rtcCodeFile/addCodeFile.js b/svr/src/socket/rtcCodeFile/addCodeFile.js index f3ae7c6..a7a1d3e 100644 --- a/svr/src/socket/rtcCodeFile/addCodeFile.js +++ b/svr/src/socket/rtcCodeFile/addCodeFile.js @@ -6,6 +6,7 @@ const bussinessNotify = require("./../../bussiness/notify/notifyHandler") const utils = require("./../../utils/utils"); const seafile = require("./../../bussiness/oss/seafile") const rtcCommData = require("./../rtcCommData/commData"); +const check = require("./../../utils/check/content"); /** * 添加取件码文件 @@ -31,19 +32,17 @@ async function addCodeFile(io, socket, tables, dbClient, data){ let {handshake, userAgent, ip} = utils.getSocketClientInfo(socket); - const ossToken = await seafile.seafileGetToken(); - let donwloadLink = "" - + const ossToken = await seafile.seafileGetToken(); if(ossToken){ - let shareLink = await seafile.seafileCreateShareLink(ossToken, { + let downloadData = await seafile.seafileGetDownLoadLink(ossToken, { name : data.ossFileName, can_edit : false, can_download : true, expire_days : 1 }); - if(shareLink){ - donwloadLink = seafile.seafileGetDownLoadLink(shareLink.token); + if(downloadData){ + donwloadLink = downloadData.downloadLink; } } @@ -98,6 +97,7 @@ async function addCodeFile(io, socket, tables, dbClient, data){ }); bussinessNotify.sendSystemErrorMsg({ title: "socket-addCodeFile", + data: JSON.stringify(data), room: data.room, from : socket.id, msg : JSON.stringify({ diff --git a/svr/src/socket/rtcCodeFile/getCodeFile.js b/svr/src/socket/rtcCodeFile/getCodeFile.js index bc1e2b6..04399f7 100644 --- a/svr/src/socket/rtcCodeFile/getCodeFile.js +++ b/svr/src/socket/rtcCodeFile/getCodeFile.js @@ -5,6 +5,7 @@ const bussinessNotify = require("./../../bussiness/notify/notifyHandler") const utils = require("./../../utils/utils"); const daoFile = require("./../../dao/file/file") const rtcCommData = require("./../rtcCommData/commData"); +const check = require("./../../utils/check/content"); /** * 取件码取件 @@ -71,6 +72,7 @@ async function getCodeFile(io, socket, tables, dbClient, data){ }); bussinessNotify.sendSystemErrorMsg({ title: "socket-getCodeFile", + data: JSON.stringify(data), room: data.room, from : socket.id, msg : JSON.stringify({ diff --git a/svr/src/socket/rtcCodeFile/prepareCodeFile.js b/svr/src/socket/rtcCodeFile/prepareCodeFile.js index 96f99d0..19a9e0c 100644 --- a/svr/src/socket/rtcCodeFile/prepareCodeFile.js +++ b/svr/src/socket/rtcCodeFile/prepareCodeFile.js @@ -5,6 +5,7 @@ const bussinessNotify = require("./../../bussiness/notify/notifyHandler") const utils = require("./../../utils/utils"); const seafile = require("./../../bussiness/oss/seafile") const rtcCommData = require("./../rtcCommData/commData"); +const check = require("./../../utils/check/content"); /** * 生成取件码上传链接 @@ -17,7 +18,6 @@ const rtcCommData = require("./../rtcCommData/commData"); */ async function prepareCodeFile(io, socket, tables, dbClient, data){ try{ - let cacheSwitchData = rtcCommData.getCacheSwitchData() if(!cacheSwitchData.openGetCodeFile){ @@ -42,10 +42,8 @@ async function prepareCodeFile(io, socket, tables, dbClient, data){ return } - const ossToken = await seafile.seafileGetToken(); - data.uploadLink = ""; - + const ossToken = await seafile.seafileGetToken(); if(ossToken){ let uploadLink = await seafile.seafileGetUploadLink(ossToken); uploadLink = uploadLink.replace(/^(\s|\")+|(\s|\")+$/g, '') + "?ret-json=1"; @@ -90,6 +88,7 @@ async function prepareCodeFile(io, socket, tables, dbClient, data){ }); bussinessNotify.sendSystemErrorMsg({ title: "socket-prepareCodeFile", + data: JSON.stringify(data), room: data.room, from : socket.id, msg : JSON.stringify({ diff --git a/svr/src/socket/rtcCommData/commData.js b/svr/src/socket/rtcCommData/commData.js index 81269db..52d621d 100644 --- a/svr/src/socket/rtcCommData/commData.js +++ b/svr/src/socket/rtcCommData/commData.js @@ -3,6 +3,7 @@ const daoDog = require("./../../dao/dog/dog") const utils = require("./../../utils/utils"); const rtcConstant = require("../rtcConstant"); const rtcClientEvent = rtcConstant.rtcClientEvent +const bussinessNotify = require("./../../bussiness/notify/notifyHandler") // 公共聊天数据缓存 let chatingComm = null @@ -20,7 +21,6 @@ let cacheSwitchData = null */ async function getCommData(io, socket, tables, dbClient, data){ try{ - let {handshake, userAgent, ip} = utils.getSocketClientInfo(socket); let manageInfo = await daoRoom.getOrCreateManageRoom({ @@ -34,8 +34,8 @@ async function getCommData(io, socket, tables, dbClient, data){ } if(!chatingComm){ - chatingComm = await daoDog.getDogChating10Info({ - limit : 10 + chatingComm = await daoDog.getDogChatingCommInfo({ + limit : switchData.chatingCommCount || 10 }, tables, dbClient); } @@ -53,6 +53,7 @@ async function getCommData(io, socket, tables, dbClient, data){ }); bussinessNotify.sendSystemErrorMsg({ title: "socket-commData", + data: JSON.stringify(data), room: data.room, from : socket.id, msg : JSON.stringify({ diff --git a/svr/src/socket/rtcConstant.js b/svr/src/socket/rtcConstant.js index 13c6776..616465d 100644 --- a/svr/src/socket/rtcConstant.js +++ b/svr/src/socket/rtcConstant.js @@ -73,8 +73,12 @@ let rtcServerMessageEvent = { stopVideoShare : "stopVideoShare", //开始直播 startLiveShare : "startLiveShare", - // 结束直播 + //结束直播 stopLiveShare : "stopLiveShare", + //开始远程画笔 + startRemoteDraw : "startRemoteDraw", + //结束远程画笔 + stopRemoteDraw : "stopRemoteDraw", } /** diff --git a/svr/src/socket/rtcControl/control.js b/svr/src/socket/rtcControl/control.js index 59c4cd1..728eba5 100644 --- a/svr/src/socket/rtcControl/control.js +++ b/svr/src/socket/rtcControl/control.js @@ -3,6 +3,7 @@ const daoDog = require("./../../dao/dog/dog") const bussinessNotify = require("./../../bussiness/notify/notifyHandler") const rtcConstant = require("../rtcConstant"); const rtcClientEvent = rtcConstant.rtcClientEvent +const check = require("./../../utils/check/content"); /** * 远程控制 @@ -15,7 +16,6 @@ const rtcClientEvent = rtcConstant.rtcClientEvent */ async function control(io, socket, tables, dbClient, data){ try{ - let {room, from, to, opArr} = data; if(from !== socket.id){ @@ -78,6 +78,7 @@ async function control(io, socket, tables, dbClient, data){ }); bussinessNotify.sendSystemErrorMsg({ title: "socket-control", + data: JSON.stringify(data), room: data.room, from : socket.id, msg : JSON.stringify({ diff --git a/svr/src/socket/rtcCount/count.js b/svr/src/socket/rtcCount/count.js index 4ead278..a6f873b 100644 --- a/svr/src/socket/rtcCount/count.js +++ b/svr/src/socket/rtcCount/count.js @@ -15,7 +15,7 @@ async function count(io, socket, tables, dbClient, data){ try{ let allManCount = Object.keys(io.sockets.connected).length || 0; io.sockets.emit(rtcClientEvent.count, { - mc : allManCount + 50 + mc : allManCount }) }catch(e){ utils.tlConsole(e) diff --git a/svr/src/socket/rtcCreateJoin/createJoin.js b/svr/src/socket/rtcCreateJoin/createJoin.js index 6656a7d..407b0ac 100644 --- a/svr/src/socket/rtcCreateJoin/createJoin.js +++ b/svr/src/socket/rtcCreateJoin/createJoin.js @@ -5,6 +5,7 @@ const utils = require("./../../utils/utils"); const cfg = require("./../../../conf/cfg.json") const rtcConstant = require("../rtcConstant"); const rtcClientEvent = rtcConstant.rtcClientEvent +const check = require("./../../utils/check/content"); /** * 用户创建或加入房间 @@ -18,7 +19,7 @@ const rtcClientEvent = rtcConstant.rtcClientEvent async function userCreateAndJoin(io, socket, tables, dbClient, data){ let {handshake, userAgent, ip} = utils.getSocketClientInfo(socket); - let {room, type, nickName, password = ''} = data; + let {room, type, nickName, password = '', langMode = 'zh'} = data; if (room && room.length > 15) { room = room.toString().substr(0, 14); @@ -29,6 +30,7 @@ async function userCreateAndJoin(io, socket, tables, dbClient, data){ } //设置昵称 io.sockets.connected[socket.id].nickName = nickName; + io.sockets.connected[socket.id].langMode = langMode; if(password && password.length > 6){ password = password.toString().substr(0,6); @@ -62,6 +64,8 @@ async function userCreateAndJoin(io, socket, tables, dbClient, data){ recoderId : recoderId }); + io.sockets.connected[socket.id].owner = true; + //密码房间 首次创建设置密码 if(type === 'password'){ io.sockets.adapter.rooms[room].password = password @@ -92,12 +96,15 @@ async function userCreateAndJoin(io, socket, tables, dbClient, data){ } } + io.sockets.connected[socket.id].owner = false; + io.sockets.in(room).emit(rtcClientEvent.joined,{ id: socket.id, room: room, nickName : nickName, type: type, - recoderId : recoderId + recoderId : recoderId, + langMode : langMode, }); let peers = new Array(); @@ -105,9 +112,13 @@ async function userCreateAndJoin(io, socket, tables, dbClient, data){ for (let i = 0; i < otherSocketIds.length; i++) { let otherSocketId = otherSocketIds[i] let peerNickName = io.sockets.connected[otherSocketId].nickName + let peerOwner = io.sockets.connected[otherSocketId].owner + let peerLangMode = io.sockets.connected[otherSocketId].langMode peers.push({ id: otherSocketId, - nickName: peerNickName + nickName: peerNickName, + owner : peerOwner, + langMode : peerLangMode }); } @@ -233,6 +244,7 @@ async function createJoin(io, socket, tables, dbClient, data){ } if (cfg.manage.room !== room) { + data.room = check.contentFilter(data.room); // 用户加入/创建房间 userCreateAndJoin(io, socket, tables, dbClient, data) }else{ @@ -248,6 +260,7 @@ async function createJoin(io, socket, tables, dbClient, data){ }); bussinessNotify.sendSystemErrorMsg({ title: "socket-createJoin", + data: JSON.stringify(data), room: data.room, from : socket.id, msg : JSON.stringify({ diff --git a/svr/src/socket/rtcDraw/draw.js b/svr/src/socket/rtcDraw/draw.js index 8bdb2f4..dd212b9 100644 --- a/svr/src/socket/rtcDraw/draw.js +++ b/svr/src/socket/rtcDraw/draw.js @@ -2,7 +2,7 @@ const utils = require("./../../utils/utils"); const daoDog = require("./../../dao/dog/dog") const rtcConstant = require("../rtcConstant"); const rtcClientEvent = rtcConstant.rtcClientEvent - +const check = require("./../../utils/check/content"); /** * canvas画图 * @param {*} io socketio对象 diff --git a/svr/src/socket/rtcExit/exit.js b/svr/src/socket/rtcExit/exit.js index 4bca8c0..f173534 100644 --- a/svr/src/socket/rtcExit/exit.js +++ b/svr/src/socket/rtcExit/exit.js @@ -54,6 +54,7 @@ async function exit(io, socket, tables, dbClient, data){ }); bussinessNotify.sendSystemErrorMsg({ title: "socket-exit", + data: JSON.stringify(data), room: data.room, from : socket.id, msg : JSON.stringify({ diff --git a/svr/src/socket/rtcManage/change.js b/svr/src/socket/rtcManage/change.js index e037181..ad2598a 100644 --- a/svr/src/socket/rtcManage/change.js +++ b/svr/src/socket/rtcManage/change.js @@ -5,6 +5,7 @@ const rtcCommData = require("./../rtcCommData/commData") const utils = require("./../../utils/utils"); const rtcConstant = require("../rtcConstant"); const rtcClientEvent = rtcConstant.rtcClientEvent +const check = require("./../../utils/check/content"); /** * 管理后台修改数据 @@ -71,6 +72,7 @@ async function change(io, socket, tables, dbClient, data){ }); bussinessNotify.sendSystemErrorMsg({ title: "socket-manage-change", + data: JSON.stringify(data), room: data.room, from : socket.id, msg : JSON.stringify({ diff --git a/svr/src/socket/rtcManage/confirm.js b/svr/src/socket/rtcManage/confirm.js index ad87d90..0540f88 100644 --- a/svr/src/socket/rtcManage/confirm.js +++ b/svr/src/socket/rtcManage/confirm.js @@ -7,6 +7,7 @@ const cfg = require("./../../../conf/cfg.json") const manageConfig = cfg.manage const rtcConstant = require("../rtcConstant"); const rtcClientEvent = rtcConstant.rtcClientEvent +const check = require("./../../utils/check/content"); // 登陆token列表 let tokens = []; @@ -93,6 +94,7 @@ async function confirm(io, socket, tables, dbClient, data){ }); bussinessNotify.sendSystemErrorMsg({ title: "socket-manage-confirm", + data: JSON.stringify(data), room: data.room, from : socket.id, msg : JSON.stringify({ diff --git a/svr/src/socket/rtcManage/reload.js b/svr/src/socket/rtcManage/reload.js index 8c5ee21..21a54df 100644 --- a/svr/src/socket/rtcManage/reload.js +++ b/svr/src/socket/rtcManage/reload.js @@ -8,6 +8,7 @@ const cfg = require("./../../../conf/cfg.json") const manageConfig = cfg.manage const rtcConstant = require("../rtcConstant"); const rtcClientEvent = rtcConstant.rtcClientEvent +const check = require("./../../utils/check/content"); /** * 管理后台登陆验证 @@ -85,6 +86,7 @@ async function reload(io, socket, tables, dbClient, data){ }); bussinessNotify.sendSystemErrorMsg({ title: "socket-manage-reload", + data: JSON.stringify(data), room: data.room, from : socket.id, msg : JSON.stringify({ diff --git a/svr/src/socket/rtcMessage/message.js b/svr/src/socket/rtcMessage/message.js index 87eaa05..7e65506 100644 --- a/svr/src/socket/rtcMessage/message.js +++ b/svr/src/socket/rtcMessage/message.js @@ -3,6 +3,7 @@ const bussinessNotify = require("./../../bussiness/notify/notifyHandler") const utils = require("./../../utils/utils"); const rtcConstant = require("../rtcConstant"); const rtcServerMessageEvent = rtcConstant.rtcServerMessageEvent +const check = require("./../../utils/check/content"); let rtcEventOpName = { "sendFileInfo": "准备发送文件", @@ -16,6 +17,8 @@ let rtcEventOpName = { "stopVideoShare": "停止音视频通话", "startLiveShare": "开启直播", "stopLiveShare": "关闭直播", + "startRemoteDraw": "开启远程画笔", + "stopRemoteDraw": "关闭远程画笔", } /** @@ -36,6 +39,7 @@ async function message(io, socket, tables, dbClient, data){ let {handshake, userAgent, ip} = utils.getSocketClientInfo(socket); if (emitType === rtcServerMessageEvent.sendFileInfo) { + data.name = check.contentFilter(data.name); bussinessNotify.sendFileInfoNotify({ title: rtcEventOpName.sendFileInfo, room: data.room, @@ -50,6 +54,7 @@ async function message(io, socket, tables, dbClient, data){ } if (emitType === rtcServerMessageEvent.sendDone) { + data.name = check.contentFilter(data.name); bussinessNotify.sendFileDoneNotify({ title: rtcEventOpName.sendDone, room: data.room, @@ -152,6 +157,26 @@ async function message(io, socket, tables, dbClient, data){ }) } + if (emitType === rtcServerMessageEvent.startRemoteDraw) { + bussinessNotify.sendStartRemoteDrawNotify({ + title: rtcEventOpName.startRemoteDraw, + userAgent: userAgent, + ip: ip, + room: data.room, + }) + } + + if (emitType === rtcServerMessageEvent.stopRemoteDraw) { + bussinessNotify.sendStopRemoteDrawNotify({ + title: rtcEventOpName.stopRemoteDraw, + userAgent: data.userAgent, + userAgent: userAgent, + ip: ip, + room: data.room, + drawCount : data.drawCount + }) + } + if (rtcEventOpName[emitType]) { await daoDog.addDogData({ name: rtcEventOpName[emitType], @@ -200,6 +225,7 @@ async function message(io, socket, tables, dbClient, data){ }); bussinessNotify.sendSystemErrorMsg({ title: "socket-message", + data: JSON.stringify(data), room: data.room, from : socket.id, msg : JSON.stringify({ diff --git a/svr/src/socket/rtcOpenai/openai.js b/svr/src/socket/rtcOpenai/openai.js index 4d41876..3c9a2d7 100644 --- a/svr/src/socket/rtcOpenai/openai.js +++ b/svr/src/socket/rtcOpenai/openai.js @@ -5,6 +5,7 @@ const utils = require("./../../utils/utils"); const bussinessOpenai = require("./../../bussiness/openai/openai") const rtcConstant = require("../rtcConstant"); const rtcClientEvent = rtcConstant.rtcClientEvent +const check = require("./../../utils/check/content"); /** * ai聊天 @@ -33,6 +34,9 @@ async function openai(io, socket, tables, dbClient, data){ value = value.substr(0, 1000) } + data.content = check.contentFilter(data.content); + data.value = check.contentFilter(data.value); + // 有上下文,结合上下文 if(content){ content = content.substr(0, 5000); @@ -61,7 +65,7 @@ async function openai(io, socket, tables, dbClient, data){ socketId: data.socketId, device: userAgent, flag: 0, - content: decodeURIComponent(data.content), + content: utils.unescapeStr(data.content), handshake: JSON.stringify(handshake), ip: ip }, tables, dbClient); @@ -85,6 +89,7 @@ async function openai(io, socket, tables, dbClient, data){ }); bussinessNotify.sendSystemErrorMsg({ title: "socket-openai", + data: JSON.stringify(data), room: data.room, from : socket.id, msg : JSON.stringify({ diff --git a/svr/src/utils/check/content.js b/svr/src/utils/check/content.js index 2072de7..f5e8ded 100644 --- a/svr/src/utils/check/content.js +++ b/svr/src/utils/check/content.js @@ -1,7 +1,11 @@ const checkLib = require("./core").trie -const utils = require("../../../src/utils/utils"); - +/** + * 内容过滤 + * @param {*} text + * @param {*} replaceChar + * @returns + */ function contentFilter(text, replaceChar = '*') { let filteredText = ''; let currentIndex = 0; @@ -19,9 +23,32 @@ function contentFilter(text, replaceChar = '*') { return filteredText; } -module.exports = { - contentFilter +/** + * 对象内容过滤 + * @param {*} text + * @returns + */ +function objectContentFilter(obj) { + if (obj === null || obj === undefined) { + return obj; + } + if (typeof obj === 'string') { + return contentFilter(obj); + } + if (typeof obj === 'object') { + if (obj instanceof Array) { + return obj.map(item => objectContentFilter(item)); + } else { + const newObj = {}; + for (const key in obj) { + newObj[key] = objectContentFilter(obj[key]); + } + return newObj; + } + } + return obj; } - -utils.tlConsole(contentFilter("草泥马")) +module.exports = { + contentFilter, objectContentFilter +} \ No newline at end of file diff --git a/svr/src/utils/check/core.js b/svr/src/utils/check/core.js index 681df43..f793eea 100644 --- a/svr/src/utils/check/core.js +++ b/svr/src/utils/check/core.js @@ -37,6 +37,16 @@ class Trie { } return null; } + + toJson() { + //将树转换为json + return JSON.stringify(this.root, (key, value) => { + if (key === 'children') { + return [...value]; + } + return value; + }); + } } // 敏感词库 diff --git a/svr/src/utils/check/words.js b/svr/src/utils/check/words.js new file mode 100644 index 0000000..8ea3fcc --- /dev/null +++ b/svr/src/utils/check/words.js @@ -0,0 +1 @@ +module.exports = [] \ No newline at end of file diff --git a/svr/src/utils/utils.js b/svr/src/utils/utils.js index 497251b..27792a8 100644 --- a/svr/src/utils/utils.js +++ b/svr/src/utils/utils.js @@ -1,4 +1,5 @@ const os = require('os'); +const crypto = require('crypto'); const cfg = require('./../../conf/cfg.json'); /** @@ -146,9 +147,6 @@ function getFileSizeStr(size) { return head + '.' + tail + "M"; } -// const style = "color: yellow; font-style: italic; background-color: black; padding: 5px; font-weight: bold; font-family: system-ui;" -// console.log( `%ctl-rtc-file-${cfg.version} \t ${msg}`, style ); - function tlConsole(...msg){ console.log(`\x1B[1m${new Date().toLocaleString()}\x1B[0m \x1B[40m\x1B[33m tl-rtc-file-${cfg.version} \x1B[0m : \x1B[36m%s\x1B[0m`,...msg) } @@ -171,6 +169,136 @@ ${".".repeat(process.stdout.columns - 2)} } +/** + * 生成客户端控制台打印logo + */ +function genClientLogo(){ + let style = "font-size:20px;color: black; font-style: italic;"; + style += "font-weight: bold; font-family: system-ui;"; + style += "padding: 8px;cursor: pointer;" + return style; +} + + +/** + * 生成turn服务的iceServers配置 + * @param {*} withTurn + * @param {*} useSecret + * @param {*} username + * @returns + */ +function genTurnServerIceServersConfig(withTurn, useSecret, username){ + let iceServers = [{ + urls : cfg.webrtc.stun.host + }]; + + //无需turn中继 + if(!withTurn){ + return iceServers; + } + + //turn固定账号模式 + if(!useSecret){ + iceServers.push({ + urls : cfg.webrtc.turn.host, + username: cfg.webrtc.turn.username, + credential: cfg.webrtc.turn.credential + }) + return iceServers; + } + + // 有效账号模式 + const secret = cfg.webrtc.turn.secret || "tlrtcfile"; + //生成账号的有效期 + const expirseTime = 60 * 60 * 24 * 1000; + //当前时间 + const time = new Date().getTime(); + //turn服务的用户名规则 + const turnUsername = `${time + expirseTime}:${username}`; + //turn服务的密码规则 + const dig = crypto.createHmac('sha1', secret).update(turnUsername).digest(); + const turnPassword = Buffer.from(dig, 'utf-8').toString('base64'); + + iceServers.push({ + urls : cfg.webrtc.turn.host, + username: turnUsername, + credential: turnPassword + }) + + return iceServers; +} + +/** + * 转义字符串 + * @param {*} str + * @returns + */ +function escapeStr(str) { + const entityMap = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + '/': '/', + '`': '`', + '=': '=' + }; + + const encodedMap = { + '%': '%25', + '!': '%21', + "'": '%27', + '(': '%28', + ')': '%29', + '*': '%2A', + '-': '%2D', + '.': '%2E', + '_': '%5F', + '~': '%7E' + }; + + return String(str).replace(/[&<>"'`=\/%!'()*\-._~]/g, function (s) { + return entityMap[s] || encodedMap[s] || ''; + }); +} + +/** + * 解析转义字符串 + * @param {*} str + * @returns + */ +function unescapeStr(str) { + const entityMap = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + ''': "'", + '/': '/', + '`': '`', + '=': '=' + }; + + const encodedMap = { + '%25': '%', + '%21': '!', + '%27': "'", + '%28': '(', + '%29': ')', + '%2A': '*', + '%2D': '-', + '%2E': '.', + '%5F': '_', + '%7E': '~' + }; + + return String(str).replace(/&(amp|lt|gt|quot|#39|#x2F|#x60|#x3D);|%(25|21|27|28|29|2A|2D|2E|5F|7E)/g, function (s) { + return entityMap[s] || encodedMap[s] || ''; + }); +} + + module.exports = { getLocalIP, getClientIP, @@ -181,5 +309,9 @@ module.exports = { getSocketClientInfo, getFileSizeStr, tlConsole, - tlConsoleIcon + tlConsoleIcon, + genTurnServerIceServersConfig, + genClientLogo, + unescapeStr, + escapeStr } \ No newline at end of file diff --git a/svr/start-local.sh b/svr/start-local.sh new file mode 100755 index 0000000..75791d7 --- /dev/null +++ b/svr/start-local.sh @@ -0,0 +1,11 @@ +pm2 start npm --name=tl-rtc-file-api-local -- run lapi + +sleep 1 + +pm2 start npm --name=tl-rtc-file-socket-local -- run lsocket + +sleep 1 + +cd build/webpack + +pm2 start npm --name=tl-rtc-file-build-local -- run dev \ No newline at end of file diff --git a/svr/start-server.sh b/svr/start-server.sh new file mode 100755 index 0000000..3932eb3 --- /dev/null +++ b/svr/start-server.sh @@ -0,0 +1,5 @@ +pm2 start npm --name=tl-rtc-file-api-server -- run sapi + +sleep 1 + +pm2 start npm --name=tl-rtc-file-socket-server -- run ssocket \ No newline at end of file diff --git a/svr/static/layui/font-ext/demo.css b/svr/static/layui/font-ext/demo.css new file mode 100644 index 0000000..a67054a --- /dev/null +++ b/svr/static/layui/font-ext/demo.css @@ -0,0 +1,539 @@ +/* Logo 字体 */ +@font-face { + font-family: "iconfont logo"; + src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834'); + src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'), + url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'), + url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'), + url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg'); +} + +.logo { + font-family: "iconfont logo"; + font-size: 160px; + font-style: normal; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +/* tabs */ +.nav-tabs { + position: relative; +} + +.nav-tabs .nav-more { + position: absolute; + right: 0; + bottom: 0; + height: 42px; + line-height: 42px; + color: #666; +} + +#tabs { + border-bottom: 1px solid #eee; +} + +#tabs li { + cursor: pointer; + width: 100px; + height: 40px; + line-height: 40px; + text-align: center; + font-size: 16px; + border-bottom: 2px solid transparent; + position: relative; + z-index: 1; + margin-bottom: -1px; + color: #666; +} + + +#tabs .active { + border-bottom-color: #f00; + color: #222; +} + +.tab-container .content { + display: none; +} + +/* 页面布局 */ +.main { + padding: 30px 100px; + width: 960px; + margin: 0 auto; +} + +.main .logo { + color: #333; + text-align: left; + margin-bottom: 30px; + line-height: 1; + height: 110px; + margin-top: -50px; + overflow: hidden; + *zoom: 1; +} + +.main .logo a { + font-size: 160px; + color: #333; +} + +.helps { + margin-top: 40px; +} + +.helps pre { + padding: 20px; + margin: 10px 0; + border: solid 1px #e7e1cd; + background-color: #fffdef; + overflow: auto; +} + +.icon_lists { + width: 100% !important; + overflow: hidden; + *zoom: 1; +} + +.icon_lists li { + width: 100px; + margin-bottom: 10px; + margin-right: 20px; + text-align: center; + list-style: none !important; + cursor: default; +} + +.icon_lists li .code-name { + line-height: 1.2; +} + +.icon_lists .icon { + display: block; + height: 100px; + line-height: 100px; + font-size: 42px; + margin: 10px auto; + color: #333; + -webkit-transition: font-size 0.25s linear, width 0.25s linear; + -moz-transition: font-size 0.25s linear, width 0.25s linear; + transition: font-size 0.25s linear, width 0.25s linear; +} + +.icon_lists .icon:hover { + font-size: 100px; +} + +.icon_lists .svg-icon { + /* 通过设置 font-size 来改变图标大小 */ + width: 1em; + /* 图标和文字相邻时,垂直对齐 */ + vertical-align: -0.15em; + /* 通过设置 color 来改变 SVG 的颜色/fill */ + fill: currentColor; + /* path 和 stroke 溢出 viewBox 部分在 IE 下会显示 + normalize.css 中也包含这行 */ + overflow: hidden; +} + +.icon_lists li .name, +.icon_lists li .code-name { + color: #666; +} + +/* markdown 样式 */ +.markdown { + color: #666; + font-size: 14px; + line-height: 1.8; +} + +.highlight { + line-height: 1.5; +} + +.markdown img { + vertical-align: middle; + max-width: 100%; +} + +.markdown h1 { + color: #404040; + font-weight: 500; + line-height: 40px; + margin-bottom: 24px; +} + +.markdown h2, +.markdown h3, +.markdown h4, +.markdown h5, +.markdown h6 { + color: #404040; + margin: 1.6em 0 0.6em 0; + font-weight: 500; + clear: both; +} + +.markdown h1 { + font-size: 28px; +} + +.markdown h2 { + font-size: 22px; +} + +.markdown h3 { + font-size: 16px; +} + +.markdown h4 { + font-size: 14px; +} + +.markdown h5 { + font-size: 12px; +} + +.markdown h6 { + font-size: 12px; +} + +.markdown hr { + height: 1px; + border: 0; + background: #e9e9e9; + margin: 16px 0; + clear: both; +} + +.markdown p { + margin: 1em 0; +} + +.markdown>p, +.markdown>blockquote, +.markdown>.highlight, +.markdown>ol, +.markdown>ul { + width: 80%; +} + +.markdown ul>li { + list-style: circle; +} + +.markdown>ul li, +.markdown blockquote ul>li { + margin-left: 20px; + padding-left: 4px; +} + +.markdown>ul li p, +.markdown>ol li p { + margin: 0.6em 0; +} + +.markdown ol>li { + list-style: decimal; +} + +.markdown>ol li, +.markdown blockquote ol>li { + margin-left: 20px; + padding-left: 4px; +} + +.markdown code { + margin: 0 3px; + padding: 0 5px; + background: #eee; + border-radius: 3px; +} + +.markdown strong, +.markdown b { + font-weight: 600; +} + +.markdown>table { + border-collapse: collapse; + border-spacing: 0px; + empty-cells: show; + border: 1px solid #e9e9e9; + width: 95%; + margin-bottom: 24px; +} + +.markdown>table th { + white-space: nowrap; + color: #333; + font-weight: 600; +} + +.markdown>table th, +.markdown>table td { + border: 1px solid #e9e9e9; + padding: 8px 16px; + text-align: left; +} + +.markdown>table th { + background: #F7F7F7; +} + +.markdown blockquote { + font-size: 90%; + color: #999; + border-left: 4px solid #e9e9e9; + padding-left: 0.8em; + margin: 1em 0; +} + +.markdown blockquote p { + margin: 0; +} + +.markdown .anchor { + opacity: 0; + transition: opacity 0.3s ease; + margin-left: 8px; +} + +.markdown .waiting { + color: #ccc; +} + +.markdown h1:hover .anchor, +.markdown h2:hover .anchor, +.markdown h3:hover .anchor, +.markdown h4:hover .anchor, +.markdown h5:hover .anchor, +.markdown h6:hover .anchor { + opacity: 1; + display: inline-block; +} + +.markdown>br, +.markdown>p>br { + clear: both; +} + + +.hljs { + display: block; + background: white; + padding: 0.5em; + color: #333333; + overflow-x: auto; +} + +.hljs-comment, +.hljs-meta { + color: #969896; +} + +.hljs-string, +.hljs-variable, +.hljs-template-variable, +.hljs-strong, +.hljs-emphasis, +.hljs-quote { + color: #df5000; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-type { + color: #a71d5d; +} + +.hljs-literal, +.hljs-symbol, +.hljs-bullet, +.hljs-attribute { + color: #0086b3; +} + +.hljs-section, +.hljs-name { + color: #63a35c; +} + +.hljs-tag { + color: #333333; +} + +.hljs-title, +.hljs-attr, +.hljs-selector-id, +.hljs-selector-class, +.hljs-selector-attr, +.hljs-selector-pseudo { + color: #795da3; +} + +.hljs-addition { + color: #55a532; + background-color: #eaffea; +} + +.hljs-deletion { + color: #bd2c00; + background-color: #ffecec; +} + +.hljs-link { + text-decoration: underline; +} + +/* 代码高亮 */ +/* PrismJS 1.15.0 +https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */ +/** + * prism.js default theme for JavaScript, CSS and HTML + * Based on dabblet (http://dabblet.com) + * @author Lea Verou + */ +code[class*="language-"], +pre[class*="language-"] { + color: black; + background: none; + text-shadow: 0 1px white; + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + + -webkit-hyphens: none; + -moz-hyphens: none; + -ms-hyphens: none; + hyphens: none; +} + +pre[class*="language-"]::-moz-selection, +pre[class*="language-"] ::-moz-selection, +code[class*="language-"]::-moz-selection, +code[class*="language-"] ::-moz-selection { + text-shadow: none; + background: #b3d4fc; +} + +pre[class*="language-"]::selection, +pre[class*="language-"] ::selection, +code[class*="language-"]::selection, +code[class*="language-"] ::selection { + text-shadow: none; + background: #b3d4fc; +} + +@media print { + + code[class*="language-"], + pre[class*="language-"] { + text-shadow: none; + } +} + +/* Code blocks */ +pre[class*="language-"] { + padding: 1em; + margin: .5em 0; + overflow: auto; +} + +:not(pre)>code[class*="language-"], +pre[class*="language-"] { + background: #f5f2f0; +} + +/* Inline code */ +:not(pre)>code[class*="language-"] { + padding: .1em; + border-radius: .3em; + white-space: normal; +} + +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: slategray; +} + +.token.punctuation { + color: #999; +} + +.namespace { + opacity: .7; +} + +.token.property, +.token.tag, +.token.boolean, +.token.number, +.token.constant, +.token.symbol, +.token.deleted { + color: #905; +} + +.token.selector, +.token.attr-name, +.token.string, +.token.char, +.token.builtin, +.token.inserted { + color: #690; +} + +.token.operator, +.token.entity, +.token.url, +.language-css .token.string, +.style .token.string { + color: #9a6e3a; + background: hsla(0, 0%, 100%, .5); +} + +.token.atrule, +.token.attr-value, +.token.keyword { + color: #07a; +} + +.token.function, +.token.class-name { + color: #DD4A68; +} + +.token.regex, +.token.important, +.token.variable { + color: #e90; +} + +.token.important, +.token.bold { + font-weight: bold; +} + +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} diff --git a/svr/static/layui/font-ext/demo_index.html b/svr/static/layui/font-ext/demo_index.html new file mode 100644 index 0000000..918da38 --- /dev/null +++ b/svr/static/layui/font-ext/demo_index.html @@ -0,0 +1,1959 @@ + + + + + iconfont Demo + + + + + + + + + + + + + +
+

+ + +

+ +
+
+
    + +
  • + +
    三角形
    +
    &#xe619;
    +
  • + +
  • + +
    向上三角形
    +
    &#xe70f;
    +
  • + +
  • + +
    星星
    +
    &#xe61a;
    +
  • + +
  • + +
    星星
    +
    &#xe639;
    +
  • + +
  • + +
    tx-fill-平行四边形
    +
    &#xe64c;
    +
  • + +
  • + +
    tx-fill-六边形
    +
    &#xe64b;
    +
  • + +
  • + +
    平行四边形
    +
    &#xedf9;
    +
  • + +
  • + +
    六边形
    +
    &#xe61b;
    +
  • + +
  • + +
    AI智能
    +
    &#xe679;
    +
  • + +
  • + +
    P2P
    +
    &#xe618;
    +
  • + +
  • + +
    github
    +
    &#xe66f;
    +
  • + +
  • + +
    文件类型-Excel
    +
    &#xe602;
    +
  • + +
  • + +
    文件类型-文件夹
    +
    &#xe603;
    +
  • + +
  • + +
    文件类型-Word
    +
    &#xe605;
    +
  • + +
  • + +
    文件类型-PPT
    +
    &#xe606;
    +
  • + +
  • + +
    文件类型-音频
    +
    &#xe607;
    +
  • + +
  • + +
    文件类型-程序
    +
    &#xe608;
    +
  • + +
  • + +
    文件类型-视频
    +
    &#xe609;
    +
  • + +
  • + +
    文件类型-链接
    +
    &#xe60a;
    +
  • + +
  • + +
    文件类型-图片
    +
    &#xe60b;
    +
  • + +
  • + +
    文件类型-压缩包
    +
    &#xe60c;
    +
  • + +
  • + +
    文件类型-未知文件
    +
    &#xe60d;
    +
  • + +
  • + +
    文件类型-Gif
    +
    &#xe60e;
    +
  • + +
  • + +
    文件类型-Exe
    +
    &#xe60f;
    +
  • + +
  • + +
    文件类型-Pdf
    +
    &#xe610;
    +
  • + +
  • + +
    文件类型-Txt
    +
    &#xe611;
    +
  • + +
  • + +
    文件类型-WPS
    +
    &#xe612;
    +
  • + +
  • + +
    文件类型-数据库
    +
    &#xe613;
    +
  • + +
  • + +
    文件类型-3D
    +
    &#xe614;
    +
  • + +
  • + +
    文件类型-邮件
    +
    &#xe616;
    +
  • + +
  • + +
    文件类型-配置文件
    +
    &#xe617;
    +
  • + +
  • + +
    多语言
    +
    &#xe659;
    +
  • + +
  • + +
    WIFI
    +
    &#xe700;
    +
  • + +
  • + +
    doc
    +
    &#xe652;
    +
  • + +
  • + +
    jpg
    +
    &#xe653;
    +
  • + +
  • + +
    html
    +
    &#xe654;
    +
  • + +
  • + +
    mp3
    +
    &#xe655;
    +
  • + +
  • + +
    png
    +
    &#xe657;
    +
  • + +
  • + +
    dll
    +
    &#xe658;
    +
  • + +
  • + +
    mp4
    +
    &#xe65a;
    +
  • + +
  • + +
    pdf
    +
    &#xe65b;
    +
  • + +
  • + +
    gif
    +
    &#xe65c;
    +
  • + +
  • + +
    exe
    +
    &#xe65d;
    +
  • + +
  • + +
    mpg
    +
    &#xe65e;
    +
  • + +
  • + +
    psd
    +
    &#xe65f;
    +
  • + +
  • + +
    mkv
    +
    &#xe660;
    +
  • + +
  • + +
    xls
    +
    &#xe661;
    +
  • + +
  • + +
    rmvb
    +
    &#xe662;
    +
  • + +
  • + +
    wav
    +
    &#xe664;
    +
  • + +
  • + +
    swf
    +
    &#xe665;
    +
  • + +
  • + +
    avi
    +
    &#xe666;
    +
  • + +
  • + +
    zip
    +
    &#xe667;
    +
  • + +
  • + +
    othe
    +
    &#xe668;
    +
  • + +
  • + +
    ppt
    +
    &#xe650;
    +
  • + +
  • + +
    txt
    +
    &#xe651;
    +
  • + +
  • + +
    PDF
    +
    &#xe601;
    +
  • + +
  • + +
    代码文件_file-code
    +
    &#xe621;
    +
  • + +
  • + +
    警告
    +
    &#xe600;
    +
  • + +
  • + +
    红包
    +
    &#xe656;
    +
  • + +
  • + +
    圆角矩形
    +
    &#xe64e;
    +
  • + +
  • + +
    圆形
    +
    &#xe64f;
    +
  • + +
  • + +
    橡皮擦
    +
    &#xe6b8;
    +
  • + +
  • + +
    头像 男孩
    +
    &#xe672;
    +
  • + +
  • + +
    文字
    +
    &#xe6ec;
    +
  • + +
  • + +
    +
    &#xe689;
    +
  • + +
  • + +
    云服务器
    +
    &#xe615;
    +
  • + +
  • + +
    矩形
    +
    &#xe620;
    +
  • + +
  • + +
    圆形
    +
    &#xe626;
    +
  • + +
  • + +
    下载
    +
    &#xe638;
    +
  • + +
  • + +
    图片
    +
    &#xe691;
    +
  • + +
  • + +
    工具
    +
    &#xe6cf;
    +
  • + +
  • + +
    用户反馈
    +
    &#xe604;
    +
  • + +
  • + +
    5g
    +
    &#xe63f;
    +
  • + +
  • + +
    3g
    +
    &#xe640;
    +
  • + +
  • + +
    4g
    +
    &#xe641;
    +
  • + +
  • + +
    2g
    +
    &#xe642;
    +
  • + +
  • + +
    正确
    +
    &#xec6b;
    +
  • + +
+
+

Unicode 引用

+
+ +

Unicode 是字体在网页端最原始的应用方式,特点是:

+
    +
  • 支持按字体的方式去动态调整图标大小,颜色等等。
  • +
  • 默认情况下不支持多色,直接添加多色图标会自动去色。
  • +
+
+

注意:新版 iconfont 支持两种方式引用多色图标:SVG symbol 引用方式和彩色字体图标模式。(使用彩色字体图标需要在「编辑项目」中开启「彩色」选项后并重新生成。)

+
+

Unicode 使用步骤如下:

+

第一步:拷贝项目下面生成的 @font-face

+
@font-face {
+  font-family: 'iconfont';
+  src: url('iconfont.woff2?t=1688291642630') format('woff2'),
+       url('iconfont.woff?t=1688291642630') format('woff'),
+       url('iconfont.ttf?t=1688291642630') format('truetype');
+}
+
+

第二步:定义使用 iconfont 的样式

+
.iconfont {
+  font-family: "iconfont" !important;
+  font-size: 16px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+

第三步:挑选相应图标并获取字体编码,应用于页面

+
+<span class="iconfont">&#x33;</span>
+
+
+

"iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。

+
+
+
+
+
    + +
  • + +
    + 三角形 +
    +
    .icon-rtc-file-sanjiaoxing +
    +
  • + +
  • + +
    + 向上三角形 +
    +
    .icon-rtc-file-xiangshangsanjiaoxing +
    +
  • + +
  • + +
    + 星星 +
    +
    .icon-rtc-file-xingxing +
    +
  • + +
  • + +
    + 星星 +
    +
    .icon-rtc-file-xingxing1 +
    +
  • + +
  • + +
    + tx-fill-平行四边形 +
    +
    .icon-rtc-file-tx-fill-pinghangsibianxing +
    +
  • + +
  • + +
    + tx-fill-六边形 +
    +
    .icon-rtc-file-tx-fill-liubianxing +
    +
  • + +
  • + +
    + 平行四边形 +
    +
    .icon-rtc-file-pinghangsibianxing +
    +
  • + +
  • + +
    + 六边形 +
    +
    .icon-rtc-file-hexagon +
    +
  • + +
  • + +
    + AI智能 +
    +
    .icon-rtc-file-AIzhineng +
    +
  • + +
  • + +
    + P2P +
    +
    .icon-rtc-file-PP- +
    +
  • + +
  • + +
    + github +
    +
    .icon-rtc-file-github +
    +
  • + +
  • + +
    + 文件类型-Excel +
    +
    .icon-rtc-file-Excel +
    +
  • + +
  • + +
    + 文件类型-文件夹 +
    +
    .icon-rtc-file-File +
    +
  • + +
  • + +
    + 文件类型-Word +
    +
    .icon-rtc-file-Word +
    +
  • + +
  • + +
    + 文件类型-PPT +
    +
    .icon-rtc-file-PPT +
    +
  • + +
  • + +
    + 文件类型-音频 +
    +
    .icon-rtc-file-music +
    +
  • + +
  • + +
    + 文件类型-程序 +
    +
    .icon-rtc-file-chengxu +
    +
  • + +
  • + +
    + 文件类型-视频 +
    +
    .icon-rtc-file-shipin +
    +
  • + +
  • + +
    + 文件类型-链接 +
    +
    .icon-rtc-file-lianjiewenjian +
    +
  • + +
  • + +
    + 文件类型-图片 +
    +
    .icon-rtc-file-tupian +
    +
  • + +
  • + +
    + 文件类型-压缩包 +
    +
    .icon-rtc-file-yasuobao +
    +
  • + +
  • + +
    + 文件类型-未知文件 +
    +
    .icon-rtc-file-weizhiwenjian +
    +
  • + +
  • + +
    + 文件类型-Gif +
    +
    .icon-rtc-file-Gif +
    +
  • + +
  • + +
    + 文件类型-Exe +
    +
    .icon-rtc-file-Exe +
    +
  • + +
  • + +
    + 文件类型-Pdf +
    +
    .icon-rtc-file-Pdf +
    +
  • + +
  • + +
    + 文件类型-Txt +
    +
    .icon-rtc-file-txt1 +
    +
  • + +
  • + +
    + 文件类型-WPS +
    +
    .icon-rtc-file-WPS +
    +
  • + +
  • + +
    + 文件类型-数据库 +
    +
    .icon-rtc-file-shujuku +
    +
  • + +
  • + +
    + 文件类型-3D +
    +
    .icon-rtc-file-a-3D +
    +
  • + +
  • + +
    + 文件类型-邮件 +
    +
    .icon-rtc-file-youjian +
    +
  • + +
  • + +
    + 文件类型-配置文件 +
    +
    .icon-rtc-file-peizhiwenjian +
    +
  • + +
  • + +
    + 多语言 +
    +
    .icon-rtc-file-duoyuyan +
    +
  • + +
  • + +
    + WIFI +
    +
    .icon-rtc-file-WIFI +
    +
  • + +
  • + +
    + doc +
    +
    .icon-rtc-file-doc +
    +
  • + +
  • + +
    + jpg +
    +
    .icon-rtc-file-jpg +
    +
  • + +
  • + +
    + html +
    +
    .icon-rtc-file-html +
    +
  • + +
  • + +
    + mp3 +
    +
    .icon-rtc-file-icon_MP- +
    +
  • + +
  • + +
    + png +
    +
    .icon-rtc-file-png +
    +
  • + +
  • + +
    + dll +
    +
    .icon-rtc-file-dll +
    +
  • + +
  • + +
    + mp4 +
    +
    .icon-rtc-file-mp4 +
    +
  • + +
  • + +
    + pdf +
    +
    .icon-rtc-file-pdf +
    +
  • + +
  • + +
    + gif +
    +
    .icon-rtc-file-gif +
    +
  • + +
  • + +
    + exe +
    +
    .icon-rtc-file-exe +
    +
  • + +
  • + +
    + mpg +
    +
    .icon-rtc-file-mpg +
    +
  • + +
  • + +
    + psd +
    +
    .icon-rtc-file-psd +
    +
  • + +
  • + +
    + mkv +
    +
    .icon-rtc-file-mkv +
    +
  • + +
  • + +
    + xls +
    +
    .icon-rtc-file-xls +
    +
  • + +
  • + +
    + rmvb +
    +
    .icon-rtc-file-rmvb +
    +
  • + +
  • + +
    + wav +
    +
    .icon-rtc-file-wav +
    +
  • + +
  • + +
    + swf +
    +
    .icon-rtc-file-swf +
    +
  • + +
  • + +
    + avi +
    +
    .icon-rtc-file-avi +
    +
  • + +
  • + +
    + zip +
    +
    .icon-rtc-file-zip1 +
    +
  • + +
  • + +
    + othe +
    +
    .icon-rtc-file-othe +
    +
  • + +
  • + +
    + ppt +
    +
    .icon-rtc-file-ppt +
    +
  • + +
  • + +
    + txt +
    +
    .icon-rtc-file-txt +
    +
  • + +
  • + +
    + PDF +
    +
    .icon-rtc-file-PDF +
    +
  • + +
  • + +
    + 代码文件_file-code +
    +
    .icon-rtc-file-daimawenjian_file-code +
    +
  • + +
  • + +
    + 警告 +
    +
    .icon-rtc-file-jinggao +
    +
  • + +
  • + +
    + 红包 +
    +
    .icon-rtc-file-hongbao +
    +
  • + +
  • + +
    + 圆角矩形 +
    +
    .icon-rtc-file-yuanjiao-rect +
    +
  • + +
  • + +
    + 圆形 +
    +
    .icon-rtc-file-circle +
    +
  • + +
  • + +
    + 橡皮擦 +
    +
    .icon-rtc-file-xiangpica +
    +
  • + +
  • + +
    + 头像 男孩 +
    +
    .icon-rtc-file-icon-test +
    +
  • + +
  • + +
    + 文字 +
    +
    .icon-rtc-file-wenzi +
    +
  • + +
  • + +
    + 猪 +
    +
    .icon-rtc-file-zhu +
    +
  • + +
  • + +
    + 云服务器 +
    +
    .icon-rtc-file-yunfuwuqi +
    +
  • + +
  • + +
    + 矩形 +
    +
    .icon-rtc-file-juxing +
    +
  • + +
  • + +
    + 圆形 +
    +
    .icon-rtc-file-yuanxing +
    +
  • + +
  • + +
    + 下载 +
    +
    .icon-rtc-file-xiazai +
    +
  • + +
  • + +
    + 图片 +
    +
    .icon-rtc-file-tupian_huaban +
    +
  • + +
  • + +
    + 工具 +
    +
    .icon-rtc-file-gongju +
    +
  • + +
  • + +
    + 用户反馈 +
    +
    .icon-rtc-file-yonghufankuibeifen +
    +
  • + +
  • + +
    + 5g +
    +
    .icon-rtc-file-five-g +
    +
  • + +
  • + +
    + 3g +
    +
    .icon-rtc-file-three-g +
    +
  • + +
  • + +
    + 4g +
    +
    .icon-rtc-file-four-g +
    +
  • + +
  • + +
    + 2g +
    +
    .icon-rtc-file-two-g +
    +
  • + +
  • + +
    + 正确 +
    +
    .icon-rtc-file-zhengque +
    +
  • + +
+
+

font-class 引用

+
+ +

font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。

+

与 Unicode 使用方式相比,具有如下特点:

+
    +
  • 相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。
  • +
  • 因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。
  • +
+

使用步骤如下:

+

第一步:引入项目下面生成的 fontclass 代码:

+
<link rel="stylesheet" href="./iconfont.css">
+
+

第二步:挑选相应图标并获取类名,应用于页面:

+
<span class="iconfont icon-rtc-file-xxx"></span>
+
+
+

" + iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。

+
+
+
+
+
    + +
  • + +
    三角形
    +
    #icon-rtc-file-sanjiaoxing
    +
  • + +
  • + +
    向上三角形
    +
    #icon-rtc-file-xiangshangsanjiaoxing
    +
  • + +
  • + +
    星星
    +
    #icon-rtc-file-xingxing
    +
  • + +
  • + +
    星星
    +
    #icon-rtc-file-xingxing1
    +
  • + +
  • + +
    tx-fill-平行四边形
    +
    #icon-rtc-file-tx-fill-pinghangsibianxing
    +
  • + +
  • + +
    tx-fill-六边形
    +
    #icon-rtc-file-tx-fill-liubianxing
    +
  • + +
  • + +
    平行四边形
    +
    #icon-rtc-file-pinghangsibianxing
    +
  • + +
  • + +
    六边形
    +
    #icon-rtc-file-hexagon
    +
  • + +
  • + +
    AI智能
    +
    #icon-rtc-file-AIzhineng
    +
  • + +
  • + +
    P2P
    +
    #icon-rtc-file-PP-
    +
  • + +
  • + +
    github
    +
    #icon-rtc-file-github
    +
  • + +
  • + +
    文件类型-Excel
    +
    #icon-rtc-file-Excel
    +
  • + +
  • + +
    文件类型-文件夹
    +
    #icon-rtc-file-File
    +
  • + +
  • + +
    文件类型-Word
    +
    #icon-rtc-file-Word
    +
  • + +
  • + +
    文件类型-PPT
    +
    #icon-rtc-file-PPT
    +
  • + +
  • + +
    文件类型-音频
    +
    #icon-rtc-file-music
    +
  • + +
  • + +
    文件类型-程序
    +
    #icon-rtc-file-chengxu
    +
  • + +
  • + +
    文件类型-视频
    +
    #icon-rtc-file-shipin
    +
  • + +
  • + +
    文件类型-链接
    +
    #icon-rtc-file-lianjiewenjian
    +
  • + +
  • + +
    文件类型-图片
    +
    #icon-rtc-file-tupian
    +
  • + +
  • + +
    文件类型-压缩包
    +
    #icon-rtc-file-yasuobao
    +
  • + +
  • + +
    文件类型-未知文件
    +
    #icon-rtc-file-weizhiwenjian
    +
  • + +
  • + +
    文件类型-Gif
    +
    #icon-rtc-file-Gif
    +
  • + +
  • + +
    文件类型-Exe
    +
    #icon-rtc-file-Exe
    +
  • + +
  • + +
    文件类型-Pdf
    +
    #icon-rtc-file-Pdf
    +
  • + +
  • + +
    文件类型-Txt
    +
    #icon-rtc-file-txt1
    +
  • + +
  • + +
    文件类型-WPS
    +
    #icon-rtc-file-WPS
    +
  • + +
  • + +
    文件类型-数据库
    +
    #icon-rtc-file-shujuku
    +
  • + +
  • + +
    文件类型-3D
    +
    #icon-rtc-file-a-3D
    +
  • + +
  • + +
    文件类型-邮件
    +
    #icon-rtc-file-youjian
    +
  • + +
  • + +
    文件类型-配置文件
    +
    #icon-rtc-file-peizhiwenjian
    +
  • + +
  • + +
    多语言
    +
    #icon-rtc-file-duoyuyan
    +
  • + +
  • + +
    WIFI
    +
    #icon-rtc-file-WIFI
    +
  • + +
  • + +
    doc
    +
    #icon-rtc-file-doc
    +
  • + +
  • + +
    jpg
    +
    #icon-rtc-file-jpg
    +
  • + +
  • + +
    html
    +
    #icon-rtc-file-html
    +
  • + +
  • + +
    mp3
    +
    #icon-rtc-file-icon_MP-
    +
  • + +
  • + +
    png
    +
    #icon-rtc-file-png
    +
  • + +
  • + +
    dll
    +
    #icon-rtc-file-dll
    +
  • + +
  • + +
    mp4
    +
    #icon-rtc-file-mp4
    +
  • + +
  • + +
    pdf
    +
    #icon-rtc-file-pdf
    +
  • + +
  • + +
    gif
    +
    #icon-rtc-file-gif
    +
  • + +
  • + +
    exe
    +
    #icon-rtc-file-exe
    +
  • + +
  • + +
    mpg
    +
    #icon-rtc-file-mpg
    +
  • + +
  • + +
    psd
    +
    #icon-rtc-file-psd
    +
  • + +
  • + +
    mkv
    +
    #icon-rtc-file-mkv
    +
  • + +
  • + +
    xls
    +
    #icon-rtc-file-xls
    +
  • + +
  • + +
    rmvb
    +
    #icon-rtc-file-rmvb
    +
  • + +
  • + +
    wav
    +
    #icon-rtc-file-wav
    +
  • + +
  • + +
    swf
    +
    #icon-rtc-file-swf
    +
  • + +
  • + +
    avi
    +
    #icon-rtc-file-avi
    +
  • + +
  • + +
    zip
    +
    #icon-rtc-file-zip1
    +
  • + +
  • + +
    othe
    +
    #icon-rtc-file-othe
    +
  • + +
  • + +
    ppt
    +
    #icon-rtc-file-ppt
    +
  • + +
  • + +
    txt
    +
    #icon-rtc-file-txt
    +
  • + +
  • + +
    PDF
    +
    #icon-rtc-file-PDF
    +
  • + +
  • + +
    代码文件_file-code
    +
    #icon-rtc-file-daimawenjian_file-code
    +
  • + +
  • + +
    警告
    +
    #icon-rtc-file-jinggao
    +
  • + +
  • + +
    红包
    +
    #icon-rtc-file-hongbao
    +
  • + +
  • + +
    圆角矩形
    +
    #icon-rtc-file-yuanjiao-rect
    +
  • + +
  • + +
    圆形
    +
    #icon-rtc-file-circle
    +
  • + +
  • + +
    橡皮擦
    +
    #icon-rtc-file-xiangpica
    +
  • + +
  • + +
    头像 男孩
    +
    #icon-rtc-file-icon-test
    +
  • + +
  • + +
    文字
    +
    #icon-rtc-file-wenzi
    +
  • + +
  • + +
    +
    #icon-rtc-file-zhu
    +
  • + +
  • + +
    云服务器
    +
    #icon-rtc-file-yunfuwuqi
    +
  • + +
  • + +
    矩形
    +
    #icon-rtc-file-juxing
    +
  • + +
  • + +
    圆形
    +
    #icon-rtc-file-yuanxing
    +
  • + +
  • + +
    下载
    +
    #icon-rtc-file-xiazai
    +
  • + +
  • + +
    图片
    +
    #icon-rtc-file-tupian_huaban
    +
  • + +
  • + +
    工具
    +
    #icon-rtc-file-gongju
    +
  • + +
  • + +
    用户反馈
    +
    #icon-rtc-file-yonghufankuibeifen
    +
  • + +
  • + +
    5g
    +
    #icon-rtc-file-five-g
    +
  • + +
  • + +
    3g
    +
    #icon-rtc-file-three-g
    +
  • + +
  • + +
    4g
    +
    #icon-rtc-file-four-g
    +
  • + +
  • + +
    2g
    +
    #icon-rtc-file-two-g
    +
  • + +
  • + +
    正确
    +
    #icon-rtc-file-zhengque
    +
  • + +
+
+

Symbol 引用

+
+ +

这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇文章 + 这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:

+
    +
  • 支持多色图标了,不再受单色限制。
  • +
  • 通过一些技巧,支持像字体那样,通过 font-size, color 来调整样式。
  • +
  • 兼容性较差,支持 IE9+,及现代浏览器。
  • +
  • 浏览器渲染 SVG 的性能一般,还不如 png。
  • +
+

使用步骤如下:

+

第一步:引入项目下面生成的 symbol 代码:

+
<script src="./iconfont.js"></script>
+
+

第二步:加入通用 CSS 代码(引入一次就行):

+
<style>
+.icon {
+  width: 1em;
+  height: 1em;
+  vertical-align: -0.15em;
+  fill: currentColor;
+  overflow: hidden;
+}
+</style>
+
+

第三步:挑选相应图标并获取类名,应用于页面:

+
<svg class="icon" aria-hidden="true">
+  <use xlink:href="#icon-xxx"></use>
+</svg>
+
+
+
+ +
+
+ + + diff --git a/svr/static/layui/font-ext/iconfont.css b/svr/static/layui/font-ext/iconfont.css new file mode 100644 index 0000000..94fd580 --- /dev/null +++ b/svr/static/layui/font-ext/iconfont.css @@ -0,0 +1,323 @@ +@font-face { + font-family: "iconfont"; /* Project id 4147343 */ + src: url('iconfont.woff2?t=1688291642630') format('woff2'), + url('iconfont.woff?t=1688291642630') format('woff'), + url('iconfont.ttf?t=1688291642630') format('truetype'); +} + +.iconfont { + font-family: "iconfont" !important; + font-size: 16px; + font-style: normal; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.icon-rtc-file-sanjiaoxing:before { + content: "\e619"; +} + +.icon-rtc-file-xiangshangsanjiaoxing:before { + content: "\e70f"; +} + +.icon-rtc-file-xingxing:before { + content: "\e61a"; +} + +.icon-rtc-file-xingxing1:before { + content: "\e639"; +} + +.icon-rtc-file-tx-fill-pinghangsibianxing:before { + content: "\e64c"; +} + +.icon-rtc-file-tx-fill-liubianxing:before { + content: "\e64b"; +} + +.icon-rtc-file-pinghangsibianxing:before { + content: "\edf9"; +} + +.icon-rtc-file-hexagon:before { + content: "\e61b"; +} + +.icon-rtc-file-AIzhineng:before { + content: "\e679"; +} + +.icon-rtc-file-PP-:before { + content: "\e618"; +} + +.icon-rtc-file-github:before { + content: "\e66f"; +} + +.icon-rtc-file-Excel:before { + content: "\e602"; +} + +.icon-rtc-file-File:before { + content: "\e603"; +} + +.icon-rtc-file-Word:before { + content: "\e605"; +} + +.icon-rtc-file-PPT:before { + content: "\e606"; +} + +.icon-rtc-file-music:before { + content: "\e607"; +} + +.icon-rtc-file-chengxu:before { + content: "\e608"; +} + +.icon-rtc-file-shipin:before { + content: "\e609"; +} + +.icon-rtc-file-lianjiewenjian:before { + content: "\e60a"; +} + +.icon-rtc-file-tupian:before { + content: "\e60b"; +} + +.icon-rtc-file-yasuobao:before { + content: "\e60c"; +} + +.icon-rtc-file-weizhiwenjian:before { + content: "\e60d"; +} + +.icon-rtc-file-Gif:before { + content: "\e60e"; +} + +.icon-rtc-file-Exe:before { + content: "\e60f"; +} + +.icon-rtc-file-Pdf:before { + content: "\e610"; +} + +.icon-rtc-file-txt1:before { + content: "\e611"; +} + +.icon-rtc-file-WPS:before { + content: "\e612"; +} + +.icon-rtc-file-shujuku:before { + content: "\e613"; +} + +.icon-rtc-file-a-3D:before { + content: "\e614"; +} + +.icon-rtc-file-youjian:before { + content: "\e616"; +} + +.icon-rtc-file-peizhiwenjian:before { + content: "\e617"; +} + +.icon-rtc-file-duoyuyan:before { + content: "\e659"; +} + +.icon-rtc-file-WIFI:before { + content: "\e700"; +} + +.icon-rtc-file-doc:before { + content: "\e652"; +} + +.icon-rtc-file-jpg:before { + content: "\e653"; +} + +.icon-rtc-file-html:before { + content: "\e654"; +} + +.icon-rtc-file-icon_MP-:before { + content: "\e655"; +} + +.icon-rtc-file-png:before { + content: "\e657"; +} + +.icon-rtc-file-dll:before { + content: "\e658"; +} + +.icon-rtc-file-mp4:before { + content: "\e65a"; +} + +.icon-rtc-file-pdf:before { + content: "\e65b"; +} + +.icon-rtc-file-gif:before { + content: "\e65c"; +} + +.icon-rtc-file-exe:before { + content: "\e65d"; +} + +.icon-rtc-file-mpg:before { + content: "\e65e"; +} + +.icon-rtc-file-psd:before { + content: "\e65f"; +} + +.icon-rtc-file-mkv:before { + content: "\e660"; +} + +.icon-rtc-file-xls:before { + content: "\e661"; +} + +.icon-rtc-file-rmvb:before { + content: "\e662"; +} + +.icon-rtc-file-wav:before { + content: "\e664"; +} + +.icon-rtc-file-swf:before { + content: "\e665"; +} + +.icon-rtc-file-avi:before { + content: "\e666"; +} + +.icon-rtc-file-zip1:before { + content: "\e667"; +} + +.icon-rtc-file-othe:before { + content: "\e668"; +} + +.icon-rtc-file-ppt:before { + content: "\e650"; +} + +.icon-rtc-file-txt:before { + content: "\e651"; +} + +.icon-rtc-file-PDF:before { + content: "\e601"; +} + +.icon-rtc-file-daimawenjian_file-code:before { + content: "\e621"; +} + +.icon-rtc-file-jinggao:before { + content: "\e600"; +} + +.icon-rtc-file-hongbao:before { + content: "\e656"; +} + +.icon-rtc-file-yuanjiao-rect:before { + content: "\e64e"; +} + +.icon-rtc-file-circle:before { + content: "\e64f"; +} + +.icon-rtc-file-xiangpica:before { + content: "\e6b8"; +} + +.icon-rtc-file-icon-test:before { + content: "\e672"; +} + +.icon-rtc-file-wenzi:before { + content: "\e6ec"; +} + +.icon-rtc-file-zhu:before { + content: "\e689"; +} + +.icon-rtc-file-yunfuwuqi:before { + content: "\e615"; +} + +.icon-rtc-file-juxing:before { + content: "\e620"; +} + +.icon-rtc-file-yuanxing:before { + content: "\e626"; +} + +.icon-rtc-file-xiazai:before { + content: "\e638"; +} + +.icon-rtc-file-tupian_huaban:before { + content: "\e691"; +} + +.icon-rtc-file-gongju:before { + content: "\e6cf"; +} + +.icon-rtc-file-yonghufankuibeifen:before { + content: "\e604"; +} + +.icon-rtc-file-five-g:before { + content: "\e63f"; +} + +.icon-rtc-file-three-g:before { + content: "\e640"; +} + +.icon-rtc-file-four-g:before { + content: "\e641"; +} + +.icon-rtc-file-two-g:before { + content: "\e642"; +} + +.icon-rtc-file-zhengque:before { + content: "\ec6b"; +} + diff --git a/svr/static/layui/font-ext/iconfont.js b/svr/static/layui/font-ext/iconfont.js new file mode 100644 index 0000000..e1312bf --- /dev/null +++ b/svr/static/layui/font-ext/iconfont.js @@ -0,0 +1 @@ +window._iconfont_svg_string_4147343='',function(c){var l=(l=document.getElementsByTagName("script"))[l.length-1],h=l.getAttribute("data-injectcss"),l=l.getAttribute("data-disable-injectsvg");if(!l){var a,t,F,i,v,p=function(l,h){h.parentNode.insertBefore(l,h)};if(h&&!c.__iconfont__svg__cssinject__){c.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(l){console&&console.log(l)}}a=function(){var l,h=document.createElement("div");h.innerHTML=c._iconfont_svg_string_4147343,(h=h.getElementsByTagName("svg")[0])&&(h.setAttribute("aria-hidden","true"),h.style.position="absolute",h.style.width=0,h.style.height=0,h.style.overflow="hidden",h=h,(l=document.body).firstChild?p(h,l.firstChild):l.appendChild(h))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(a,0):(t=function(){document.removeEventListener("DOMContentLoaded",t,!1),a()},document.addEventListener("DOMContentLoaded",t,!1)):document.attachEvent&&(F=a,i=c.document,v=!1,M(),i.onreadystatechange=function(){"complete"==i.readyState&&(i.onreadystatechange=null,z())})}function z(){v||(v=!0,F())}function M(){try{i.documentElement.doScroll("left")}catch(l){return void setTimeout(M,50)}z()}}(window); \ No newline at end of file diff --git a/svr/static/layui/font-ext/iconfont.json b/svr/static/layui/font-ext/iconfont.json new file mode 100644 index 0000000..2fb3fe1 --- /dev/null +++ b/svr/static/layui/font-ext/iconfont.json @@ -0,0 +1,548 @@ +{ + "id": "4147343", + "name": "file", + "font_family": "iconfont", + "css_prefix_text": "icon-rtc-file-", + "description": "", + "glyphs": [ + { + "icon_id": "3101162", + "name": "三角形", + "font_class": "sanjiaoxing", + "unicode": "e619", + "unicode_decimal": 58905 + }, + { + "icon_id": "6874514", + "name": "向上三角形", + "font_class": "xiangshangsanjiaoxing", + "unicode": "e70f", + "unicode_decimal": 59151 + }, + { + "icon_id": "8727201", + "name": "星星", + "font_class": "xingxing", + "unicode": "e61a", + "unicode_decimal": 58906 + }, + { + "icon_id": "10715456", + "name": "星星", + "font_class": "xingxing1", + "unicode": "e639", + "unicode_decimal": 58937 + }, + { + "icon_id": "14718685", + "name": "tx-fill-平行四边形", + "font_class": "tx-fill-pinghangsibianxing", + "unicode": "e64c", + "unicode_decimal": 58956 + }, + { + "icon_id": "14718689", + "name": "tx-fill-六边形", + "font_class": "tx-fill-liubianxing", + "unicode": "e64b", + "unicode_decimal": 58955 + }, + { + "icon_id": "22383635", + "name": "平行四边形", + "font_class": "pinghangsibianxing", + "unicode": "edf9", + "unicode_decimal": 60921 + }, + { + "icon_id": "27938688", + "name": "六边形", + "font_class": "hexagon", + "unicode": "e61b", + "unicode_decimal": 58907 + }, + { + "icon_id": "6537210", + "name": "AI智能", + "font_class": "AIzhineng", + "unicode": "e679", + "unicode_decimal": 59001 + }, + { + "icon_id": "3827634", + "name": "P2P", + "font_class": "PP-", + "unicode": "e618", + "unicode_decimal": 58904 + }, + { + "icon_id": "14401714", + "name": "github", + "font_class": "github", + "unicode": "e66f", + "unicode_decimal": 58991 + }, + { + "icon_id": "22725966", + "name": "文件类型-Excel", + "font_class": "Excel", + "unicode": "e602", + "unicode_decimal": 58882 + }, + { + "icon_id": "22735864", + "name": "文件类型-文件夹", + "font_class": "File", + "unicode": "e603", + "unicode_decimal": 58883 + }, + { + "icon_id": "22735865", + "name": "文件类型-Word", + "font_class": "Word", + "unicode": "e605", + "unicode_decimal": 58885 + }, + { + "icon_id": "22735866", + "name": "文件类型-PPT", + "font_class": "PPT", + "unicode": "e606", + "unicode_decimal": 58886 + }, + { + "icon_id": "22735867", + "name": "文件类型-音频", + "font_class": "music", + "unicode": "e607", + "unicode_decimal": 58887 + }, + { + "icon_id": "22761828", + "name": "文件类型-程序", + "font_class": "chengxu", + "unicode": "e608", + "unicode_decimal": 58888 + }, + { + "icon_id": "22761829", + "name": "文件类型-视频", + "font_class": "shipin", + "unicode": "e609", + "unicode_decimal": 58889 + }, + { + "icon_id": "22761830", + "name": "文件类型-链接", + "font_class": "lianjiewenjian", + "unicode": "e60a", + "unicode_decimal": 58890 + }, + { + "icon_id": "22761831", + "name": "文件类型-图片", + "font_class": "tupian", + "unicode": "e60b", + "unicode_decimal": 58891 + }, + { + "icon_id": "22761832", + "name": "文件类型-压缩包", + "font_class": "yasuobao", + "unicode": "e60c", + "unicode_decimal": 58892 + }, + { + "icon_id": "22761833", + "name": "文件类型-未知文件", + "font_class": "weizhiwenjian", + "unicode": "e60d", + "unicode_decimal": 58893 + }, + { + "icon_id": "22761834", + "name": "文件类型-Gif", + "font_class": "Gif", + "unicode": "e60e", + "unicode_decimal": 58894 + }, + { + "icon_id": "22761835", + "name": "文件类型-Exe", + "font_class": "Exe", + "unicode": "e60f", + "unicode_decimal": 58895 + }, + { + "icon_id": "22761836", + "name": "文件类型-Pdf", + "font_class": "Pdf", + "unicode": "e610", + "unicode_decimal": 58896 + }, + { + "icon_id": "22761837", + "name": "文件类型-Txt", + "font_class": "txt1", + "unicode": "e611", + "unicode_decimal": 58897 + }, + { + "icon_id": "22767524", + "name": "文件类型-WPS", + "font_class": "WPS", + "unicode": "e612", + "unicode_decimal": 58898 + }, + { + "icon_id": "22767526", + "name": "文件类型-数据库", + "font_class": "shujuku", + "unicode": "e613", + "unicode_decimal": 58899 + }, + { + "icon_id": "22767545", + "name": "文件类型-3D", + "font_class": "a-3D", + "unicode": "e614", + "unicode_decimal": 58900 + }, + { + "icon_id": "22770102", + "name": "文件类型-邮件", + "font_class": "youjian", + "unicode": "e616", + "unicode_decimal": 58902 + }, + { + "icon_id": "22770103", + "name": "文件类型-配置文件", + "font_class": "peizhiwenjian", + "unicode": "e617", + "unicode_decimal": 58903 + }, + { + "icon_id": "658008", + "name": "多语言", + "font_class": "duoyuyan", + "unicode": "e659", + "unicode_decimal": 58969 + }, + { + "icon_id": "1906325", + "name": "WIFI", + "font_class": "WIFI", + "unicode": "e700", + "unicode_decimal": 59136 + }, + { + "icon_id": "4031002", + "name": "doc", + "font_class": "doc", + "unicode": "e652", + "unicode_decimal": 58962 + }, + { + "icon_id": "4031003", + "name": "jpg", + "font_class": "jpg", + "unicode": "e653", + "unicode_decimal": 58963 + }, + { + "icon_id": "4031004", + "name": "html", + "font_class": "html", + "unicode": "e654", + "unicode_decimal": 58964 + }, + { + "icon_id": "4031005", + "name": "mp3", + "font_class": "icon_MP-", + "unicode": "e655", + "unicode_decimal": 58965 + }, + { + "icon_id": "4031006", + "name": "png", + "font_class": "png", + "unicode": "e657", + "unicode_decimal": 58967 + }, + { + "icon_id": "4031007", + "name": "dll", + "font_class": "dll", + "unicode": "e658", + "unicode_decimal": 58968 + }, + { + "icon_id": "4031009", + "name": "mp4", + "font_class": "mp4", + "unicode": "e65a", + "unicode_decimal": 58970 + }, + { + "icon_id": "4031010", + "name": "pdf", + "font_class": "pdf", + "unicode": "e65b", + "unicode_decimal": 58971 + }, + { + "icon_id": "4031011", + "name": "gif", + "font_class": "gif", + "unicode": "e65c", + "unicode_decimal": 58972 + }, + { + "icon_id": "4031012", + "name": "exe", + "font_class": "exe", + "unicode": "e65d", + "unicode_decimal": 58973 + }, + { + "icon_id": "4031013", + "name": "mpg", + "font_class": "mpg", + "unicode": "e65e", + "unicode_decimal": 58974 + }, + { + "icon_id": "4031014", + "name": "psd", + "font_class": "psd", + "unicode": "e65f", + "unicode_decimal": 58975 + }, + { + "icon_id": "4031015", + "name": "mkv", + "font_class": "mkv", + "unicode": "e660", + "unicode_decimal": 58976 + }, + { + "icon_id": "4031016", + "name": "xls", + "font_class": "xls", + "unicode": "e661", + "unicode_decimal": 58977 + }, + { + "icon_id": "4031017", + "name": "rmvb", + "font_class": "rmvb", + "unicode": "e662", + "unicode_decimal": 58978 + }, + { + "icon_id": "4031019", + "name": "wav", + "font_class": "wav", + "unicode": "e664", + "unicode_decimal": 58980 + }, + { + "icon_id": "4031020", + "name": "swf", + "font_class": "swf", + "unicode": "e665", + "unicode_decimal": 58981 + }, + { + "icon_id": "4031021", + "name": "avi", + "font_class": "avi", + "unicode": "e666", + "unicode_decimal": 58982 + }, + { + "icon_id": "4033510", + "name": "zip", + "font_class": "zip1", + "unicode": "e667", + "unicode_decimal": 58983 + }, + { + "icon_id": "4033741", + "name": "othe", + "font_class": "othe", + "unicode": "e668", + "unicode_decimal": 58984 + }, + { + "icon_id": "4031008", + "name": "ppt", + "font_class": "ppt", + "unicode": "e650", + "unicode_decimal": 58960 + }, + { + "icon_id": "4031018", + "name": "txt", + "font_class": "txt", + "unicode": "e651", + "unicode_decimal": 58961 + }, + { + "icon_id": "17880986", + "name": "PDF", + "font_class": "PDF", + "unicode": "e601", + "unicode_decimal": 58881 + }, + { + "icon_id": "33390112", + "name": "代码文件_file-code", + "font_class": "daimawenjian_file-code", + "unicode": "e621", + "unicode_decimal": 58913 + }, + { + "icon_id": "124495", + "name": "警告", + "font_class": "jinggao", + "unicode": "e600", + "unicode_decimal": 58880 + }, + { + "icon_id": "683275", + "name": "红包", + "font_class": "hongbao", + "unicode": "e656", + "unicode_decimal": 58966 + }, + { + "icon_id": "755610", + "name": "圆角矩形", + "font_class": "yuanjiao-rect", + "unicode": "e64e", + "unicode_decimal": 58958 + }, + { + "icon_id": "755612", + "name": "圆形", + "font_class": "circle", + "unicode": "e64f", + "unicode_decimal": 58959 + }, + { + "icon_id": "1057040", + "name": "橡皮擦", + "font_class": "xiangpica", + "unicode": "e6b8", + "unicode_decimal": 59064 + }, + { + "icon_id": "1909028", + "name": "头像 男孩", + "font_class": "icon-test", + "unicode": "e672", + "unicode_decimal": 58994 + }, + { + "icon_id": "4890393", + "name": "文字", + "font_class": "wenzi", + "unicode": "e6ec", + "unicode_decimal": 59116 + }, + { + "icon_id": "6996983", + "name": "猪", + "font_class": "zhu", + "unicode": "e689", + "unicode_decimal": 59017 + }, + { + "icon_id": "9959300", + "name": "云服务器", + "font_class": "yunfuwuqi", + "unicode": "e615", + "unicode_decimal": 58901 + }, + { + "icon_id": "10048835", + "name": "矩形", + "font_class": "juxing", + "unicode": "e620", + "unicode_decimal": 58912 + }, + { + "icon_id": "10048847", + "name": "圆形", + "font_class": "yuanxing", + "unicode": "e626", + "unicode_decimal": 58918 + }, + { + "icon_id": "10715450", + "name": "下载", + "font_class": "xiazai", + "unicode": "e638", + "unicode_decimal": 58936 + }, + { + "icon_id": "12706985", + "name": "图片", + "font_class": "tupian_huaban", + "unicode": "e691", + "unicode_decimal": 59025 + }, + { + "icon_id": "15718632", + "name": "工具", + "font_class": "gongju", + "unicode": "e6cf", + "unicode_decimal": 59087 + }, + { + "icon_id": "21497145", + "name": "用户反馈", + "font_class": "yonghufankuibeifen", + "unicode": "e604", + "unicode_decimal": 58884 + }, + { + "icon_id": "22272771", + "name": "5g", + "font_class": "five-g", + "unicode": "e63f", + "unicode_decimal": 58943 + }, + { + "icon_id": "22272772", + "name": "3g", + "font_class": "three-g", + "unicode": "e640", + "unicode_decimal": 58944 + }, + { + "icon_id": "22272775", + "name": "4g", + "font_class": "four-g", + "unicode": "e641", + "unicode_decimal": 58945 + }, + { + "icon_id": "22272787", + "name": "2g", + "font_class": "two-g", + "unicode": "e642", + "unicode_decimal": 58946 + }, + { + "icon_id": "23949547", + "name": "正确", + "font_class": "zhengque", + "unicode": "ec6b", + "unicode_decimal": 60523 + } + ] +} diff --git a/svr/static/layui/font-ext/iconfont.ttf b/svr/static/layui/font-ext/iconfont.ttf new file mode 100644 index 0000000000000000000000000000000000000000..74a4606ab4d4e3fa674b43baaa73110bdc456865 GIT binary patch literal 30868 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 A@&Et; literal 0 HcmV?d00001 diff --git a/svr/static/layui/font-ext/iconfont.woff b/svr/static/layui/font-ext/iconfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..228b748573d5a20b982d660cb96761c15ff6862f GIT binary patch literal 17640 zcmY&1Mwr$(CZQIE&wr$(Fv27R#zyI#jcGanwb8601KTJP$kEf!9 z1Q0OLe<5}T1pB|$EA{{J|Ly<(kW^I{0RjSs`cLKk4{Ag)`^& zf8ZcT<8-$APyA2&&kscOAIP92z&Nbz-Ms$O693~=|J}>Q74iFG=VzC# zZ>Au{E7#P>%*bfZgvqGU)X2s85!!ffTAFUsG||M!I0z__k0pnhl9fLR06GRb)f8ln zKx7dT2?9jH3oZrpKd-T|N$$YF)WE>Xq+2)uP(&!g+GoLJas(93(#XPU1P*LnPYnl| z&)oApxqa6U007<*L`ju0k;Rcwfr8NCO}%petxPJYDPxV?2ZDmI&`zBJA#ly3auspG z79a4D3X_|d9K^@bax%#4eLx8WIS%Tg;ran-YDKuz7++t1@%-a#PZ2m(^B%lV27W6wWUG*>B|uiTq`tqwiOb^S-|9iQCZh-!qAYJ~IeL{cxHr3wWvqu)fwm74%V^tQ%UR##u zURx2O&~;WGVZhOtgv`;jQB&tN`>baa8Kd`L)8L$^JXZPakaq$%&OM0H)*N@8YZ8RN zlahD!5V(2xy*VC$;FKtecLF8JEkQb5d%~B&J&iuMsEE#4`N(3U*>mvwYD43=y8G+b zt^9x@z^w*dKwKUD0IMD`kG>kJh*bwuz+Mesz*7xdAXtq^30#L@3Bn$_48R%Y7M9;1 zDLirVP?F^muVl}qT)|Ml&_SKU(!o{0wLv^ZsDq_MszbCyb`MpJ;u(Gy(^vMXx}nln zS4-bW~O-RCHL+&3spauQvzQhEuXn~GiZ z>JU7$=#W0s=ukcL=+L(!*=BX4+~#uQ+~#*<+!k>Y+?ISIqPq0Ox}owxOa1o3yP@|% zabWVnxnc3aaA5Z#Fju$`?>M(&+4g>7*$!Ys&j+>Q;X_`ixw8{$7*+-8g`S6HL(RuK z^H+L!Bc`%s!A$)MK$yz%gPzBEBIR>m@bmg99K9nm0o=(wpdlzyVpx_u-JdoT-f(I( zBgXw#2wu6Zz0jF>quxy0>Z|`&Uzz{$^S^fTw($Di&dk+n_+DUu;76hpL6ecWIpGE% zMS$xJY)3RTF@q7VuPeay!H;QzjGaW9;*Cc^H}#LKM_u3E-}6UZ&wD`e`Z>DK*L#$u z4NN}T`c~ImUex>Cwj(&7#jSD2^NCw@kc=0pbgC7Spv#Aft<4wGMSm>X1T-pJ2DY-$ zWH61>iijwAX`|ZNm$Cb1E0a8g51~h0gqOA}(k|6;rlFDzjB%LA{p(iP7uD*Xx zQj)C?92YnG^b(>uGDAr3D*+r@7EAXp(D|`3IIC)&F9pwHt(2$S9Y~5gU4oyCRm{4_ zNaMZt`VV;6CtXFm!kVm5ANGv`xRr=$Fcc`hi(u6mA4-hXiUSdihG>ckveKXDW(3`y zHZYUWSvFtHEmi^;4Hlt%8h?28a}@>bDa)+=of6LqSom`fcrWMdZFYWY%-X9QGfJ`@CD@0?ADFe0V!;@$>^R?8PC>p8q7K6e4hb zKoA~g?2Ekdy&px{jBn!<-1*`fpWWZ8SpeFninS;Bk=hX^|4KWtZLwAQ*u5_bq}-;9 zFwDyvng25ti1G`usb0i4DY`YeCo%V7_Q*&Oh?l4S{_~n+>G%72CiO_DOj$jXpHMHP z$#!eM1FQbdx#M*RHJ^mr8Ph?!{k>h-MrAhZ8K>)aV;=UAl$6hzBNwDX|uuPn0>sH{SA&Oe^8Cd zl0u10pKO0^Yp2HfpjNqkcw{c!!JZxuz?lBjW%t^y_J=3fKllh@2vlGx&0y^y)7%g5 zWZ!0MkK3BopZqt`8`2%uozflQOZdw5Dt#k;)6jw0*?;nrPLhJrceSDiB^Tl3&1y)tUwh^{lU6(W*&$MS9N2B@)D}UM29;<^KrJvL$qkL zH3ETt%=)8ep0P`{Omn|YWhCwohdhwTtdMhg#QFvnA0u;x|WA5BRY8ff}X#AjdD_i{KY2-)7N#_aRnko_ifyZQ#70f zevcQ(Z_u$wJQ3?>7PDX+2{lb*1bV9$(c+%O2vHpvoNo-AFA`+#xtQU|cQoi-2pOV? zWx~*i2?8Wu_afv~PF~(4?|rrJE6MM+oHQ(;iPw{CjkNe@zTpDvCdgL3yv5bKELkC4=2?aM zeM08QY^x;+3T&>L?a1B30)^aYsO+ecsw%m1vszXi*;h;L_C$C$iK(rLio3~$?ppH8 zih>4afmFHevCCQle|Ck0ruq5p`h3I)Zv^o{yjYeb!Hm_MT#i4#>8Y4rm5yizbz5 zWtn~zMVw~gjeU(m++<4HOLfisbBY24DH6*1?&GowjhSz>5e@Wmhd0uO%$`O^B36r8 zb-3P|)L@1GUq`t%7WAF%ZL_&=PCrBsk1MKZgS;h3dXZuq5?rvS9;a)I*ZZ**D9`JL zpQGc?#!15m?7TqE<;@)br(MzShFfP(Eoj;+3!To6H?N5mn_9M;&Kvk^YhA5NVvBSl znXt;LB0vBx5@_EcxT+Q#IRhyin{QrJN^E%uYQ+wQlpbgX7=&a97o0!_H8~m=2MNP5 zGP+pQ*+zKVj7rf6~GRR2taVX)*j5>?XTqW<^&CSvJWMu`8hANXNPKF1aq|Lr6`dVV|&~CO-P8J;uoJp1_ z6&|y&pt71p9c>7f^VI=i;bMEXcbAt?RetGuj<^syE4TbUxN@53j3GK0etD^~T9mz* zo?#r^W8igS`bh2u&*B%XI%Qf6B9faql}kHg>4Vfhr1|B=T9k4uPAde-eoPh z@UBu519jISIcr2cPJKsoe3}+XL9KhdIGvsLX`d}@HctN?3QHWN1fqf8@Xq{hDsg$2 zGKpB4yLei+3GzTv2dXSlFTDb3fa3Mjff*lbQaH038)uF^`gtWXXMLWUNIX{|foT2YVEcXb}kv!xPrhOj9^uGGTY ziI<}sLBsW>U=e!Wy~`kam<*#sCN*43Q>15bTrg8+M49izJi-~GFUJ<%aJ~DAKZ5v-z50q7hCKjS?nWIJIK={YP_qkT+1Tsq7qT2HgNel zze}@$-jm4=U5LbmYp zZyctikMu?8aCsma^ohYU7~nDLzc{-8T4RoUORmr`_c5(LD|m(Yjg@x z=(93y3$km}gEh)G?>D;QAd|{^#xgFhuO|)N1;<#0Glggs69=VaV2pfKgFd+(5_Ko- zk6)Z4I&^no{6Gnzn379sEs#x(qsWs`lDHcoF5xQ-ipSNFr^Z*P301-SPrX>)zwmyo zA#v6f_dyhx`Q-z5x^RUrGLE4(q|K02ljDgWnnuGGtv@j_0#7oRh~<0x!^HR&R`5`c zyB-4x*gyp$l+7p9Y2VqfcAVM9BCGwDwyFQN`0wvQ90dnF7tHKg4vx<; z&9YjFEt3Rxif!_rRUAue)MddzK>fSgLfm3L(!Fi>cP?2hax9fn%};kP&1Z_(FX({! z)o_9A=xVawZ$M3+vUIe{mR0OnA+jQ7$j*OHU8d5MTd!~_D{C3kB)3GNgG4YMt^7cPk9ITN zR}x}=hse|Nk+=^&%bj*|n=!#wSm(uKm&6LLW~VtlYui>_ z`U4ME?B%VKdeV%Jrq@H^pK?Y=8-~N;k=KVu(k>HjfBW z`0njMB??jUDMGsj$uE`~pZYJI&vCVqp!SQPE#z4w!$Fm8Cu_&>_OqjWaf=`3h-jfc zqyS~EM9~gN8;0!dC>f553Iz8IBEgE0LnZ1eRZ@CRGf{r3=FVzowW#Nlnqe2q-!?kL z#YpWc3EDUX8(Sm9oOA?<=Vt@{<)*ITNUX^pHB2-*ETx6Ym10Sjqz?OWQc81=xOnxv zW`G;_Y5~sW)an<2EgfET%tGW3=aa>S{^AMLpv)Z$Msb3VvWDc^vD@w<%^jC!*`lA2 zH2tj+>2h)OLxIX0*Uih_ zH5}`XgipG=<5{?Esjdqbb@+<~_ADO-0h}r?VI?m!5&-n*%9mhz8-U~_VNyrT@ zw9I<#0Wyxsde1GK$e zB+kt~WD92xOtSXeW=7CpLlXw!@5Qvjr8^@5yM^nTND8GXvzm=)>OOCOlD6j_G4Arc zeC+%=)bICfTX;WYSCnQl$?zmG;TyYl@i5onWMYihi@Qj~{i5n+Zx;FcYM zOMAn_K*sfv@>}D=gKdc{>X5KHX3cAq=w5*BkzVM*?E-hr)RX-%*-> zu*UfeV8^Q>aF02hwgy#rM*a=;p4Qz>g+0dq5V8KiEwm7Ex^A0Z?#Pfk_F9+c!x0;%v`z988pm+^Mh z)n5fxS0(HPE#hqIeK1NBHkvZ|A(Ap36RK(>c`QDmdedkyTHoP`< zxQz5;hTg_7tR~2Ek5RJB$U9rQ`tB6>vp?0FBQ3j$AmX{n(8V26VU0N^_mc(S$)JJG zUkdifCM>z5)mQ#7%wn#^IKAt-{;Op98`4EXIWItMZcuEyRs;R)BacYRS@}VzJg)^l zjF^;S2IBa~xVBFrp8{1cnbt*L4}Fh+wC#Tb0?7mM8EcGfJ-MYEjE0(!emH&88Qc)z<`FFwz&b33+;8iqbgw zKEfm^&Ad6j*{|wxsa_Rc8$9ndr5S$?HJdzT0y|&F3AH%)1#+vsyLepgS0YV1T91a; zv$ziTTT$mkC$nMCG3&9E-5SzAfIKK2f~JlE&pXumhgmQ?`o!(AMv2^UZ-izwz>$u!JHX=`jV#5xy$k&oPR`X~#VeMR~eUlI8UT zGrY@ZeWAVGNeY}ETa$4uYZP_*SH>A>+gKM|Mr`&Yn4op(oySIXE(p5UNL*V&i)J+T z5UXLM3Gf=B3~3ls1x6kxl+O_Y_e%PI*y-W}4r&Up(32cW1f$#HLvMy(^>)ck{$a>u z==n|-8eN7e+HqUj22+NUd!<}b-YDl)mW;tLKh3;dtRA9Oap?PBRMk|K6{%8b*f;h0 zakJH%Z0gqS5TT3~U#Hchw4#ZyzJG;PmkgPYniTQ>cn&0tb;5BDKWI^02kfpxSj7>G~TSCGkmmms@v9UQL&%U zISMi%Z|EdB9k4O|^%wF{y8Q=dtkdZh!U5XOaUO-^26NR z{-R6H3Dmk+qtlS9&P;_$u9Wi0aHNGn4>Hfe6)&EyMxM8*-q0dLZ(2@z^sn{JF3d!h zRwoU|6lX5&AW4ErukEr}8Q+b4!?JIB+}Mz)KFf`7ti(#LD|mgrH4yMUKF433+e5r5 zAR2jjtR_|#LC968%;PZEb9Ng&3LDZYO1v*#WSGAk$}U&R59VN?F1MS`k2BLIVo5Wf zPMA=xKW60~qMV4+1JpR9Ze#3qV6x@|s&|ND-SO#g6`y+Fkr~~H6X4HSs5VC@9yc}j&UmUg z3R5j?ZJ13U-Dqid?*ZTqP+C_1D}B9aD&GE{_tfd%=d$_UmsYOA>CUj{in8`+3C$8- zi{ef_Plnfzc~-GVo<%Jfp`C?m>tOPLRmX|2gb4Ks-J<-R-XBp!Ni#fhXw&nHA4+tYN5VKqw6iZM$&(@ z5LjyRO;7C$0XmH`%V2W|W(Thj)6p9(>sGV4sj`QII)+yX+dQn+NB|wap-(1srX5KEo*?Q3 zV(e+NAR?7r=(vxh-g$rL2nX44I+Gqjm5II6oCpL&IK28bM6Vsd@bYrR>p*||?dwAR z#_L{8&MmE}%v5cX32=-EXw(-c6h*3^=r-&@+JQ*YgpoH&R9qE|>BrhYV7QSSZwU6y z_qO>q`*z&6{Wj`$`;fDJQ3os+ZaghNPkqc-V_0`4y&!LN2mDy9EqM}$NPy_{Vdgt1 z(0h>=+L#&?>$VlCnS5)PV8)O{&c{fOrOZsqK6B6;8<=a-28NN@TRo!)9Mz1u>LpQJ zL?tJoedvJ67bp?A?Fxw0_4^6sXLP>qlb_&6TQVgL&#K(=l5r!sxb8VIcCDX0QL+eo zG#`m}bD30IF|puj5i8y9{Cgid!`~${`53G0x+~x#D#G zzy}irvMQ_jl4s$BYhBv%&5zc%}IFdmO6d$ zC9?f9(byMJvEaj3lYpKz+2N!g?ltX{FER;^%`{mGwE+^;?f4IN;subpx6K)!L7hD+ zIzW6fpkx%cUp}84exSgh9{9xSIS%R zE+lMYat7hx2s68^M8_`(1Rr=2Y=WF3;YL^MJT6$Gxs0~9n>~|x&rKzj7Qp|v4#VFA z)IZ*}rbE>@bffy@l>zS1bn$>#%hzioy zO2`M?!Gb9RNC;k{dQfDAC4?YoR(}GO8Jvwx*X*x(P*52kVI}ZCX5A!m;4W*sXGyz2 zu(&C;cCu2_{P9Ak``agy9x@^n_E{=LHR6M!*Hl!atk_(8#lvT!In)?KuLcjO6fAM|!YIZoU!*EsE8@~w-Gzb=%RT$fprukoZ3*(^TAubCE=|(A2Wya40rQ9+q=C=B;L@S8Gvf@#hJ_Yd%nIBw3o$j?ld93&d0 zC@)swRqs51r+@q~aN*Kh&TI{0f%BL$L`5(S)A%03NUwZOkC$Uva*C_wa6@{Ezjy=` z&-T}T01b(5TUQXLX-XfEpb1J2E@XvsMqCu^Zvmz{pkGq3?WoUBnvNx7B3S%0Rx-WFfw4G|>|h-P-6h^w;pYA1@Dy>W6kGbDyhz(1 z_YI2&{wp5Gr2Q7M&~LW6NpqqmYYA9hAsxIl6YJF9zs&k!(a#_WYU)!=5Zt~`L1ukZ zs098rMP+lb`q^a5T_N}swZf*0xx%H#3GURd=^fb-NKB=To)#blV&>FcOyc-#5XcW| zL=WD>rz%GiJ^1PsEVGG{`T*BbSL-vFxS8f!J5HP z?;LC|l;_NwFT)CTxn5$(96JpG?+ljP>(XLl^tSp99l)i;S5IJ@8F9>Nyl%Mp84Y&V z<rBb~I^$x&sHlI@T9B<7W9p@Cz+0y4FTx@%4A=g5&TWc$&tAiRSnPPfU zGhQhqd3hu#ySs)etlK~g({GsyJ?mpkW&;ro#&h@({m94CSH`_IPKW{S8zOhoe64c0 z1VyHg1+;BGXdXC+VR;a)zEKLMUSI}TrvQcn*OIBN^3^Y1Kjp`Kg0n-jd3ps7Ley5Y z#!1Xsst1-usz?FUmHb44KG>c*<_5*w@oUf<4{A^FSB0B^J*Pkqke`=|4a-M4CkNR> z5{mVoT@6MQ*-Ffy*n%^A*MGs7am>%bQ$-lhY^NDWA z`rtYvHr@({6SR`-@qGQMW6p;kZjjqjqyriJ^MaFi=5wVWfM+}_JXrbaFr0CyMuF9- zHghtZMuCPQEkcmEL!9z}BhY8j$)d{~K`tS2yV)ATU$$4Ui}A482GRZXs?S{n&ILr^ zQpYd&yY|8KpQe;vc?nr$^{g@FXF2vjCfN2%sm6qKffe2t+8+gD_;PlK0Njj)fz)On%^&T>B z#yPdF8ic6Zdm$^k71o!KKvKeJFD&+R2Qy;go@*prc=L6qcq1feoORClklz=UVd2rH zRQlTjCYJlrnXrZQ5yl&uYI-bXZ1+5Xu^T&PJ!LT=`?S7NL#2-{N@PiTR6HAv9JI8s zh8E;kfTX&-;N}g&s@!sapm+AKSIlX&6%cw3#a@m@h}-$3@j zdsXS<`?aba{4cjBbjXGGu9gwboBu|AzTDr=Hqv~BQJ%$Xp=4XkWJ`;9B3HguBR7E7 z;}>W!W}>A*7U{f=5t7(TD3i&TA8>4tzij`xfIp|RW z<&Y*7KQb~6FnlcCy&a>_Zf)btt6$W?tf2k@q{otP)?0cl*lSVRqg<@rG?ehmUq7aG@wrR zbTcqlhag&=DTg<*o<)ZEi?7VcJYMB1^2#|Eeeapo3~S6g5f_x-0k%D(JGPr+&%NEn z(m1HJ_3_w)<95qzepU`$i`7~xEbU4kI4uEv421ym$du|bN7-?q z1IL#ll}=j_0v6>q0C55R8huOxeuztS(2n(wh;=R)yaL|B6u|R{kv9<* zreL;ku6QGcz!w8()ZNntgZE`YZ|P0Ny;o)44Wur5n!3;DYMKGfiwffJ$}WLwyS?nI zV-}=~K1;6Oa;mDPknYa4=?d(vm8H!b)*{qZEg>yT0SP|3#Bs$s+}1*~=aFoZH)tY1 zVX}xnv{otb#3DR=HTgNP-$E#GRiJVA5_P-<0;O+|G%Z~3%06xo1_*Mg!1f6XULeND zz3xvr(WFncF9)0;o~UoMxdCc5+M{R`-Sfsj-RqA*KQRU} zHx5;|C2r^zTwVZV-3V4cdE3L=lAVg+zFZ12kCN(H20dgsPni2dJ~NDxK$$)JVrrHm7IzC~>?HT)r#3ra;JCWV2gP(X&D(?>Jite% zjKVvFBRHlrB=fKuGf8~7%x$$w(CaKzOmqA8TXTFV#2~DD!|%nvV2@%Lqy8Lz3Nr?b zfCG84IGU61>O-uVXH%{MXy>D??8~ekG-dc(Ml@A`Eh`+P9N3OTg|}TBpI@ zhr2^)&Yp%#cjsd#=(f1yi7{_{DYnt?=Z7rapU{L0Mn<_S{~JbvNZMYRT1pAIOCw7@ zqY;4*4yJi_nE|WO(Y_fzRecH&aftj(^ZVzp*tRl#0>>zZ!p`9cU(tGOFM9Jh=h-lv z7?y@6Dvx&ZKB%MT=PY2zI@?%(9U>0aJO zI6)}9=fiDNBGZDyzUkhf@5E1d&S~ds02UZA%ou)Mx^lq%J=PGj4_p;N!_NCX&0m#j6Y)rDl{$WHT!5_br6iD z@NF9J@-T;v_bkVx%!1WDO7{!s4ZmaZ75XMZ>wNt!&kcuXg5I|~bCnd-)tOnb;_ho{ z@a!(F0@cSErxFc(3>ELlOEw01P#5#;?L=nsDjV(qWJQahMsoU14CRO~tx!l7wFd3{ zHHqghtM1bPm%hwO1_p^VS}{@aJU?T&K)UO>=vvG-cFtZrgTbGL>UfP>Ru9$31aZlI zO@5kB2{H+><;m7|!H=^hYsevt`-;Mob4l7jNfc>1ledSG8n036lm9w=r8qSGAIer{ zx9gc+!Cyju=O+Ok1FJkn=MoNqd);2VuX{PtL4WD)i0twERiK#4xJH;P97qBYe04HM zUNR!xg6h1UV#8QQ^&QyfPqk6OKhmTkog{+j#Qv-BJHIi-h-U#&}X5 z@b@<7wO(Is&U&-957%Zp<@I}XXy9rGYGhz1k>lH`4IVHjAB9>|powd=7tJa{l~-%o zgtt>~8C^fFtk{z#$&W2lnw|yPK9#EQQyWqTy`0&6JpD1Kx;nqvDXD0!?HdQf2SFW9 z1~>Riw#l5ALI*uL$P?5Z8YFqUC%*_ryXnMdknXz;m=m+6+O91Nm^m>cGO#)J_}{g3-K0lW$w ztK8x%h6mb&6jW%hz^nx9Rf&*SdkzloXo>xn z^Wy_#yrQuzN3i?AF0ghdU1Hj|QCK~w?eAu1=U_^0n^m2jwwZ3Yb^Pqm*LJ~d{3Mew zi$smxA!%XzrQ|;MdJZ!Ip4J*uuxbpB=<^<2Hw1jah6(12U(c6cfXVG+U|(NH%Yp#| z#kWK=HUAG*#vSaTOi>V$G;+@B3&nFHIbP=LCS~VlA|Qj$Y=mvOaPl)m$ynJ zvbYp<=1AmJg*V>Ba{50Pw|i0I+0>1Yd`~BvKP9GcbV?YKzS+CWa}4mQ9(yqctn|P+ zTv15s)RF3RcLKZQMjJs8cyK6qhh$r>0O#mL8{D2r0B3|J`-;BBo-u`12Rk`NqjfF+?A*!vGcFzU2;gPsi>gA{18^>qbu z7VT}vESp_(qCfDK*D@7Gbg^N@P9hXa3qqyx!*DN88Oh69&ucI4HrXY&?!P@Y!H%B; zLci0p-)FFF>$$?6lh^bQ_rkuD-Pv!5g_{%7*~hCkgNA>vO281*k4~c6Fh^K?} z3cnJw^r0$pb8>#4|Amyp)~XCywd*>Ns$L&YTa4;|Pk%~&2KR4_FMjly7#8&}Bp8T> zj{C9omerX}0$t~fV!kjnuUxr^p$5@S+d7N2T|`3puxZzGdFWw+b1zN2fh3D`X$qdhA8=edhd7v_KX%$dIr?m}$^KxTmH!dsx_jcaMW=;q%W_elHd@|L!< zq1owSlaTz7{v3d^FQ?ew?RExJ3Sv0^~7cToJh9&@*D|D#=K5!Q$YhM+Udf6{Xb7sJR0>;b^WMx$tj| zwmi3-zlf1IxAo~qRJ61cY_~q{xQvfHbi1!!Y6-Nx^mw(I~6S`_j#T&q*9Yp z?D$@M)W~)f-W99Jmk^e=u+XS0qB6#x=H`nrG#Ty^GLmcA!SCoZ{BwWd{%i|0K|itS z+}S(J;v|F)er6S;0wc$H@UXd37Eo#=-~>VV zdD4A$H-01sk$lQ-`10j##f&dQD1+?hXZ4{5QCw1@*mfg1d!*)UO^Q&O?N)IFH6 z2gI-`D6So(GBuYP5(F!}sBm!rwUD?6R*|5R4W>2zx}{ei39kvemvJirT^Ul$fKy0F zNugb5KNp&x1eybI0X_}5q^pPluP^W6obdF%a=_qtcnk}KQV8W4Ce*Ji9KZA`A>n%K zVZMqagYRe+)n6(%^&r|89wGAjT?2>MI=m`Gk5n423r|u`+t)&wK7xKb7jwz?8~pCS zpbb$+wXw14hBc8(&6zl6 z+OSh+;K^F_xppljAH5#!?YsW&dR|VsyX)cL*s(!`2W%V<+2$6-tD$5>K;V#K28E)v z5ZnL6&g^AyArjbGn80nk|Lr^HbA3f~W>=kL3$%EH(0iNjksBNSv@D3UU{Us~MwT6m zmD9ACqX>jdn0Q8d9q7}Z%tOBF>W=fx^v(Tbd1ZS=c{ROxl@ftY6|;|Qx`5CLQxM%+ z$g<+(LDY|A5Ya5I!Ge`|4^lqD^3jItb%9e=_WH2vuqZg6lq<3b6$24)fpbJIetv%z z*)J*{eSee)X`%Y2;+`9}08{&q zx3lnto>^2Hfoz#^eU>h>^W+xNZ<{QIMx)lFJBDb(4dRG6k!l}5=D&cszDq_PE)Hg9 zkGtZv6O!2oFJNmU9ZDMf$<*3gT<)-|%x&Xf0@T?*?(yW&%vX9A90&1q$ma`L9&|W^ z(_X@!F7}f$k|5Q&g3ZDyW{vqMC21xc)jG}4^j9aOi&{rBqDrzZrd4K-px5smHK@2{ zZmaZbZG%+L$AR=UJ!ynqPDGB6(VJfs?B3e3Xf-+Sv#o7Vq)+p8H*?vM)Q?u&mBZ^( z9u0%HXl7(^xBvLz#-PuC)e0sEbDSh*oHn3!+S_ktzgOMWJMKz%7uU`|^ZfAxTy?8S z!7+KTc5;46?$wZ}99wU!PS!(h9kOxHOH2iPPY;~)W0EZ~;@ptD!J~#gj(x?6Qy4r) zW29N@c&g^ah|{fN###YYx^WYPTT6YoNj=SNu4a*6Th8caqaE(mhO%NYQCh@{SuQJr z$wlU;R_2P)9RZt7hQEDP!3fyTBo;ng@Wb|#_)#bh2^r?P8Dh&kXC_5TkeFX`lbnL~|NmQ@``BiG^p6+GC zy19+ahwpdg^gb{zpgSXmU|qT_nerP`*9Q!s+nf32bA?#*%Qlux~%TSwzBI!&kMeA}ik41k(_ssBvK9mBO% zaIA;=w~R}sA8gxOs#+~u>Hm_0A147xaE(QPFy|T=&L>I{(()&rFX?a{G<5P~L)JCU zt}SW!7U92+@}-&|P1};7b9>cU4Lr=iD9|UM3UQEwgrV zzv)d^$Y-Wa$L-$j3CY^EpsP=#25zpvRHY4AQ%?Y^3yC+CGhHIub|g{vKF$bEIke`WE=V|NZOu_{rPeHs~L zzUK9azc4yI$*nQB!xeuUjNv~uTvc54?xz`UcgZR7O1G&=_GR7b=!&evD*B5+ zwEElL0^#MOxn~un+lX7|=6%w8q$oOEJ4v^%3rqM$e_n$>wtou-e6k@PNswk&2AJ^V zZZbBCw2K4=Q*FaD7XMnqC>z4fw~Z_a(R0a?g`7NrH3o+XVM3Gfr^dva4kQbp(NUW~ zGALR6X@qYBJW}h~j=?fSDWNhNmT|Z49bF?0@9nbGuTo_$yrW9Jj+Tly z-TSJ3Fnb-?l+EVM8gcV<6GOvpt+FsFJhFK|&N7Ix%3*VSg6^gbZwm1lyDiDjo{TGR zW~;%PwAlbIZz#_wLrtyF@<0ICq2)T&BbVAZ*^uAr*3WVXg0$JOL2#g_~~B^Ft+W{EDA ztHMs5Et9MmG|Famalayj>whCURIt&sYKguRbK*zH$|q?tfD-3wUH-V~&6^;ybRhy5 zPn6GP4Hgw|u)(~hneRnlcN<>}bWOv{X!y)KA(E6#VEP5k0`zp_`M>mbxweLu+1kS! zR`bqolXX4Db$<6D?q!7h{uYJk&i{GpnQiMzF2Wc$&LPVhM}1@YZ>qzVQ3j_K5uKXX zyu6j84J+SiSYwR2rCXT7((>-rFfdE4kC1U}|00{3&ak&fE3|OI@16IZUPtT|jW{_H zd%2{yIvdvk6(xjwRh6D^8O(#5zZ-s5jpW|zh#5mp5ief}Pxshw=q<|7Bj|D^PVUmQM&M~gH0AFYqgm+sS>Q#J2*s6kDH&2&WS6`atg*ixcdx! zKJHPI*)?sr-w10CLl)YTLnf`f6Z;7^+Sn^*&+B3gZLniZb}X^%Pe+|?qq}5*mY7x> z0S6C@Sly!8Ur2>BS?&M(@BP0&^FRj$CUEfgUmS+m9okqzdxK2{-9}Hpg1?vA%~`kr zJp>4f#Qzh41b+J{0CR~BXaE2Jc${NkWME)!_}{<~!;iZMc${NkWME+M zW7@@_&j12UK+FY%3=IFld4xWF-tc7=B54ZRbuHXir!d2>D z!an(1xP}M(2-m6q3O6wEu7#UudEvn7snc^c+o@G((#WLlc#idA6Ho1_Jkd5^nN)Ry z&QTiaRNG^le7op57pcgaL=AbXTV4*REW1K@_h8^Py zAq-MPMRaHRnC=BOh*@d>bx-KF$f+N4g)Rbg&Riq9(!zNrr)dD{jl0gfx^| z%}HXi;txFBt*M0611yWG41Kh@q7#2m%#i#6*pqKpc${rfX>-#s5Y4L`J84OQmKG@Y zeHsWY_gP3&0<>fXX8N(C*s`S5w%k}s?EHG<9s@J5GumD4z58l2wL_Y%{hzim0|Ezi zxbVszRoGsgN|~xv1D5YolV-YaT1@64%Y{3*9C={hwYg%+Tx^hx)4> zuT-XrY-NAvHA16GQ_|Gg>2-S~Q~?=g+z~p78!}Mo?pEI?nOz`^W0GWRBnu$)v9m1HVRvovXBCT3r{ zLvw&`Rijc|n>VGhb$G*FVd%hK)I!9EW}&n~n24r(Mh=*aSn5V{%zW-?F=AG_kuoEn X*Y!mCyfLj%+Bd9L`wdXy<*xt$Y@nk_ literal 0 HcmV?d00001 diff --git a/svr/static/layui/font-ext/iconfont.woff2 b/svr/static/layui/font-ext/iconfont.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..f912c377f56503af02ba9d5f747365710c8105e5 GIT binary patch literal 15076 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