├── .eslintrc.cjs ├── .gitignore ├── .prettierrc.json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── args.json ├── bin ├── start.js └── zuodeploy.js ├── demo ├── args.json ├── c.sh ├── chmod.sh ├── deploy.sh └── temp.sh ├── deploy-master.sh ├── docImages ├── deploy-add-sh.png ├── deploy-log.png ├── deploy-terminal-log.png ├── doc-1-deploy.png ├── doc-2-nginx.png ├── doc-3-terminal.png └── doc-4-deploy-m.png ├── frontend ├── favicon.ico ├── index-old.html ├── index.html └── static │ ├── axios.1.1.2.min.js │ ├── element-plus-2.2.18.min.js │ ├── element-plus.2.2.18.index.css │ ├── lodash.4.17.21.min.js │ ├── socket.io.4.4.1.min.js │ └── vue.3.2.41.min.js ├── index.js ├── package.json ├── publish.sh ├── server ├── index.js └── utils │ ├── logger.js │ └── runCmd.js ├── servertemp.sh └── v1.0.0.md /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | es2021: true, 4 | node: true, 5 | }, 6 | extends: ["eslint:recommended"], 7 | parserOptions: { 8 | ecmaVersion: "latest", 9 | sourceType: "module", 10 | }, 11 | plugins: ["prettier"], 12 | rules: { 13 | "prettier/prettier": "error", 14 | }, 15 | ignorePatterns: ["frontend/static/*"], 16 | }; 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | package-lock.json 4 | dist 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | 15 | # Editor directories and files 16 | .idea 17 | .vscode 18 | *.suo 19 | *.ntvs* 20 | *.njsproj 21 | *.sln 22 | *.sw? 23 | 24 | notesData.json 25 | covertLog.json -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | # CHANGELOG 3 | 4 | ## 1.0.8(2022-11-22) 5 | 6 | - feat: 新增部署脚本超时时间设置 7 | - feat: 将外部引用 static 文件,切换到个人 cdn 8 | - fix: 修复 child 不能正常终止问题 9 | - docs: 更新 README.md 10 | 11 | ## 1.0.7(2022-11-08) 12 | 13 | zuo-deploy 升级为 Linux 操作面板 14 | 15 | - feat: 支持实时终端(轻量)。 16 | - feat: 支持多项目部署、自动化部署脚本管理(增、改、删)。 17 | - feat: 支持 Nginx 配置管理(增、改、删),支持 Nginx 快捷操作。 18 | - feat: 支持 Https 证书文件管理。 19 | 20 | ## 0.3.2(2022-03-06) 21 | 22 | - fix:  修复 log \n 被忽略显示异常的问题,增加推荐的部署 shell 脚本内容 23 | 24 | ## 0.3.1(2022-02-26) 25 | 26 | - feat: 使用 prompt 将端口、密码改为询问方式输入 27 | 28 | ## 0.3.0(2022-02-26) 29 | 30 | - feat: 使用 pm2 改造服务,防止 terminal 中断后进程被杀掉 31 | 32 | ## 0.2.2(2022-02-11) 33 | 34 | - fix: npm 官网 github 链接更正 35 | - fix: socket.io cdn 链接在服务器上运行时异常,将 cdn 替换为官方 cdn 36 | 37 | ## 0.2.0(2022-02-10) 38 | 39 | - feat: 新增 socket 实时输出部署 log 40 | - feat: 启动命令增加端口、密码参数配置 41 | - feat: 引入session, 新增部署接口鉴权、前端登录功能 42 | - feat: 对页面 UI 进行简单修改, 优化提示, 提高 log 展示性能 43 | - feat: 部署 log 加时间戳 44 | - chore: 去掉默认的 ES Module,使用默认的 CommonJS 45 | 46 | ## 0.1.4(2022-02-08) 47 | 48 | - 初步完成自动化部署功能 49 | - koa 提供自动化部署监听服务,请求接口服务,直接开始部署、执行shell脚本。部署完成后在前端页面显示部署 log 50 | - 命令行工具支持 zuodeploy start 开启服务 51 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 dev-zuo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # zuo-deploy 2 | 3 | 基于 Vue3 + Node.js 的轻量 Linux 操作面板,支持简单实时终端、自动化部署、持续集成、Nginx 配置管理/操作、Https 证书管理等。 4 | 5 | ![version-v1.0.8](https://img.shields.io/badge/version-v1.0.8-yellow.svg) ![license-MIT](https://img.shields.io/badge/license-MIT-green.svg) 6 | 7 | **注意:不支持 windows 系统,仅支持 Linux/MacOS 等** 8 | 9 | ![doc-1-deploy.png](./docImages/doc-1-deploy.png) 10 | 11 | ## 使用 12 | 13 | 如果是一台全新的服务器,需要先安装 node、git、nginx,如果已安装,可以跳过这一步 14 | 15 | ```bash 16 | # 以一台全新的 centos 为例,安装基础环境 17 | 18 | # 1、安装 git 19 | yum install git -y 20 | 21 | # 2、使用 nvm 安装 node 22 | git clone https://gitee.com/mirrors/nvm.git ~/.nvm && cd ~/.nvm && git checkout `git describe --abbrev=0 --tags` 23 | echo ". ~/.nvm/nvm.sh" >> /etc/profile 24 | source /etc/profile 25 | nvm install v14.19.0 26 | nvm install 16.19.0 27 | nvm use 14.19.0 28 | # 设置 npm 镜像为淘宝源 29 | npm config set registry https://registry.npmmirror.com/ 30 | 31 | # 3、安装 nginx 32 | yum install -y nginx 33 | ``` 34 | 35 | 安装 36 | ```bash 37 | # 全局安装 38 | npm install zuo-deploy pm2 -g 39 | 40 | # 新建一个目录,用于 zuo-deploy 运行目录,创建的部署脚本会存放到该目录 41 | mkdir zuodeploy; cd zuodeploy; 42 | 43 | # 开启服务 44 | zuodeploy start 45 | # ✔ 请指定部署服务监听端口: … 7777 46 | # ✔ 请设置登录密码(默认:888888) … ****** 47 | 48 | # 访问 127.0.0.1:7777 打开操作界面,密码 888888 49 | # 如果是服务器:服务器ip:7777 50 | ``` 51 | 52 | **注意: 如果使用的是云服务器, 请开放防火墙及配置安全组放行. 以下为示例** 53 | 54 | **配置安全组**: 55 | ![image](https://github.com/Alioth996/zuo-deploy/assets/64628135/f4fad983-0bdd-4773-a7b8-4a9f52fa1b1b) 56 | 57 | **防火墙放行**: 58 | ![image](https://github.com/Alioth996/zuo-deploy/assets/64628135/e46bf610-f3ca-463c-8d8b-d21947c615d5) 59 | 60 | ## 部署脚本管理 61 | 62 | 支持多项目并行部署,log 互不干扰。新建脚本注意文件名需要以 .sh 命名 63 | 64 | ![doc-4-deploy-m.png](./docImages/doc-4-deploy-m.png) 65 | 66 | ### Vue前端项目部署脚本 67 | 68 | 以下为 visitors.zuo11.com 项目自动化部署脚本(vue3+ts+vite) 69 | 70 | ```bash 71 | # 进入项目目录 72 | cd /root/visitors 73 | 74 | # 获取最近更新 75 | git pull; 76 | git log -1; # 查看最近一次提交 log 77 | 78 | # 部署前端服务 79 | cd visitors-fe; 80 | # 如果需要安装新 npm 包 81 | # npm install; 82 | npm run build; 83 | echo '前端服务部署完成' 84 | ``` 85 | ### Node接口服务部署脚本 86 | 87 | 以下为 api.zuo11.com 接口服务自动化部署脚本 88 | 89 | ```bash 90 | # 进入 api.zuo11.com 目录 91 | cd /root/api.zuo11.com 92 | 93 | git config --global core.quotepath false # 防止中文乱码 94 | echo "git pull" 95 | git pull 96 | git log -1 # 查看最近一次提交 log 97 | 98 | # 如果需要安装新 npm 包 99 | # npm install 100 | 101 | echo '重新开启服务' 102 | pm2 delete api.zuo11.com 103 | pm2 start index.js -n 'api.zuo11.com' 104 | echo '部署完成' 105 | ``` 106 | 107 | ### 通用部署脚本 108 | ```bash 109 | echo "开始部署..." 110 | 111 | # 进入项目目录 112 | cd /var/www/hello-world 113 | 114 | # 防止部署 log 中文乱码 115 | git config --global core.quotepath false 116 | 117 | echo "git pull" 118 | git pull 119 | 120 | # 查看最近一次提交 log,了解当前部署的是哪个版本 121 | echo "git log -1" 122 | git log -1 123 | 124 | # 构建相关 125 | # npm install 126 | # 构建 127 | npm run build 128 | 129 | echo "部署完成!" 130 | ``` 131 | 132 | ### 其他任务类脚本 133 | 134 | 除了部署,也可以用于数据备份、跑一些脚本任务。 135 | 136 | ## Nginx/Https证书管理 137 | 138 | 支持 nginx 配置管理、多 nginx 配置管理、https 证书管理、nginx 服务重启等。 139 | 140 | ![doc-2-nginx.png](./docImages/doc-2-nginx.png) 141 | 142 | ### Nginx 配置参考 143 | ```bash 144 | # For more information on configuration, see: 145 | # * Official English Documentation: http://nginx.org/en/docs/ 146 | # * Official Russian Documentation: http://nginx.org/ru/docs/ 147 | 148 | user root; 149 | worker_processes auto; 150 | error_log /var/log/nginx/error.log; 151 | pid /run/nginx.pid; 152 | 153 | # Load dynamic modules. See /usr/share/doc/nginx/README.dynamic. 154 | include /usr/share/nginx/modules/*.conf; 155 | 156 | events { 157 | worker_connections 1024; 158 | } 159 | 160 | http { 161 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 162 | '$status $body_bytes_sent "$http_referer" ' 163 | '"$http_user_agent" "$http_x_forwarded_for"'; 164 | 165 | access_log /var/log/nginx/access.log main; 166 | 167 | sendfile on; 168 | tcp_nopush on; 169 | tcp_nodelay on; 170 | keepalive_timeout 65; 171 | types_hash_max_size 4096; 172 | 173 | include /etc/nginx/mime.types; 174 | default_type application/octet-stream; 175 | 176 | # Load modular configuration files from the /etc/nginx/conf.d directory. 177 | # See http://nginx.org/en/docs/ngx_core_module.html#include 178 | # for more information. 179 | include /etc/nginx/conf.d/*.conf; 180 | 181 | gzip on; 182 | gzip_vary on; 183 | gzip_min_length 1000; 184 | gzip_comp_level 2; 185 | gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml image/jpeg image/gif image/png application/javascript; 186 | 187 | server { 188 | listen 80; 189 | listen [::]:80; 190 | server_name xx.com www.xx.com; 191 | charset utf-8; 192 | 193 | if ($host = 'xx.com') { 194 | rewrite ^/(.*)$ http://www.xx.com/$1 permanent; 195 | } 196 | 197 | #charset koi8-r; 198 | 199 | #access_log logs/host.access.log main; 200 | 201 | location / { 202 | # root C:\Users\Administrator\Desktop\dist; 203 | root /root/xx.com/dist; 204 | index index.html index.htm; 205 | } 206 | 207 | # 配置 404 208 | error_page 404 /root/zuo11.com/dist/404.html; 209 | 210 | # redirect server error pages to the static page /50x.html 211 | # 212 | error_page 500 502 503 504 /50x.html; 213 | location = /50x.html { 214 | root html; 215 | } 216 | } 217 | 218 | server { 219 | listen 80; 220 | server_name demo.xx.com; 221 | charset utf-8; 222 | location / { 223 | root /root/demo.xx.com; 224 | index index.html index.htm; 225 | } 226 | } 227 | 228 | server { 229 | listen 80; 230 | server_name test.xx.com; 231 | charset utf-8; 232 | location / { 233 | root /root/test/test-fe/dist; 234 | index index.html index.htm; 235 | try_files $uri $uri/ /index.html; 236 | } 237 | } 238 | 239 | server { 240 | listen 443 ssl; 241 | server_name api.zuo11.com; 242 | 243 | ssl_certificate cert/3391782_api.xxx.com.pem; 244 | ssl_certificate_key cert/3391782_api.xx.com.key; 245 | 246 | ssl_session_cache shared:SSL:1m; 247 | ssl_session_timeout 5m; 248 | 249 | # ssl_ciphers HIGH:!aNULL:!MD5; 250 | # ssl_prefer_server_ciphers on; 251 | 252 | ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; #使用此加密套件。 253 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #使用该协议进行配置。 254 | ssl_prefer_server_ciphers on; 255 | 256 | location / { 257 | # root html; 258 | # index index.html index.htm; 259 | proxy_pass http://127.0.0.1:7778; 260 | } 261 | } 262 | } 263 | ``` 264 | ## 实时终端 265 | 266 | 支持简单终端,但涉及 vi 等需要等待输入的操作,建议使用 ssh 直连。一般常用功能 267 | 268 | - mkdir, cd, ls, pwd 269 | - chmod 0777 xxx(修改目录权限) 270 | - 其他 terminal 操作 271 | 272 | ![doc-3-terminal.png](./docImages/doc-3-terminal.png) 273 | 274 | ## 全局设置 275 | - 脚本执行超时时间,默认 2 分钟(推荐),可选 5, 10, 30。主要防止服务器 cpu 占用率过高,减少资源/内存占用。 276 | 277 | ## 其他 278 | ### 服务 log 查询 279 | 280 | zuodeploy start 会用 pm2 开启一个 zuodeploy 服务,再次执行 zuodeploy start 会删除原服务,再次开启新服务。**如果开启失败,重新运行一次命令即可** 281 | 282 | ```bash 283 | # 查看 log 284 | pm2 log 285 | pm2 log zuodeploy --lines 1000 # 指定行 286 | ``` 287 | 288 | ### pm2 相关 289 | 290 | 如果直接使用 node xx.js 运行服务,进程很容易被杀掉,这里使用 pm2 以守护进程方式后台运行服务 291 | 292 | ```js 293 | pm2 stop zuodeoploy 294 | pm2 start src/index.js -n 'zuodeoploy' 295 | ``` 296 | 297 | 跨文件传参, 文件读写 298 | 299 | ## 历史版本 300 | 301 | Tag | 描述 | 实现文档 302 | --- | --- | --- 303 | [v0.3.2](https://github.com/zuoxiaobai/zuo-deploy/tree/v0.3.2) | 用 js 写一个 CI、CD 工具 | [Vue + Node.js 从 0 到 1 实现自动化部署工具](http://www.zuo11.com/blog/2022/2/zuo_deploy_think.html) 304 | 305 | ## License 306 | 307 | MIT 308 | -------------------------------------------------------------------------------- /args.json: -------------------------------------------------------------------------------- 1 | {"port":"7777","password":"123"} -------------------------------------------------------------------------------- /bin/start.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const ZuoDeploy = require("../index.js"); 4 | 5 | module.exports = function start(args) { 6 | let zuoDeploy = new ZuoDeploy(); 7 | 8 | zuoDeploy.start(args); 9 | }; 10 | -------------------------------------------------------------------------------- /bin/zuodeploy.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const { program } = require("commander"); 4 | const prompts = require("prompts"); 5 | 6 | program.version(require("../package.json").version); 7 | 8 | program 9 | .command("start") 10 | .description("开启部署监听服务") // description + action 可防止查找 command拼接文件 11 | .option("-p, --port ", "指定部署服务监听端口") 12 | .option("-w, --password ", "设置登录密码") 13 | .action(async (options) => { 14 | let { port, password } = options; 15 | const args = 16 | port && password 17 | ? { port, password } 18 | : await prompts([ 19 | { 20 | type: "number", 21 | name: "port", 22 | initial: 7777, 23 | message: "请指定部署服务监听端口:", 24 | validate: (value) => 25 | value !== "" && (value < 3000 || value > 10000) 26 | ? `端口号必须在 3000 - 10000 之间` 27 | : true, 28 | }, 29 | { 30 | type: "password", 31 | name: "password", 32 | initial: "888888", 33 | message: "请设置登录密码(默认:888888)", 34 | validate: (value) => 35 | value.length < 6 ? `密码需要 6 位以上` : true, 36 | }, 37 | ]); 38 | require("./start")(args); // args 为 { port: 7777, password: '888888' } 39 | }); 40 | 41 | program.parse(); 42 | -------------------------------------------------------------------------------- /demo/args.json: -------------------------------------------------------------------------------- 1 | {"port":7777,"password":"888888"} -------------------------------------------------------------------------------- /demo/c.sh: -------------------------------------------------------------------------------- 1 | pwd -------------------------------------------------------------------------------- /demo/chmod.sh: -------------------------------------------------------------------------------- 1 | ls -------------------------------------------------------------------------------- /demo/deploy.sh: -------------------------------------------------------------------------------- 1 | git pull 2 | npm run build 3 | -------------------------------------------------------------------------------- /demo/temp.sh: -------------------------------------------------------------------------------- 1 | ls -------------------------------------------------------------------------------- /deploy-master.sh: -------------------------------------------------------------------------------- 1 | 2 | # 测试部署脚本 3 | 4 | echo "开始部署..." 5 | 6 | echo "git pull" 7 | git pull 8 | 9 | echo "zuoblog init" 10 | zuoblog init 11 | 12 | echo "部署完成!" -------------------------------------------------------------------------------- /docImages/deploy-add-sh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dev-zuo/zuo-deploy/fa9e6c4d2a5842999233d9ebc96f410633e79de9/docImages/deploy-add-sh.png -------------------------------------------------------------------------------- /docImages/deploy-log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dev-zuo/zuo-deploy/fa9e6c4d2a5842999233d9ebc96f410633e79de9/docImages/deploy-log.png -------------------------------------------------------------------------------- /docImages/deploy-terminal-log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dev-zuo/zuo-deploy/fa9e6c4d2a5842999233d9ebc96f410633e79de9/docImages/deploy-terminal-log.png -------------------------------------------------------------------------------- /docImages/doc-1-deploy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dev-zuo/zuo-deploy/fa9e6c4d2a5842999233d9ebc96f410633e79de9/docImages/doc-1-deploy.png -------------------------------------------------------------------------------- /docImages/doc-2-nginx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dev-zuo/zuo-deploy/fa9e6c4d2a5842999233d9ebc96f410633e79de9/docImages/doc-2-nginx.png -------------------------------------------------------------------------------- /docImages/doc-3-terminal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dev-zuo/zuo-deploy/fa9e6c4d2a5842999233d9ebc96f410633e79de9/docImages/doc-3-terminal.png -------------------------------------------------------------------------------- /docImages/doc-4-deploy-m.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dev-zuo/zuo-deploy/fa9e6c4d2a5842999233d9ebc96f410633e79de9/docImages/doc-4-deploy-m.png -------------------------------------------------------------------------------- /frontend/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dev-zuo/zuo-deploy/fa9e6c4d2a5842999233d9ebc96f410633e79de9/frontend/favicon.ico -------------------------------------------------------------------------------- /frontend/index-old.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | zuo-deploy 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 43 | 44 | 45 | 46 |
47 | 55 | 56 |
57 | 部署 58 |
59 |

部署日志:

60 |
61 |
 62 |             

{{text}}

63 |
64 |
请点击部署
65 |
66 |
67 | 68 |
69 |
70 | 141 | 142 | 143 | -------------------------------------------------------------------------------- /frontend/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | zuo-deploy 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 24 | 157 | 158 | 159 | 160 |
161 | 162 | 167 | 175 | 176 | 177 |
178 |
179 | 180 | ZuoDeploy 181 | 182 |
183 | 185 | {{ item.title }} 186 | 187 |
188 |
189 |
190 | 文档 191 | Github 192 |
193 |
194 | 195 |
196 | 197 |
198 |

当前执行路径:{{processCwd}} 199 |

200 | 201 |
202 | 运行前清空日志 203 | 运行 204 |
205 |
206 |
207 |
208 |

日志 清空日志 209 |

210 |
211 |
212 |
 213 |             
{{text}}
214 |
215 |
216 |
217 |
218 |
219 | 220 | 221 | 222 |
223 |
224 |

{{ processCwd }}目录脚本文件

225 | 新增脚本(部署、运维) 226 |
227 |
228 | 229 | 230 | 231 | 232 |
233 |
234 |
235 | 236 | 运行 237 | 238 | 239 | 清空日志+运行 240 | 241 | 242 | 修改 243 | 244 | 245 | 删除 246 | 247 |
248 |
{{shellList[curShellTabIndex].content}}
249 |
250 |
251 | 暂无 shell 脚本文件 252 |
253 |
254 |
255 |

256 | 日志 257 | 清空日志 258 | 259 |

260 |
261 |
262 |
 263 |             
{{text}}
264 |
265 |
266 |
267 |
268 |
269 | 270 | 271 | 272 |
273 |
274 |
275 | 当前服务器系统: 276 | 277 | 278 | {{item.key}} 279 | 280 | 281 |
282 |

Nginx 操作

283 | 启动nginx 284 | 重启nginx 285 | 停止nginx 286 |
287 |
288 |
289 |
配置目录: {{NGINX_PATH_LIST[curNginxSysIndex].path}}
290 |
多配置目录: {{NGINX_PATH_LIST[curNginxSysIndex].multiplePath}}
291 |
项目目录: {{NGINX_PATH_LIST[curNginxSysIndex].defaultProjectPath}}
292 |
https证书目录: {{NGINX_PATH_LIST[curNginxSysIndex].path}}/cert
293 |
294 |
295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 |
303 |
304 | 加载 Nginx 配置文件 305 | 当前文件: 306 | 307 |
308 |
309 |
310 | 修改 311 | 删除 312 |
313 |
{{mainNginxContent}}
314 |
315 |
316 | 317 | 318 | 319 |
320 |
321 | 加载 Nginx 配置文件 322 | 新增 323 | 当前目录: 324 | 325 |
326 | 327 |
328 | 329 | 331 | 332 | 333 |
334 |
335 |
336 |
337 | 修改 338 | 删除 339 |
340 |
{{nginxFileList[curNginxFileIndex].content}}
341 |
342 |
343 |
344 | 暂无 Nginx 配置文件 345 |
346 | 347 |
348 | 349 | 350 | 351 |
352 |
353 | 点击查看 Nginx Https 证书参考配置 354 |
355 | 相关链接: 356 | 腾讯云ssl申请免费证书、 357 | Nginx 服务器 SSL 证书安装部署 358 |
359 |
360 |
 361 | # 阿里云 windows 服务器 HTTPS server 配置参考(实际配置以官方文档为主)
 362 | # http://www.zuo11.com/blog/2020/6/nginx_https.html
 363 | server {
 364 |     listen       443 ssl;
 365 |     server_name  api.zuo11.com;
 366 | 
 367 |     # ssl 证书建议放在 nginx 默认目录下的 cert 目录下
 368 |     ssl_certificate     cert\3391782_api.zuo11.com.pem;
 369 |     ssl_certificate_key cert\3391782_api.zuo11.com.key;
 370 | 
 371 |     ssl_session_cache    shared:SSL:1m;
 372 |     ssl_session_timeout  5m;
 373 | 
 374 |     ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;  #使用此加密套件。
 375 |     ssl_protocols TLSv1 TLSv1.1 TLSv1.2;   #使用该协议进行配置。
 376 |     ssl_prefer_server_ciphers on;
 377 | 
 378 |     location / {
 379 |         # root   html;
 380 |         # index  index.html index.htm;
 381 |         proxy_pass http://127.0.0.1:9000;
 382 |     }
 383 | }
 384 |           
385 |
386 |
387 |
388 | 加载当前目录证书文件 389 | 当前目录: 390 | 391 |
392 | 393 |
394 | 395 | 396 |
397 |
398 |
399 | {{ item.name }} 400 | 删除 401 |
402 |
暂无数据
403 |
404 | 405 |
406 | 407 |
408 | 409 | 410 | 411 |
412 |
413 | 脚本执行超时时间: 414 | 415 | 416 | 417 | 418 | 419 | 420 |
421 |
422 | 423 | 424 | 425 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 447 | 448 | 449 | 450 | 451 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 473 | 474 | 475 |
476 |
477 | 1008 | 1009 | 1010 | -------------------------------------------------------------------------------- /frontend/static/axios.1.1.2.min.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).axios=t()}(this,(function(){"use strict";function e(t){return e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},e(t)}function t(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function n(e,t){for(var n=0;n2&&void 0!==arguments[2]?arguments[2]:{},s=i.allOwnKeys,a=void 0!==s&&s;if(null!=t)if("object"!==e(t)&&(t=[t]),l(t))for(r=0,o=t.length;r3&&void 0!==arguments[3]?arguments[3]:{},i=r.allOwnKeys;return S(t,(function(t,r){n&&m(t)?e[r]=o(t,n):e[r]=t}),{allOwnKeys:i}),e},trim:function(e){return e.trim?e.trim():e.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,"")},stripBOM:function(e){return 65279===e.charCodeAt(0)&&(e=e.slice(1)),e},inherits:function(e,t,n,r){e.prototype=Object.create(t.prototype,r),e.prototype.constructor=e,Object.defineProperty(e,"super",{value:t.prototype}),n&&Object.assign(e.prototype,n)},toFlatObject:function(e,t,n,r){var o,i,s,u={};if(t=t||{},null==e)return t;do{for(i=(o=Object.getOwnPropertyNames(e)).length;i-- >0;)s=o[i],r&&!r(s,e,t)||u[s]||(t[s]=e[s],u[s]=!0);e=!1!==n&&a(e)}while(e&&(!n||n(e,t))&&e!==Object.prototype);return t},kindOf:u,kindOfTest:c,endsWith:function(e,t,n){e=String(e),(void 0===n||n>e.length)&&(n=e.length),n-=t.length;var r=e.indexOf(t,n);return-1!==r&&r===n},toArray:function(e){if(!e)return null;if(l(e))return e;var t=e.length;if(!v(t))return null;for(var n=new Array(t);t-- >0;)n[t]=e[t];return n},forEachEntry:function(e,t){for(var n,r=(e&&e[Symbol.iterator]).call(e);(n=r.next())&&!n.done;){var o=n.value;t.call(e,o[0],o[1])}},matchAll:function(e,t){for(var n,r=[];null!==(n=e.exec(t));)r.push(n);return r},isHTMLForm:T,hasOwnProperty:x,hasOwnProp:x,reduceDescriptors:N,freezeMethods:function(e){N(e,(function(t,n){var r=e[n];m(r)&&(t.enumerable=!1,"writable"in t?t.writable=!1:t.set||(t.set=function(){throw Error("Can not read-only method '"+n+"'")}))}))},toObjectSet:function(e,t){var n={},r=function(e){e.forEach((function(e){n[e]=!0}))};return l(e)?r(e):r(String(e).split(t)),n},toCamelCase:function(e){return e.toLowerCase().replace(/[_-\s]([a-z\d])(\w*)/g,(function(e,t,n){return t.toUpperCase()+n}))},noop:function(){},toFiniteNumber:function(e,t){return e=+e,Number.isFinite(e)?e:t}};function _(e,t,n,r,o){Error.call(this),Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):this.stack=(new Error).stack,this.message=e,this.name="AxiosError",t&&(this.code=t),n&&(this.config=n),r&&(this.request=r),o&&(this.response=o)}P.inherits(_,Error,{toJSON:function(){return{message:this.message,name:this.name,description:this.description,number:this.number,fileName:this.fileName,lineNumber:this.lineNumber,columnNumber:this.columnNumber,stack:this.stack,config:this.config,code:this.code,status:this.response&&this.response.status?this.response.status:null}}});var B=_.prototype,D={};["ERR_BAD_OPTION_VALUE","ERR_BAD_OPTION","ECONNABORTED","ETIMEDOUT","ERR_NETWORK","ERR_FR_TOO_MANY_REDIRECTS","ERR_DEPRECATED","ERR_BAD_RESPONSE","ERR_BAD_REQUEST","ERR_CANCELED","ERR_NOT_SUPPORT","ERR_INVALID_URL"].forEach((function(e){D[e]={value:e}})),Object.defineProperties(_,D),Object.defineProperty(B,"isAxiosError",{value:!0}),_.from=function(e,t,n,r,o,i){var s=Object.create(B);return P.toFlatObject(e,s,(function(e){return e!==Error.prototype}),(function(e){return"isAxiosError"!==e})),_.call(s,e.message,t,n,r,o),s.cause=e,s.name=e.name,i&&Object.assign(s,i),s};var F="object"==("undefined"==typeof self?"undefined":e(self))?self.FormData:window.FormData;function U(e){return P.isPlainObject(e)||P.isArray(e)}function k(e){return P.endsWith(e,"[]")?e.slice(0,-2):e}function L(e,t,n){return e?e.concat(t).map((function(e,t){return e=k(e),!n&&t?"["+e+"]":e})).join(n?".":""):t}var q=P.toFlatObject(P,{},null,(function(e){return/^is[A-Z]/.test(e)}));function z(t,n,r){if(!P.isObject(t))throw new TypeError("target must be an object");n=n||new(F||FormData);var o,i=(r=P.toFlatObject(r,{metaTokens:!0,dots:!1,indexes:!1},!1,(function(e,t){return!P.isUndefined(t[e])}))).metaTokens,s=r.visitor||l,a=r.dots,u=r.indexes,c=(r.Blob||"undefined"!=typeof Blob&&Blob)&&((o=n)&&P.isFunction(o.append)&&"FormData"===o[Symbol.toStringTag]&&o[Symbol.iterator]);if(!P.isFunction(s))throw new TypeError("visitor must be a function");function f(e){if(null===e)return"";if(P.isDate(e))return e.toISOString();if(!c&&P.isBlob(e))throw new _("Blob is not supported. Use a Buffer instead.");return P.isArrayBuffer(e)||P.isTypedArray(e)?c&&"function"==typeof Blob?new Blob([e]):Buffer.from(e):e}function l(t,r,o){var s=t;if(t&&!o&&"object"===e(t))if(P.endsWith(r,"{}"))r=i?r:r.slice(0,-2),t=JSON.stringify(t);else if(P.isArray(t)&&function(e){return P.isArray(e)&&!e.some(U)}(t)||P.isFileList(t)||P.endsWith(r,"[]")&&(s=P.toArray(t)))return r=k(r),s.forEach((function(e,t){!P.isUndefined(e)&&n.append(!0===u?L([r],t,a):null===u?r:r+"[]",f(e))})),!1;return!!U(t)||(n.append(L(o,r,a),f(t)),!1)}var d=[],h=Object.assign(q,{defaultVisitor:l,convertValue:f,isVisitable:U});if(!P.isObject(t))throw new TypeError("data must be an object");return function e(t,r){if(!P.isUndefined(t)){if(-1!==d.indexOf(t))throw Error("Circular reference detected in "+r.join("."));d.push(t),P.forEach(t,(function(t,o){!0===(!P.isUndefined(t)&&s.call(n,t,P.isString(o)?o.trim():o,r,h))&&e(t,r?r.concat(o):[o])})),d.pop()}}(t),n}function I(e){var t={"!":"%21","'":"%27","(":"%28",")":"%29","~":"%7E","%20":"+","%00":"\0"};return encodeURIComponent(e).replace(/[!'()~]|%20|%00/g,(function(e){return t[e]}))}function M(e,t){this._pairs=[],e&&z(e,this,t)}var J=M.prototype;function H(e){return encodeURIComponent(e).replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+").replace(/%5B/gi,"[").replace(/%5D/gi,"]")}function V(e,t,n){if(!t)return e;var r=e.indexOf("#");-1!==r&&(e=e.slice(0,r));var o=n&&n.encode||H,i=P.isURLSearchParams(t)?t.toString():new M(t,n).toString(o);return i&&(e+=(-1===e.indexOf("?")?"?":"&")+i),e}J.append=function(e,t){this._pairs.push([e,t])},J.toString=function(e){var t=e?function(t){return e.call(this,t,I)}:I;return this._pairs.map((function(e){return t(e[0])+"="+t(e[1])}),"").join("&")};var W,K=function(){function e(){t(this,e),this.handlers=[]}return r(e,[{key:"use",value:function(e,t,n){return this.handlers.push({fulfilled:e,rejected:t,synchronous:!!n&&n.synchronous,runWhen:n?n.runWhen:null}),this.handlers.length-1}},{key:"eject",value:function(e){this.handlers[e]&&(this.handlers[e]=null)}},{key:"clear",value:function(){this.handlers&&(this.handlers=[])}},{key:"forEach",value:function(e){P.forEach(this.handlers,(function(t){null!==t&&e(t)}))}}]),e}(),X={silentJSONParsing:!0,forcedJSONParsing:!0,clarifyTimeoutError:!1},$="undefined"!=typeof URLSearchParams?URLSearchParams:M,Q=FormData,G=("undefined"==typeof navigator||"ReactNative"!==(W=navigator.product)&&"NativeScript"!==W&&"NS"!==W)&&"undefined"!=typeof window&&"undefined"!=typeof document,Y={isBrowser:!0,classes:{URLSearchParams:$,FormData:Q,Blob:Blob},isStandardBrowserEnv:G,protocols:["http","https","file","blob","url","data"]};function Z(e){function t(e,n,r,o){var i=e[o++],s=Number.isFinite(+i),a=o>=e.length;return i=!i&&P.isArray(r)?r.length:i,a?(P.hasOwnProp(r,i)?r[i]=[r[i],n]:r[i]=n,!s):(r[i]&&P.isObject(r[i])||(r[i]=[]),t(e,n,r[i],o)&&P.isArray(r[i])&&(r[i]=function(e){var t,n,r={},o=Object.keys(e),i=o.length;for(t=0;t0;)if(t===(n=r[o]).toLowerCase())return n;return null}function le(e,t){e&&this.set(e),this[se]=t||null}function de(e,t){var n=0,r=function(e,t){e=e||10;var n,r=new Array(e),o=new Array(e),i=0,s=0;return t=void 0!==t?t:1e3,function(a){var u=Date.now(),c=o[s];n||(n=u),r[i]=a,o[i]=u;for(var f=s,l=0;f!==i;)l+=r[f++],f%=e;if((i=(i+1)%e)===s&&(s=(s+1)%e),!(u-n-1,i=P.isObject(e);if(i&&P.isHTMLForm(e)&&(e=new FormData(e)),P.isFormData(e))return o&&o?JSON.stringify(Z(e)):e;if(P.isArrayBuffer(e)||P.isBuffer(e)||P.isStream(e)||P.isFile(e)||P.isBlob(e))return e;if(P.isArrayBufferView(e))return e.buffer;if(P.isURLSearchParams(e))return t.setContentType("application/x-www-form-urlencoded;charset=utf-8",!1),e.toString();if(i){if(r.indexOf("application/x-www-form-urlencoded")>-1)return function(e,t){return z(e,new Y.classes.URLSearchParams,Object.assign({visitor:function(e,t,n,r){return Y.isNode&&P.isBuffer(e)?(this.append(t,e.toString("base64")),!1):r.defaultVisitor.apply(this,arguments)}},t))}(e,this.formSerializer).toString();if((n=P.isFileList(e))||r.indexOf("multipart/form-data")>-1){var s=this.env&&this.env.FormData;return z(n?{"files[]":e}:e,s&&new s,this.formSerializer)}}return i||o?(t.setContentType("application/json",!1),function(e,t,n){if(P.isString(e))try{return(t||JSON.parse)(e),P.trim(e)}catch(e){if("SyntaxError"!==e.name)throw e}return(n||JSON.stringify)(e)}(e)):e}],transformResponse:[function(e){var t=this.transitional||be.transitional,n=t&&t.forcedJSONParsing,r="json"===this.responseType;if(e&&P.isString(e)&&(n&&!this.responseType||r)){var o=!(t&&t.silentJSONParsing)&&r;try{return JSON.parse(e)}catch(e){if(o){if("SyntaxError"===e.name)throw _.from(e,_.ERR_BAD_RESPONSE,this,null,this.response);throw e}}}return e}],timeout:0,xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",maxContentLength:-1,maxBodyLength:-1,env:{FormData:Y.classes.FormData,Blob:Y.classes.Blob},validateStatus:function(e){return e>=200&&e<300},headers:{common:{Accept:"application/json, text/plain, */*"}}};function ge(e,t){var n=this||be,r=t||n,o=le.from(r.headers),i=r.data;return P.forEach(e,(function(e){i=e.call(n,i,o.normalize(),t?t.status:void 0)})),o.normalize(),i}function Ee(e){return!(!e||!e.__CANCEL__)}function we(e){if(e.cancelToken&&e.cancelToken.throwIfRequested(),e.signal&&e.signal.aborted)throw new re}function Oe(e){return we(e),e.headers=le.from(e.headers),e.data=ge.call(e,e.transformRequest),(e.adapter||be.adapter)(e).then((function(t){return we(e),t.data=ge.call(e,e.transformResponse,t),t.headers=le.from(t.headers),t}),(function(t){return Ee(t)||(we(e),t&&t.response&&(t.response.data=ge.call(e,e.transformResponse,t.response),t.response.headers=le.from(t.response.headers))),Promise.reject(t)}))}function Re(e,t){t=t||{};var n={};function r(e,t){return P.isPlainObject(e)&&P.isPlainObject(t)?P.merge(e,t):P.isPlainObject(t)?P.merge({},t):P.isArray(t)?t.slice():t}function o(n){return P.isUndefined(t[n])?P.isUndefined(e[n])?void 0:r(void 0,e[n]):r(e[n],t[n])}function i(e){if(!P.isUndefined(t[e]))return r(void 0,t[e])}function s(n){return P.isUndefined(t[n])?P.isUndefined(e[n])?void 0:r(void 0,e[n]):r(void 0,t[n])}function a(n){return n in t?r(e[n],t[n]):n in e?r(void 0,e[n]):void 0}var u={url:i,method:i,data:i,baseURL:s,transformRequest:s,transformResponse:s,paramsSerializer:s,timeout:s,timeoutMessage:s,withCredentials:s,adapter:s,responseType:s,xsrfCookieName:s,xsrfHeaderName:s,onUploadProgress:s,onDownloadProgress:s,decompress:s,maxContentLength:s,maxBodyLength:s,beforeRedirect:s,transport:s,httpAgent:s,httpsAgent:s,cancelToken:s,socketPath:s,responseEncoding:s,validateStatus:a};return P.forEach(Object.keys(e).concat(Object.keys(t)),(function(e){var t=u[e]||o,r=t(e);P.isUndefined(r)&&t!==a||(n[e]=r)})),n}P.forEach(["delete","get","head"],(function(e){be.headers[e]={}})),P.forEach(["post","put","patch"],(function(e){be.headers[e]=P.merge(ve)}));var Se="1.1.2",Ae={};["object","boolean","number","function","string","symbol"].forEach((function(t,n){Ae[t]=function(r){return e(r)===t||"a"+(n<1?"n ":" ")+t}}));var je={};Ae.transitional=function(e,t,n){function r(e,t){return"[Axios v1.1.2] Transitional option '"+e+"'"+t+(n?". "+n:"")}return function(n,o,i){if(!1===e)throw new _(r(o," has been removed"+(t?" in "+t:"")),_.ERR_DEPRECATED);return t&&!je[o]&&(je[o]=!0,console.warn(r(o," has been deprecated since v"+t+" and will be removed in the near future"))),!e||e(n,o,i)}};var Te={assertOptions:function(t,n,r){if("object"!==e(t))throw new _("options must be an object",_.ERR_BAD_OPTION_VALUE);for(var o=Object.keys(t),i=o.length;i-- >0;){var s=o[i],a=n[s];if(a){var u=t[s],c=void 0===u||a(u,s,t);if(!0!==c)throw new _("option "+s+" must be "+c,_.ERR_BAD_OPTION_VALUE)}else if(!0!==r)throw new _("Unknown option "+s,_.ERR_BAD_OPTION)}},validators:Ae},xe=Te.validators,Ce=function(){function e(n){t(this,e),this.defaults=n,this.interceptors={request:new K,response:new K}}return r(e,[{key:"request",value:function(e,t){"string"==typeof e?(t=t||{}).url=e:t=e||{};var n=(t=Re(this.defaults,t)).transitional;void 0!==n&&Te.assertOptions(n,{silentJSONParsing:xe.transitional(xe.boolean),forcedJSONParsing:xe.transitional(xe.boolean),clarifyTimeoutError:xe.transitional(xe.boolean)},!1),t.method=(t.method||this.defaults.method||"get").toLowerCase();var r=t.headers&&P.merge(t.headers.common,t.headers[t.method]);r&&P.forEach(["delete","get","head","post","put","patch","common"],(function(e){delete t.headers[e]})),t.headers=new le(t.headers,r);var o=[],i=!0;this.interceptors.request.forEach((function(e){"function"==typeof e.runWhen&&!1===e.runWhen(t)||(i=i&&e.synchronous,o.unshift(e.fulfilled,e.rejected))}));var s,a=[];this.interceptors.response.forEach((function(e){a.push(e.fulfilled,e.rejected)}));var u,c=0;if(!i){var f=[Oe.bind(this),void 0];for(f.unshift.apply(f,o),f.push.apply(f,a),u=f.length,s=Promise.resolve(t);c0;)o._listeners[t](e);o._listeners=null}})),this.promise.then=function(e){var t,n=new Promise((function(e){o.subscribe(e),t=e})).then(e);return n.cancel=function(){o.unsubscribe(t)},n},n((function(e,t,n){o.reason||(o.reason=new re(e,t,n),r(o.reason))}))}return r(e,[{key:"throwIfRequested",value:function(){if(this.reason)throw this.reason}},{key:"subscribe",value:function(e){this.reason?e(this.reason):this._listeners?this._listeners.push(e):this._listeners=[e]}},{key:"unsubscribe",value:function(e){if(this._listeners){var t=this._listeners.indexOf(e);-1!==t&&this._listeners.splice(t,1)}}}],[{key:"source",value:function(){var t;return{token:new e((function(e){t=e})),cancel:t}}}]),e}();var Pe=function e(t){var n=new Ce(t),r=o(Ce.prototype.request,n);return P.extend(r,Ce.prototype,n,{allOwnKeys:!0}),P.extend(r,n,null,{allOwnKeys:!0}),r.create=function(n){return e(Re(t,n))},r}(be);return Pe.Axios=Ce,Pe.CanceledError=re,Pe.CancelToken=Ne,Pe.isCancel=Ee,Pe.VERSION=Se,Pe.toFormData=z,Pe.AxiosError=_,Pe.Cancel=Pe.CanceledError,Pe.all=function(e){return Promise.all(e)},Pe.spread=function(e){return function(t){return e.apply(null,t)}},Pe.isAxiosError=function(e){return P.isObject(e)&&!0===e.isAxiosError},Pe.formToJSON=function(e){return Z(P.isHTMLForm(e)?new FormData(e):e)},Pe})); 2 | //# sourceMappingURL=axios.min.js.map 3 | -------------------------------------------------------------------------------- /frontend/static/lodash.4.17.21.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Lodash 4 | * Copyright OpenJS Foundation and other contributors 5 | * Released under MIT license 6 | * Based on Underscore.js 1.8.3 7 | * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors 8 | */ 9 | (function(){function n(n,t,r){switch(r.length){case 0:return n.call(t);case 1:return n.call(t,r[0]);case 2:return n.call(t,r[0],r[1]);case 3:return n.call(t,r[0],r[1],r[2])}return n.apply(t,r)}function t(n,t,r,e){for(var u=-1,i=null==n?0:n.length;++u-1}function f(n,t,r){for(var e=-1,u=null==n?0:n.length;++e-1;);return r}function L(n,t){for(var r=n.length;r--&&y(t,n[r],0)>-1;);return r}function C(n,t){for(var r=n.length,e=0;r--;)n[r]===t&&++e; 14 | return e}function U(n){return"\\"+Yr[n]}function B(n,t){return null==n?X:n[t]}function T(n){return Nr.test(n)}function $(n){return Pr.test(n)}function D(n){for(var t,r=[];!(t=n.next()).done;)r.push(t.value);return r}function M(n){var t=-1,r=Array(n.size);return n.forEach(function(n,e){r[++t]=[e,n]}),r}function F(n,t){return function(r){return n(t(r))}}function N(n,t){for(var r=-1,e=n.length,u=0,i=[];++r>>1,$n=[["ary",mn],["bind",_n],["bindKey",vn],["curry",yn],["curryRight",dn],["flip",jn],["partial",bn],["partialRight",wn],["rearg",xn]],Dn="[object Arguments]",Mn="[object Array]",Fn="[object AsyncFunction]",Nn="[object Boolean]",Pn="[object Date]",qn="[object DOMException]",Zn="[object Error]",Kn="[object Function]",Vn="[object GeneratorFunction]",Gn="[object Map]",Hn="[object Number]",Jn="[object Null]",Yn="[object Object]",Qn="[object Promise]",Xn="[object Proxy]",nt="[object RegExp]",tt="[object Set]",rt="[object String]",et="[object Symbol]",ut="[object Undefined]",it="[object WeakMap]",ot="[object WeakSet]",ft="[object ArrayBuffer]",ct="[object DataView]",at="[object Float32Array]",lt="[object Float64Array]",st="[object Int8Array]",ht="[object Int16Array]",pt="[object Int32Array]",_t="[object Uint8Array]",vt="[object Uint8ClampedArray]",gt="[object Uint16Array]",yt="[object Uint32Array]",dt=/\b__p \+= '';/g,bt=/\b(__p \+=) '' \+/g,wt=/(__e\(.*?\)|\b__t\)) \+\n'';/g,mt=/&(?:amp|lt|gt|quot|#39);/g,xt=/[&<>"']/g,jt=RegExp(mt.source),At=RegExp(xt.source),kt=/<%-([\s\S]+?)%>/g,Ot=/<%([\s\S]+?)%>/g,It=/<%=([\s\S]+?)%>/g,Rt=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,zt=/^\w*$/,Et=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,St=/[\\^$.*+?()[\]{}|]/g,Wt=RegExp(St.source),Lt=/^\s+/,Ct=/\s/,Ut=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,Bt=/\{\n\/\* \[wrapped with (.+)\] \*/,Tt=/,? & /,$t=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,Dt=/[()=,{}\[\]\/\s]/,Mt=/\\(\\)?/g,Ft=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,Nt=/\w*$/,Pt=/^[-+]0x[0-9a-f]+$/i,qt=/^0b[01]+$/i,Zt=/^\[object .+?Constructor\]$/,Kt=/^0o[0-7]+$/i,Vt=/^(?:0|[1-9]\d*)$/,Gt=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,Ht=/($^)/,Jt=/['\n\r\u2028\u2029\\]/g,Yt="\\ud800-\\udfff",Qt="\\u0300-\\u036f",Xt="\\ufe20-\\ufe2f",nr="\\u20d0-\\u20ff",tr=Qt+Xt+nr,rr="\\u2700-\\u27bf",er="a-z\\xdf-\\xf6\\xf8-\\xff",ur="\\xac\\xb1\\xd7\\xf7",ir="\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf",or="\\u2000-\\u206f",fr=" \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",cr="A-Z\\xc0-\\xd6\\xd8-\\xde",ar="\\ufe0e\\ufe0f",lr=ur+ir+or+fr,sr="['\u2019]",hr="["+Yt+"]",pr="["+lr+"]",_r="["+tr+"]",vr="\\d+",gr="["+rr+"]",yr="["+er+"]",dr="[^"+Yt+lr+vr+rr+er+cr+"]",br="\\ud83c[\\udffb-\\udfff]",wr="(?:"+_r+"|"+br+")",mr="[^"+Yt+"]",xr="(?:\\ud83c[\\udde6-\\uddff]){2}",jr="[\\ud800-\\udbff][\\udc00-\\udfff]",Ar="["+cr+"]",kr="\\u200d",Or="(?:"+yr+"|"+dr+")",Ir="(?:"+Ar+"|"+dr+")",Rr="(?:"+sr+"(?:d|ll|m|re|s|t|ve))?",zr="(?:"+sr+"(?:D|LL|M|RE|S|T|VE))?",Er=wr+"?",Sr="["+ar+"]?",Wr="(?:"+kr+"(?:"+[mr,xr,jr].join("|")+")"+Sr+Er+")*",Lr="\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])",Cr="\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])",Ur=Sr+Er+Wr,Br="(?:"+[gr,xr,jr].join("|")+")"+Ur,Tr="(?:"+[mr+_r+"?",_r,xr,jr,hr].join("|")+")",$r=RegExp(sr,"g"),Dr=RegExp(_r,"g"),Mr=RegExp(br+"(?="+br+")|"+Tr+Ur,"g"),Fr=RegExp([Ar+"?"+yr+"+"+Rr+"(?="+[pr,Ar,"$"].join("|")+")",Ir+"+"+zr+"(?="+[pr,Ar+Or,"$"].join("|")+")",Ar+"?"+Or+"+"+Rr,Ar+"+"+zr,Cr,Lr,vr,Br].join("|"),"g"),Nr=RegExp("["+kr+Yt+tr+ar+"]"),Pr=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,qr=["Array","Buffer","DataView","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Promise","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","clearTimeout","isFinite","parseInt","setTimeout"],Zr=-1,Kr={}; 17 | Kr[at]=Kr[lt]=Kr[st]=Kr[ht]=Kr[pt]=Kr[_t]=Kr[vt]=Kr[gt]=Kr[yt]=!0,Kr[Dn]=Kr[Mn]=Kr[ft]=Kr[Nn]=Kr[ct]=Kr[Pn]=Kr[Zn]=Kr[Kn]=Kr[Gn]=Kr[Hn]=Kr[Yn]=Kr[nt]=Kr[tt]=Kr[rt]=Kr[it]=!1;var Vr={};Vr[Dn]=Vr[Mn]=Vr[ft]=Vr[ct]=Vr[Nn]=Vr[Pn]=Vr[at]=Vr[lt]=Vr[st]=Vr[ht]=Vr[pt]=Vr[Gn]=Vr[Hn]=Vr[Yn]=Vr[nt]=Vr[tt]=Vr[rt]=Vr[et]=Vr[_t]=Vr[vt]=Vr[gt]=Vr[yt]=!0,Vr[Zn]=Vr[Kn]=Vr[it]=!1;var Gr={"\xc0":"A","\xc1":"A","\xc2":"A","\xc3":"A","\xc4":"A","\xc5":"A","\xe0":"a","\xe1":"a","\xe2":"a","\xe3":"a","\xe4":"a","\xe5":"a", 18 | "\xc7":"C","\xe7":"c","\xd0":"D","\xf0":"d","\xc8":"E","\xc9":"E","\xca":"E","\xcb":"E","\xe8":"e","\xe9":"e","\xea":"e","\xeb":"e","\xcc":"I","\xcd":"I","\xce":"I","\xcf":"I","\xec":"i","\xed":"i","\xee":"i","\xef":"i","\xd1":"N","\xf1":"n","\xd2":"O","\xd3":"O","\xd4":"O","\xd5":"O","\xd6":"O","\xd8":"O","\xf2":"o","\xf3":"o","\xf4":"o","\xf5":"o","\xf6":"o","\xf8":"o","\xd9":"U","\xda":"U","\xdb":"U","\xdc":"U","\xf9":"u","\xfa":"u","\xfb":"u","\xfc":"u","\xdd":"Y","\xfd":"y","\xff":"y","\xc6":"Ae", 19 | "\xe6":"ae","\xde":"Th","\xfe":"th","\xdf":"ss","\u0100":"A","\u0102":"A","\u0104":"A","\u0101":"a","\u0103":"a","\u0105":"a","\u0106":"C","\u0108":"C","\u010a":"C","\u010c":"C","\u0107":"c","\u0109":"c","\u010b":"c","\u010d":"c","\u010e":"D","\u0110":"D","\u010f":"d","\u0111":"d","\u0112":"E","\u0114":"E","\u0116":"E","\u0118":"E","\u011a":"E","\u0113":"e","\u0115":"e","\u0117":"e","\u0119":"e","\u011b":"e","\u011c":"G","\u011e":"G","\u0120":"G","\u0122":"G","\u011d":"g","\u011f":"g","\u0121":"g", 20 | "\u0123":"g","\u0124":"H","\u0126":"H","\u0125":"h","\u0127":"h","\u0128":"I","\u012a":"I","\u012c":"I","\u012e":"I","\u0130":"I","\u0129":"i","\u012b":"i","\u012d":"i","\u012f":"i","\u0131":"i","\u0134":"J","\u0135":"j","\u0136":"K","\u0137":"k","\u0138":"k","\u0139":"L","\u013b":"L","\u013d":"L","\u013f":"L","\u0141":"L","\u013a":"l","\u013c":"l","\u013e":"l","\u0140":"l","\u0142":"l","\u0143":"N","\u0145":"N","\u0147":"N","\u014a":"N","\u0144":"n","\u0146":"n","\u0148":"n","\u014b":"n","\u014c":"O", 21 | "\u014e":"O","\u0150":"O","\u014d":"o","\u014f":"o","\u0151":"o","\u0154":"R","\u0156":"R","\u0158":"R","\u0155":"r","\u0157":"r","\u0159":"r","\u015a":"S","\u015c":"S","\u015e":"S","\u0160":"S","\u015b":"s","\u015d":"s","\u015f":"s","\u0161":"s","\u0162":"T","\u0164":"T","\u0166":"T","\u0163":"t","\u0165":"t","\u0167":"t","\u0168":"U","\u016a":"U","\u016c":"U","\u016e":"U","\u0170":"U","\u0172":"U","\u0169":"u","\u016b":"u","\u016d":"u","\u016f":"u","\u0171":"u","\u0173":"u","\u0174":"W","\u0175":"w", 22 | "\u0176":"Y","\u0177":"y","\u0178":"Y","\u0179":"Z","\u017b":"Z","\u017d":"Z","\u017a":"z","\u017c":"z","\u017e":"z","\u0132":"IJ","\u0133":"ij","\u0152":"Oe","\u0153":"oe","\u0149":"'n","\u017f":"s"},Hr={"&":"&","<":"<",">":">",'"':""","'":"'"},Jr={"&":"&","<":"<",">":">",""":'"',"'":"'"},Yr={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},Qr=parseFloat,Xr=parseInt,ne="object"==typeof global&&global&&global.Object===Object&&global,te="object"==typeof self&&self&&self.Object===Object&&self,re=ne||te||Function("return this")(),ee="object"==typeof exports&&exports&&!exports.nodeType&&exports,ue=ee&&"object"==typeof module&&module&&!module.nodeType&&module,ie=ue&&ue.exports===ee,oe=ie&&ne.process,fe=function(){ 23 | try{var n=ue&&ue.require&&ue.require("util").types;return n?n:oe&&oe.binding&&oe.binding("util")}catch(n){}}(),ce=fe&&fe.isArrayBuffer,ae=fe&&fe.isDate,le=fe&&fe.isMap,se=fe&&fe.isRegExp,he=fe&&fe.isSet,pe=fe&&fe.isTypedArray,_e=m("length"),ve=x(Gr),ge=x(Hr),ye=x(Jr),de=function p(x){function Z(n){if(cc(n)&&!bh(n)&&!(n instanceof Ct)){if(n instanceof Y)return n;if(bl.call(n,"__wrapped__"))return eo(n)}return new Y(n)}function J(){}function Y(n,t){this.__wrapped__=n,this.__actions__=[],this.__chain__=!!t, 24 | this.__index__=0,this.__values__=X}function Ct(n){this.__wrapped__=n,this.__actions__=[],this.__dir__=1,this.__filtered__=!1,this.__iteratees__=[],this.__takeCount__=Un,this.__views__=[]}function $t(){var n=new Ct(this.__wrapped__);return n.__actions__=Tu(this.__actions__),n.__dir__=this.__dir__,n.__filtered__=this.__filtered__,n.__iteratees__=Tu(this.__iteratees__),n.__takeCount__=this.__takeCount__,n.__views__=Tu(this.__views__),n}function Yt(){if(this.__filtered__){var n=new Ct(this);n.__dir__=-1, 25 | n.__filtered__=!0}else n=this.clone(),n.__dir__*=-1;return n}function Qt(){var n=this.__wrapped__.value(),t=this.__dir__,r=bh(n),e=t<0,u=r?n.length:0,i=Oi(0,u,this.__views__),o=i.start,f=i.end,c=f-o,a=e?f:o-1,l=this.__iteratees__,s=l.length,h=0,p=Hl(c,this.__takeCount__);if(!r||!e&&u==c&&p==c)return wu(n,this.__actions__);var _=[];n:for(;c--&&h-1}function lr(n,t){var r=this.__data__,e=Wr(r,n);return e<0?(++this.size,r.push([n,t])):r[e][1]=t,this}function sr(n){var t=-1,r=null==n?0:n.length;for(this.clear();++t=t?n:t)),n}function Fr(n,t,e,u,i,o){var f,c=t&an,a=t&ln,l=t&sn;if(e&&(f=i?e(n,u,i,o):e(n)),f!==X)return f;if(!fc(n))return n;var s=bh(n);if(s){if(f=zi(n),!c)return Tu(n,f)}else{var h=zs(n),p=h==Kn||h==Vn;if(mh(n))return Iu(n,c);if(h==Yn||h==Dn||p&&!i){if(f=a||p?{}:Ei(n),!c)return a?Mu(n,Ur(f,n)):Du(n,Cr(f,n))}else{if(!Vr[h])return i?n:{};f=Si(n,h,c)}}o||(o=new wr);var _=o.get(n);if(_)return _;o.set(n,f),kh(n)?n.forEach(function(r){f.add(Fr(r,t,e,r,n,o))}):jh(n)&&n.forEach(function(r,u){ 33 | f.set(u,Fr(r,t,e,u,n,o))});var v=l?a?di:yi:a?qc:Pc,g=s?X:v(n);return r(g||n,function(r,u){g&&(u=r,r=n[u]),Sr(f,u,Fr(r,t,e,u,n,o))}),f}function Nr(n){var t=Pc(n);return function(r){return Pr(r,n,t)}}function Pr(n,t,r){var e=r.length;if(null==n)return!e;for(n=ll(n);e--;){var u=r[e],i=t[u],o=n[u];if(o===X&&!(u in n)||!i(o))return!1}return!0}function Gr(n,t,r){if("function"!=typeof n)throw new pl(en);return Ws(function(){n.apply(X,r)},t)}function Hr(n,t,r,e){var u=-1,i=o,a=!0,l=n.length,s=[],h=t.length; 34 | if(!l)return s;r&&(t=c(t,z(r))),e?(i=f,a=!1):t.length>=tn&&(i=S,a=!1,t=new yr(t));n:for(;++uu?0:u+r), 35 | e=e===X||e>u?u:kc(e),e<0&&(e+=u),e=r>e?0:Oc(e);r0&&r(f)?t>1?ee(f,t-1,r,e,u):a(u,f):e||(u[u.length]=f)}return u}function ue(n,t){return n&&bs(n,t,Pc)}function oe(n,t){return n&&ws(n,t,Pc)}function fe(n,t){return i(t,function(t){return uc(n[t])})}function _e(n,t){t=ku(t,n);for(var r=0,e=t.length;null!=n&&rt}function xe(n,t){return null!=n&&bl.call(n,t)}function je(n,t){return null!=n&&t in ll(n)}function Ae(n,t,r){return n>=Hl(t,r)&&n=120&&p.length>=120)?new yr(a&&p):X}p=n[0]; 37 | var _=-1,v=l[0];n:for(;++_-1;)f!==n&&Ll.call(f,a,1),Ll.call(n,a,1);return n}function nu(n,t){for(var r=n?t.length:0,e=r-1;r--;){ 44 | var u=t[r];if(r==e||u!==i){var i=u;Ci(u)?Ll.call(n,u,1):yu(n,u)}}return n}function tu(n,t){return n+Nl(Ql()*(t-n+1))}function ru(n,t,r,e){for(var u=-1,i=Gl(Fl((t-n)/(r||1)),0),o=il(i);i--;)o[e?i:++u]=n,n+=r;return o}function eu(n,t){var r="";if(!n||t<1||t>Wn)return r;do t%2&&(r+=n),t=Nl(t/2),t&&(n+=n);while(t);return r}function uu(n,t){return Ls(Vi(n,t,La),n+"")}function iu(n){return Ir(ra(n))}function ou(n,t){var r=ra(n);return Xi(r,Mr(t,0,r.length))}function fu(n,t,r,e){if(!fc(n))return n;t=ku(t,n); 45 | for(var u=-1,i=t.length,o=i-1,f=n;null!=f&&++uu?0:u+t),r=r>u?u:r,r<0&&(r+=u),u=t>r?0:r-t>>>0,t>>>=0;for(var i=il(u);++e>>1,o=n[i];null!==o&&!bc(o)&&(r?o<=t:o=tn){var s=t?null:ks(n);if(s)return P(s);c=!1,u=S,l=new yr}else l=t?[]:a;n:for(;++e=e?n:au(n,t,r)}function Iu(n,t){if(t)return n.slice();var r=n.length,e=zl?zl(r):new n.constructor(r); 50 | return n.copy(e),e}function Ru(n){var t=new n.constructor(n.byteLength);return new Rl(t).set(new Rl(n)),t}function zu(n,t){return new n.constructor(t?Ru(n.buffer):n.buffer,n.byteOffset,n.byteLength)}function Eu(n){var t=new n.constructor(n.source,Nt.exec(n));return t.lastIndex=n.lastIndex,t}function Su(n){return _s?ll(_s.call(n)):{}}function Wu(n,t){return new n.constructor(t?Ru(n.buffer):n.buffer,n.byteOffset,n.length)}function Lu(n,t){if(n!==t){var r=n!==X,e=null===n,u=n===n,i=bc(n),o=t!==X,f=null===t,c=t===t,a=bc(t); 51 | if(!f&&!a&&!i&&n>t||i&&o&&c&&!f&&!a||e&&o&&c||!r&&c||!u)return 1;if(!e&&!i&&!a&&n=f)return c;return c*("desc"==r[e]?-1:1)}}return n.index-t.index}function Uu(n,t,r,e){for(var u=-1,i=n.length,o=r.length,f=-1,c=t.length,a=Gl(i-o,0),l=il(c+a),s=!e;++f1?r[u-1]:X,o=u>2?r[2]:X;for(i=n.length>3&&"function"==typeof i?(u--,i):X,o&&Ui(r[0],r[1],o)&&(i=u<3?X:i,u=1),t=ll(t);++e-1?u[i?t[o]:o]:X}}function Yu(n){return gi(function(t){var r=t.length,e=r,u=Y.prototype.thru;for(n&&t.reverse();e--;){var i=t[e];if("function"!=typeof i)throw new pl(en);if(u&&!o&&"wrapper"==bi(i))var o=new Y([],!0)}for(e=o?e:r;++e1&&d.reverse(),s&&cf))return!1;var a=i.get(n),l=i.get(t);if(a&&l)return a==t&&l==n;var s=-1,p=!0,_=r&pn?new yr:X;for(i.set(n,t),i.set(t,n);++s1?"& ":"")+t[e],t=t.join(r>2?", ":" "),n.replace(Ut,"{\n/* [wrapped with "+t+"] */\n")}function Li(n){return bh(n)||dh(n)||!!(Cl&&n&&n[Cl])}function Ci(n,t){var r=typeof n; 70 | return t=null==t?Wn:t,!!t&&("number"==r||"symbol"!=r&&Vt.test(n))&&n>-1&&n%1==0&&n0){if(++t>=On)return arguments[0]}else t=0; 74 | return n.apply(X,arguments)}}function Xi(n,t){var r=-1,e=n.length,u=e-1;for(t=t===X?e:t;++r=this.__values__.length;return{done:n,value:n?X:this.__values__[this.__index__++]}}function uf(){return this}function of(n){for(var t,r=this;r instanceof J;){var e=eo(r);e.__index__=0,e.__values__=X,t?u.__wrapped__=e:t=e;var u=e;r=r.__wrapped__}return u.__wrapped__=n,t}function ff(){var n=this.__wrapped__;if(n instanceof Ct){var t=n;return this.__actions__.length&&(t=new Ct(this)),t=t.reverse(),t.__actions__.push({func:nf,args:[Eo],thisArg:X}),new Y(t,this.__chain__)}return this.thru(Eo); 84 | }function cf(){return wu(this.__wrapped__,this.__actions__)}function af(n,t,r){var e=bh(n)?u:Jr;return r&&Ui(n,t,r)&&(t=X),e(n,mi(t,3))}function lf(n,t){return(bh(n)?i:te)(n,mi(t,3))}function sf(n,t){return ee(yf(n,t),1)}function hf(n,t){return ee(yf(n,t),Sn)}function pf(n,t,r){return r=r===X?1:kc(r),ee(yf(n,t),r)}function _f(n,t){return(bh(n)?r:ys)(n,mi(t,3))}function vf(n,t){return(bh(n)?e:ds)(n,mi(t,3))}function gf(n,t,r,e){n=Hf(n)?n:ra(n),r=r&&!e?kc(r):0;var u=n.length;return r<0&&(r=Gl(u+r,0)), 85 | dc(n)?r<=u&&n.indexOf(t,r)>-1:!!u&&y(n,t,r)>-1}function yf(n,t){return(bh(n)?c:Pe)(n,mi(t,3))}function df(n,t,r,e){return null==n?[]:(bh(t)||(t=null==t?[]:[t]),r=e?X:r,bh(r)||(r=null==r?[]:[r]),He(n,t,r))}function bf(n,t,r){var e=bh(n)?l:j,u=arguments.length<3;return e(n,mi(t,4),r,u,ys)}function wf(n,t,r){var e=bh(n)?s:j,u=arguments.length<3;return e(n,mi(t,4),r,u,ds)}function mf(n,t){return(bh(n)?i:te)(n,Uf(mi(t,3)))}function xf(n){return(bh(n)?Ir:iu)(n)}function jf(n,t,r){return t=(r?Ui(n,t,r):t===X)?1:kc(t), 86 | (bh(n)?Rr:ou)(n,t)}function Af(n){return(bh(n)?zr:cu)(n)}function kf(n){if(null==n)return 0;if(Hf(n))return dc(n)?V(n):n.length;var t=zs(n);return t==Gn||t==tt?n.size:Me(n).length}function Of(n,t,r){var e=bh(n)?h:lu;return r&&Ui(n,t,r)&&(t=X),e(n,mi(t,3))}function If(n,t){if("function"!=typeof t)throw new pl(en);return n=kc(n),function(){if(--n<1)return t.apply(this,arguments)}}function Rf(n,t,r){return t=r?X:t,t=n&&null==t?n.length:t,ai(n,mn,X,X,X,X,t)}function zf(n,t){var r;if("function"!=typeof t)throw new pl(en); 87 | return n=kc(n),function(){return--n>0&&(r=t.apply(this,arguments)),n<=1&&(t=X),r}}function Ef(n,t,r){t=r?X:t;var e=ai(n,yn,X,X,X,X,X,t);return e.placeholder=Ef.placeholder,e}function Sf(n,t,r){t=r?X:t;var e=ai(n,dn,X,X,X,X,X,t);return e.placeholder=Sf.placeholder,e}function Wf(n,t,r){function e(t){var r=h,e=p;return h=p=X,d=t,v=n.apply(e,r)}function u(n){return d=n,g=Ws(f,t),b?e(n):v}function i(n){var r=n-y,e=n-d,u=t-r;return w?Hl(u,_-e):u}function o(n){var r=n-y,e=n-d;return y===X||r>=t||r<0||w&&e>=_; 88 | }function f(){var n=fh();return o(n)?c(n):(g=Ws(f,i(n)),X)}function c(n){return g=X,m&&h?e(n):(h=p=X,v)}function a(){g!==X&&As(g),d=0,h=y=p=g=X}function l(){return g===X?v:c(fh())}function s(){var n=fh(),r=o(n);if(h=arguments,p=this,y=n,r){if(g===X)return u(y);if(w)return As(g),g=Ws(f,t),e(y)}return g===X&&(g=Ws(f,t)),v}var h,p,_,v,g,y,d=0,b=!1,w=!1,m=!0;if("function"!=typeof n)throw new pl(en);return t=Ic(t)||0,fc(r)&&(b=!!r.leading,w="maxWait"in r,_=w?Gl(Ic(r.maxWait)||0,t):_,m="trailing"in r?!!r.trailing:m), 89 | s.cancel=a,s.flush=l,s}function Lf(n){return ai(n,jn)}function Cf(n,t){if("function"!=typeof n||null!=t&&"function"!=typeof t)throw new pl(en);var r=function(){var e=arguments,u=t?t.apply(this,e):e[0],i=r.cache;if(i.has(u))return i.get(u);var o=n.apply(this,e);return r.cache=i.set(u,o)||i,o};return r.cache=new(Cf.Cache||sr),r}function Uf(n){if("function"!=typeof n)throw new pl(en);return function(){var t=arguments;switch(t.length){case 0:return!n.call(this);case 1:return!n.call(this,t[0]);case 2: 90 | return!n.call(this,t[0],t[1]);case 3:return!n.call(this,t[0],t[1],t[2])}return!n.apply(this,t)}}function Bf(n){return zf(2,n)}function Tf(n,t){if("function"!=typeof n)throw new pl(en);return t=t===X?t:kc(t),uu(n,t)}function $f(t,r){if("function"!=typeof t)throw new pl(en);return r=null==r?0:Gl(kc(r),0),uu(function(e){var u=e[r],i=Ou(e,0,r);return u&&a(i,u),n(t,this,i)})}function Df(n,t,r){var e=!0,u=!0;if("function"!=typeof n)throw new pl(en);return fc(r)&&(e="leading"in r?!!r.leading:e,u="trailing"in r?!!r.trailing:u), 91 | Wf(n,t,{leading:e,maxWait:t,trailing:u})}function Mf(n){return Rf(n,1)}function Ff(n,t){return ph(Au(t),n)}function Nf(){if(!arguments.length)return[];var n=arguments[0];return bh(n)?n:[n]}function Pf(n){return Fr(n,sn)}function qf(n,t){return t="function"==typeof t?t:X,Fr(n,sn,t)}function Zf(n){return Fr(n,an|sn)}function Kf(n,t){return t="function"==typeof t?t:X,Fr(n,an|sn,t)}function Vf(n,t){return null==t||Pr(n,t,Pc(t))}function Gf(n,t){return n===t||n!==n&&t!==t}function Hf(n){return null!=n&&oc(n.length)&&!uc(n); 92 | }function Jf(n){return cc(n)&&Hf(n)}function Yf(n){return n===!0||n===!1||cc(n)&&we(n)==Nn}function Qf(n){return cc(n)&&1===n.nodeType&&!gc(n)}function Xf(n){if(null==n)return!0;if(Hf(n)&&(bh(n)||"string"==typeof n||"function"==typeof n.splice||mh(n)||Oh(n)||dh(n)))return!n.length;var t=zs(n);if(t==Gn||t==tt)return!n.size;if(Mi(n))return!Me(n).length;for(var r in n)if(bl.call(n,r))return!1;return!0}function nc(n,t){return Se(n,t)}function tc(n,t,r){r="function"==typeof r?r:X;var e=r?r(n,t):X;return e===X?Se(n,t,X,r):!!e; 93 | }function rc(n){if(!cc(n))return!1;var t=we(n);return t==Zn||t==qn||"string"==typeof n.message&&"string"==typeof n.name&&!gc(n)}function ec(n){return"number"==typeof n&&Zl(n)}function uc(n){if(!fc(n))return!1;var t=we(n);return t==Kn||t==Vn||t==Fn||t==Xn}function ic(n){return"number"==typeof n&&n==kc(n)}function oc(n){return"number"==typeof n&&n>-1&&n%1==0&&n<=Wn}function fc(n){var t=typeof n;return null!=n&&("object"==t||"function"==t)}function cc(n){return null!=n&&"object"==typeof n}function ac(n,t){ 94 | return n===t||Ce(n,t,ji(t))}function lc(n,t,r){return r="function"==typeof r?r:X,Ce(n,t,ji(t),r)}function sc(n){return vc(n)&&n!=+n}function hc(n){if(Es(n))throw new fl(rn);return Ue(n)}function pc(n){return null===n}function _c(n){return null==n}function vc(n){return"number"==typeof n||cc(n)&&we(n)==Hn}function gc(n){if(!cc(n)||we(n)!=Yn)return!1;var t=El(n);if(null===t)return!0;var r=bl.call(t,"constructor")&&t.constructor;return"function"==typeof r&&r instanceof r&&dl.call(r)==jl}function yc(n){ 95 | return ic(n)&&n>=-Wn&&n<=Wn}function dc(n){return"string"==typeof n||!bh(n)&&cc(n)&&we(n)==rt}function bc(n){return"symbol"==typeof n||cc(n)&&we(n)==et}function wc(n){return n===X}function mc(n){return cc(n)&&zs(n)==it}function xc(n){return cc(n)&&we(n)==ot}function jc(n){if(!n)return[];if(Hf(n))return dc(n)?G(n):Tu(n);if(Ul&&n[Ul])return D(n[Ul]());var t=zs(n);return(t==Gn?M:t==tt?P:ra)(n)}function Ac(n){if(!n)return 0===n?n:0;if(n=Ic(n),n===Sn||n===-Sn){return(n<0?-1:1)*Ln}return n===n?n:0}function kc(n){ 96 | var t=Ac(n),r=t%1;return t===t?r?t-r:t:0}function Oc(n){return n?Mr(kc(n),0,Un):0}function Ic(n){if("number"==typeof n)return n;if(bc(n))return Cn;if(fc(n)){var t="function"==typeof n.valueOf?n.valueOf():n;n=fc(t)?t+"":t}if("string"!=typeof n)return 0===n?n:+n;n=R(n);var r=qt.test(n);return r||Kt.test(n)?Xr(n.slice(2),r?2:8):Pt.test(n)?Cn:+n}function Rc(n){return $u(n,qc(n))}function zc(n){return n?Mr(kc(n),-Wn,Wn):0===n?n:0}function Ec(n){return null==n?"":vu(n)}function Sc(n,t){var r=gs(n);return null==t?r:Cr(r,t); 97 | }function Wc(n,t){return v(n,mi(t,3),ue)}function Lc(n,t){return v(n,mi(t,3),oe)}function Cc(n,t){return null==n?n:bs(n,mi(t,3),qc)}function Uc(n,t){return null==n?n:ws(n,mi(t,3),qc)}function Bc(n,t){return n&&ue(n,mi(t,3))}function Tc(n,t){return n&&oe(n,mi(t,3))}function $c(n){return null==n?[]:fe(n,Pc(n))}function Dc(n){return null==n?[]:fe(n,qc(n))}function Mc(n,t,r){var e=null==n?X:_e(n,t);return e===X?r:e}function Fc(n,t){return null!=n&&Ri(n,t,xe)}function Nc(n,t){return null!=n&&Ri(n,t,je); 98 | }function Pc(n){return Hf(n)?Or(n):Me(n)}function qc(n){return Hf(n)?Or(n,!0):Fe(n)}function Zc(n,t){var r={};return t=mi(t,3),ue(n,function(n,e,u){Br(r,t(n,e,u),n)}),r}function Kc(n,t){var r={};return t=mi(t,3),ue(n,function(n,e,u){Br(r,e,t(n,e,u))}),r}function Vc(n,t){return Gc(n,Uf(mi(t)))}function Gc(n,t){if(null==n)return{};var r=c(di(n),function(n){return[n]});return t=mi(t),Ye(n,r,function(n,r){return t(n,r[0])})}function Hc(n,t,r){t=ku(t,n);var e=-1,u=t.length;for(u||(u=1,n=X);++et){ 101 | var e=n;n=t,t=e}if(r||n%1||t%1){var u=Ql();return Hl(n+u*(t-n+Qr("1e-"+((u+"").length-1))),t)}return tu(n,t)}function fa(n){return Qh(Ec(n).toLowerCase())}function ca(n){return n=Ec(n),n&&n.replace(Gt,ve).replace(Dr,"")}function aa(n,t,r){n=Ec(n),t=vu(t);var e=n.length;r=r===X?e:Mr(kc(r),0,e);var u=r;return r-=t.length,r>=0&&n.slice(r,u)==t}function la(n){return n=Ec(n),n&&At.test(n)?n.replace(xt,ge):n}function sa(n){return n=Ec(n),n&&Wt.test(n)?n.replace(St,"\\$&"):n}function ha(n,t,r){n=Ec(n),t=kc(t); 102 | var e=t?V(n):0;if(!t||e>=t)return n;var u=(t-e)/2;return ri(Nl(u),r)+n+ri(Fl(u),r)}function pa(n,t,r){n=Ec(n),t=kc(t);var e=t?V(n):0;return t&&e>>0)?(n=Ec(n),n&&("string"==typeof t||null!=t&&!Ah(t))&&(t=vu(t),!t&&T(n))?Ou(G(n),0,r):n.split(t,r)):[]}function ba(n,t,r){return n=Ec(n),r=null==r?0:Mr(kc(r),0,n.length),t=vu(t),n.slice(r,r+t.length)==t}function wa(n,t,r){var e=Z.templateSettings;r&&Ui(n,t,r)&&(t=X),n=Ec(n),t=Sh({},t,e,li);var u,i,o=Sh({},t.imports,e.imports,li),f=Pc(o),c=E(o,f),a=0,l=t.interpolate||Ht,s="__p += '",h=sl((t.escape||Ht).source+"|"+l.source+"|"+(l===It?Ft:Ht).source+"|"+(t.evaluate||Ht).source+"|$","g"),p="//# sourceURL="+(bl.call(t,"sourceURL")?(t.sourceURL+"").replace(/\s/g," "):"lodash.templateSources["+ ++Zr+"]")+"\n"; 104 | n.replace(h,function(t,r,e,o,f,c){return e||(e=o),s+=n.slice(a,c).replace(Jt,U),r&&(u=!0,s+="' +\n__e("+r+") +\n'"),f&&(i=!0,s+="';\n"+f+";\n__p += '"),e&&(s+="' +\n((__t = ("+e+")) == null ? '' : __t) +\n'"),a=c+t.length,t}),s+="';\n";var _=bl.call(t,"variable")&&t.variable;if(_){if(Dt.test(_))throw new fl(un)}else s="with (obj) {\n"+s+"\n}\n";s=(i?s.replace(dt,""):s).replace(bt,"$1").replace(wt,"$1;"),s="function("+(_||"obj")+") {\n"+(_?"":"obj || (obj = {});\n")+"var __t, __p = ''"+(u?", __e = _.escape":"")+(i?", __j = Array.prototype.join;\nfunction print() { __p += __j.call(arguments, '') }\n":";\n")+s+"return __p\n}"; 105 | var v=Xh(function(){return cl(f,p+"return "+s).apply(X,c)});if(v.source=s,rc(v))throw v;return v}function ma(n){return Ec(n).toLowerCase()}function xa(n){return Ec(n).toUpperCase()}function ja(n,t,r){if(n=Ec(n),n&&(r||t===X))return R(n);if(!n||!(t=vu(t)))return n;var e=G(n),u=G(t);return Ou(e,W(e,u),L(e,u)+1).join("")}function Aa(n,t,r){if(n=Ec(n),n&&(r||t===X))return n.slice(0,H(n)+1);if(!n||!(t=vu(t)))return n;var e=G(n);return Ou(e,0,L(e,G(t))+1).join("")}function ka(n,t,r){if(n=Ec(n),n&&(r||t===X))return n.replace(Lt,""); 106 | if(!n||!(t=vu(t)))return n;var e=G(n);return Ou(e,W(e,G(t))).join("")}function Oa(n,t){var r=An,e=kn;if(fc(t)){var u="separator"in t?t.separator:u;r="length"in t?kc(t.length):r,e="omission"in t?vu(t.omission):e}n=Ec(n);var i=n.length;if(T(n)){var o=G(n);i=o.length}if(r>=i)return n;var f=r-V(e);if(f<1)return e;var c=o?Ou(o,0,f).join(""):n.slice(0,f);if(u===X)return c+e;if(o&&(f+=c.length-f),Ah(u)){if(n.slice(f).search(u)){var a,l=c;for(u.global||(u=sl(u.source,Ec(Nt.exec(u))+"g")),u.lastIndex=0;a=u.exec(l);)var s=a.index; 107 | c=c.slice(0,s===X?f:s)}}else if(n.indexOf(vu(u),f)!=f){var h=c.lastIndexOf(u);h>-1&&(c=c.slice(0,h))}return c+e}function Ia(n){return n=Ec(n),n&&jt.test(n)?n.replace(mt,ye):n}function Ra(n,t,r){return n=Ec(n),t=r?X:t,t===X?$(n)?Q(n):_(n):n.match(t)||[]}function za(t){var r=null==t?0:t.length,e=mi();return t=r?c(t,function(n){if("function"!=typeof n[1])throw new pl(en);return[e(n[0]),n[1]]}):[],uu(function(e){for(var u=-1;++uWn)return[];var r=Un,e=Hl(n,Un);t=mi(t),n-=Un;for(var u=O(e,t);++r1?n[t-1]:X;return r="function"==typeof r?(n.pop(), 119 | r):X,Ho(n,r)}),Qs=gi(function(n){var t=n.length,r=t?n[0]:0,e=this.__wrapped__,u=function(t){return Tr(t,n)};return!(t>1||this.__actions__.length)&&e instanceof Ct&&Ci(r)?(e=e.slice(r,+r+(t?1:0)),e.__actions__.push({func:nf,args:[u],thisArg:X}),new Y(e,this.__chain__).thru(function(n){return t&&!n.length&&n.push(X),n})):this.thru(u)}),Xs=Fu(function(n,t,r){bl.call(n,r)?++n[r]:Br(n,r,1)}),nh=Ju(ho),th=Ju(po),rh=Fu(function(n,t,r){bl.call(n,r)?n[r].push(t):Br(n,r,[t])}),eh=uu(function(t,r,e){var u=-1,i="function"==typeof r,o=Hf(t)?il(t.length):[]; 120 | return ys(t,function(t){o[++u]=i?n(r,t,e):Ie(t,r,e)}),o}),uh=Fu(function(n,t,r){Br(n,r,t)}),ih=Fu(function(n,t,r){n[r?0:1].push(t)},function(){return[[],[]]}),oh=uu(function(n,t){if(null==n)return[];var r=t.length;return r>1&&Ui(n,t[0],t[1])?t=[]:r>2&&Ui(t[0],t[1],t[2])&&(t=[t[0]]),He(n,ee(t,1),[])}),fh=Dl||function(){return re.Date.now()},ch=uu(function(n,t,r){var e=_n;if(r.length){var u=N(r,wi(ch));e|=bn}return ai(n,e,t,r,u)}),ah=uu(function(n,t,r){var e=_n|vn;if(r.length){var u=N(r,wi(ah));e|=bn; 121 | }return ai(t,e,n,r,u)}),lh=uu(function(n,t){return Gr(n,1,t)}),sh=uu(function(n,t,r){return Gr(n,Ic(t)||0,r)});Cf.Cache=sr;var hh=js(function(t,r){r=1==r.length&&bh(r[0])?c(r[0],z(mi())):c(ee(r,1),z(mi()));var e=r.length;return uu(function(u){for(var i=-1,o=Hl(u.length,e);++i=t}),dh=Re(function(){return arguments}())?Re:function(n){return cc(n)&&bl.call(n,"callee")&&!Wl.call(n,"callee")},bh=il.isArray,wh=ce?z(ce):ze,mh=ql||qa,xh=ae?z(ae):Ee,jh=le?z(le):Le,Ah=se?z(se):Be,kh=he?z(he):Te,Oh=pe?z(pe):$e,Ih=ii(Ne),Rh=ii(function(n,t){return n<=t}),zh=Nu(function(n,t){if(Mi(t)||Hf(t))return $u(t,Pc(t),n),X;for(var r in t)bl.call(t,r)&&Sr(n,r,t[r])}),Eh=Nu(function(n,t){$u(t,qc(t),n)}),Sh=Nu(function(n,t,r,e){$u(t,qc(t),n,e)}),Wh=Nu(function(n,t,r,e){$u(t,Pc(t),n,e); 123 | }),Lh=gi(Tr),Ch=uu(function(n,t){n=ll(n);var r=-1,e=t.length,u=e>2?t[2]:X;for(u&&Ui(t[0],t[1],u)&&(e=1);++r1),t}),$u(n,di(n),r),e&&(r=Fr(r,an|ln|sn,hi));for(var u=t.length;u--;)yu(r,t[u]);return r}),Nh=gi(function(n,t){return null==n?{}:Je(n,t)}),Ph=ci(Pc),qh=ci(qc),Zh=Vu(function(n,t,r){return t=t.toLowerCase(),n+(r?fa(t):t)}),Kh=Vu(function(n,t,r){return n+(r?"-":"")+t.toLowerCase()}),Vh=Vu(function(n,t,r){return n+(r?" ":"")+t.toLowerCase()}),Gh=Ku("toLowerCase"),Hh=Vu(function(n,t,r){ 125 | return n+(r?"_":"")+t.toLowerCase()}),Jh=Vu(function(n,t,r){return n+(r?" ":"")+Qh(t)}),Yh=Vu(function(n,t,r){return n+(r?" ":"")+t.toUpperCase()}),Qh=Ku("toUpperCase"),Xh=uu(function(t,r){try{return n(t,X,r)}catch(n){return rc(n)?n:new fl(n)}}),np=gi(function(n,t){return r(t,function(t){t=no(t),Br(n,t,ch(n[t],n))}),n}),tp=Yu(),rp=Yu(!0),ep=uu(function(n,t){return function(r){return Ie(r,n,t)}}),up=uu(function(n,t){return function(r){return Ie(n,r,t)}}),ip=ti(c),op=ti(u),fp=ti(h),cp=ui(),ap=ui(!0),lp=ni(function(n,t){ 126 | return n+t},0),sp=fi("ceil"),hp=ni(function(n,t){return n/t},1),pp=fi("floor"),_p=ni(function(n,t){return n*t},1),vp=fi("round"),gp=ni(function(n,t){return n-t},0);return Z.after=If,Z.ary=Rf,Z.assign=zh,Z.assignIn=Eh,Z.assignInWith=Sh,Z.assignWith=Wh,Z.at=Lh,Z.before=zf,Z.bind=ch,Z.bindAll=np,Z.bindKey=ah,Z.castArray=Nf,Z.chain=Qo,Z.chunk=uo,Z.compact=io,Z.concat=oo,Z.cond=za,Z.conforms=Ea,Z.constant=Sa,Z.countBy=Xs,Z.create=Sc,Z.curry=Ef,Z.curryRight=Sf,Z.debounce=Wf,Z.defaults=Ch,Z.defaultsDeep=Uh, 127 | Z.defer=lh,Z.delay=sh,Z.difference=Us,Z.differenceBy=Bs,Z.differenceWith=Ts,Z.drop=fo,Z.dropRight=co,Z.dropRightWhile=ao,Z.dropWhile=lo,Z.fill=so,Z.filter=lf,Z.flatMap=sf,Z.flatMapDeep=hf,Z.flatMapDepth=pf,Z.flatten=_o,Z.flattenDeep=vo,Z.flattenDepth=go,Z.flip=Lf,Z.flow=tp,Z.flowRight=rp,Z.fromPairs=yo,Z.functions=$c,Z.functionsIn=Dc,Z.groupBy=rh,Z.initial=mo,Z.intersection=$s,Z.intersectionBy=Ds,Z.intersectionWith=Ms,Z.invert=Bh,Z.invertBy=Th,Z.invokeMap=eh,Z.iteratee=Ca,Z.keyBy=uh,Z.keys=Pc,Z.keysIn=qc, 128 | Z.map=yf,Z.mapKeys=Zc,Z.mapValues=Kc,Z.matches=Ua,Z.matchesProperty=Ba,Z.memoize=Cf,Z.merge=Dh,Z.mergeWith=Mh,Z.method=ep,Z.methodOf=up,Z.mixin=Ta,Z.negate=Uf,Z.nthArg=Ma,Z.omit=Fh,Z.omitBy=Vc,Z.once=Bf,Z.orderBy=df,Z.over=ip,Z.overArgs=hh,Z.overEvery=op,Z.overSome=fp,Z.partial=ph,Z.partialRight=_h,Z.partition=ih,Z.pick=Nh,Z.pickBy=Gc,Z.property=Fa,Z.propertyOf=Na,Z.pull=Fs,Z.pullAll=Oo,Z.pullAllBy=Io,Z.pullAllWith=Ro,Z.pullAt=Ns,Z.range=cp,Z.rangeRight=ap,Z.rearg=vh,Z.reject=mf,Z.remove=zo,Z.rest=Tf, 129 | Z.reverse=Eo,Z.sampleSize=jf,Z.set=Jc,Z.setWith=Yc,Z.shuffle=Af,Z.slice=So,Z.sortBy=oh,Z.sortedUniq=$o,Z.sortedUniqBy=Do,Z.split=da,Z.spread=$f,Z.tail=Mo,Z.take=Fo,Z.takeRight=No,Z.takeRightWhile=Po,Z.takeWhile=qo,Z.tap=Xo,Z.throttle=Df,Z.thru=nf,Z.toArray=jc,Z.toPairs=Ph,Z.toPairsIn=qh,Z.toPath=Ha,Z.toPlainObject=Rc,Z.transform=Qc,Z.unary=Mf,Z.union=Ps,Z.unionBy=qs,Z.unionWith=Zs,Z.uniq=Zo,Z.uniqBy=Ko,Z.uniqWith=Vo,Z.unset=Xc,Z.unzip=Go,Z.unzipWith=Ho,Z.update=na,Z.updateWith=ta,Z.values=ra,Z.valuesIn=ea, 130 | Z.without=Ks,Z.words=Ra,Z.wrap=Ff,Z.xor=Vs,Z.xorBy=Gs,Z.xorWith=Hs,Z.zip=Js,Z.zipObject=Jo,Z.zipObjectDeep=Yo,Z.zipWith=Ys,Z.entries=Ph,Z.entriesIn=qh,Z.extend=Eh,Z.extendWith=Sh,Ta(Z,Z),Z.add=lp,Z.attempt=Xh,Z.camelCase=Zh,Z.capitalize=fa,Z.ceil=sp,Z.clamp=ua,Z.clone=Pf,Z.cloneDeep=Zf,Z.cloneDeepWith=Kf,Z.cloneWith=qf,Z.conformsTo=Vf,Z.deburr=ca,Z.defaultTo=Wa,Z.divide=hp,Z.endsWith=aa,Z.eq=Gf,Z.escape=la,Z.escapeRegExp=sa,Z.every=af,Z.find=nh,Z.findIndex=ho,Z.findKey=Wc,Z.findLast=th,Z.findLastIndex=po, 131 | Z.findLastKey=Lc,Z.floor=pp,Z.forEach=_f,Z.forEachRight=vf,Z.forIn=Cc,Z.forInRight=Uc,Z.forOwn=Bc,Z.forOwnRight=Tc,Z.get=Mc,Z.gt=gh,Z.gte=yh,Z.has=Fc,Z.hasIn=Nc,Z.head=bo,Z.identity=La,Z.includes=gf,Z.indexOf=wo,Z.inRange=ia,Z.invoke=$h,Z.isArguments=dh,Z.isArray=bh,Z.isArrayBuffer=wh,Z.isArrayLike=Hf,Z.isArrayLikeObject=Jf,Z.isBoolean=Yf,Z.isBuffer=mh,Z.isDate=xh,Z.isElement=Qf,Z.isEmpty=Xf,Z.isEqual=nc,Z.isEqualWith=tc,Z.isError=rc,Z.isFinite=ec,Z.isFunction=uc,Z.isInteger=ic,Z.isLength=oc,Z.isMap=jh, 132 | Z.isMatch=ac,Z.isMatchWith=lc,Z.isNaN=sc,Z.isNative=hc,Z.isNil=_c,Z.isNull=pc,Z.isNumber=vc,Z.isObject=fc,Z.isObjectLike=cc,Z.isPlainObject=gc,Z.isRegExp=Ah,Z.isSafeInteger=yc,Z.isSet=kh,Z.isString=dc,Z.isSymbol=bc,Z.isTypedArray=Oh,Z.isUndefined=wc,Z.isWeakMap=mc,Z.isWeakSet=xc,Z.join=xo,Z.kebabCase=Kh,Z.last=jo,Z.lastIndexOf=Ao,Z.lowerCase=Vh,Z.lowerFirst=Gh,Z.lt=Ih,Z.lte=Rh,Z.max=Ya,Z.maxBy=Qa,Z.mean=Xa,Z.meanBy=nl,Z.min=tl,Z.minBy=rl,Z.stubArray=Pa,Z.stubFalse=qa,Z.stubObject=Za,Z.stubString=Ka, 133 | Z.stubTrue=Va,Z.multiply=_p,Z.nth=ko,Z.noConflict=$a,Z.noop=Da,Z.now=fh,Z.pad=ha,Z.padEnd=pa,Z.padStart=_a,Z.parseInt=va,Z.random=oa,Z.reduce=bf,Z.reduceRight=wf,Z.repeat=ga,Z.replace=ya,Z.result=Hc,Z.round=vp,Z.runInContext=p,Z.sample=xf,Z.size=kf,Z.snakeCase=Hh,Z.some=Of,Z.sortedIndex=Wo,Z.sortedIndexBy=Lo,Z.sortedIndexOf=Co,Z.sortedLastIndex=Uo,Z.sortedLastIndexBy=Bo,Z.sortedLastIndexOf=To,Z.startCase=Jh,Z.startsWith=ba,Z.subtract=gp,Z.sum=el,Z.sumBy=ul,Z.template=wa,Z.times=Ga,Z.toFinite=Ac,Z.toInteger=kc, 134 | Z.toLength=Oc,Z.toLower=ma,Z.toNumber=Ic,Z.toSafeInteger=zc,Z.toString=Ec,Z.toUpper=xa,Z.trim=ja,Z.trimEnd=Aa,Z.trimStart=ka,Z.truncate=Oa,Z.unescape=Ia,Z.uniqueId=Ja,Z.upperCase=Yh,Z.upperFirst=Qh,Z.each=_f,Z.eachRight=vf,Z.first=bo,Ta(Z,function(){var n={};return ue(Z,function(t,r){bl.call(Z.prototype,r)||(n[r]=t)}),n}(),{chain:!1}),Z.VERSION=nn,r(["bind","bindKey","curry","curryRight","partial","partialRight"],function(n){Z[n].placeholder=Z}),r(["drop","take"],function(n,t){Ct.prototype[n]=function(r){ 135 | r=r===X?1:Gl(kc(r),0);var e=this.__filtered__&&!t?new Ct(this):this.clone();return e.__filtered__?e.__takeCount__=Hl(r,e.__takeCount__):e.__views__.push({size:Hl(r,Un),type:n+(e.__dir__<0?"Right":"")}),e},Ct.prototype[n+"Right"]=function(t){return this.reverse()[n](t).reverse()}}),r(["filter","map","takeWhile"],function(n,t){var r=t+1,e=r==Rn||r==En;Ct.prototype[n]=function(n){var t=this.clone();return t.__iteratees__.push({iteratee:mi(n,3),type:r}),t.__filtered__=t.__filtered__||e,t}}),r(["head","last"],function(n,t){ 136 | var r="take"+(t?"Right":"");Ct.prototype[n]=function(){return this[r](1).value()[0]}}),r(["initial","tail"],function(n,t){var r="drop"+(t?"":"Right");Ct.prototype[n]=function(){return this.__filtered__?new Ct(this):this[r](1)}}),Ct.prototype.compact=function(){return this.filter(La)},Ct.prototype.find=function(n){return this.filter(n).head()},Ct.prototype.findLast=function(n){return this.reverse().find(n)},Ct.prototype.invokeMap=uu(function(n,t){return"function"==typeof n?new Ct(this):this.map(function(r){ 137 | return Ie(r,n,t)})}),Ct.prototype.reject=function(n){return this.filter(Uf(mi(n)))},Ct.prototype.slice=function(n,t){n=kc(n);var r=this;return r.__filtered__&&(n>0||t<0)?new Ct(r):(n<0?r=r.takeRight(-n):n&&(r=r.drop(n)),t!==X&&(t=kc(t),r=t<0?r.dropRight(-t):r.take(t-n)),r)},Ct.prototype.takeRightWhile=function(n){return this.reverse().takeWhile(n).reverse()},Ct.prototype.toArray=function(){return this.take(Un)},ue(Ct.prototype,function(n,t){var r=/^(?:filter|find|map|reject)|While$/.test(t),e=/^(?:head|last)$/.test(t),u=Z[e?"take"+("last"==t?"Right":""):t],i=e||/^find/.test(t); 138 | u&&(Z.prototype[t]=function(){var t=this.__wrapped__,o=e?[1]:arguments,f=t instanceof Ct,c=o[0],l=f||bh(t),s=function(n){var t=u.apply(Z,a([n],o));return e&&h?t[0]:t};l&&r&&"function"==typeof c&&1!=c.length&&(f=l=!1);var h=this.__chain__,p=!!this.__actions__.length,_=i&&!h,v=f&&!p;if(!i&&l){t=v?t:new Ct(this);var g=n.apply(t,o);return g.__actions__.push({func:nf,args:[s],thisArg:X}),new Y(g,h)}return _&&v?n.apply(this,o):(g=this.thru(s),_?e?g.value()[0]:g.value():g)})}),r(["pop","push","shift","sort","splice","unshift"],function(n){ 139 | var t=_l[n],r=/^(?:push|sort|unshift)$/.test(n)?"tap":"thru",e=/^(?:pop|shift)$/.test(n);Z.prototype[n]=function(){var n=arguments;if(e&&!this.__chain__){var u=this.value();return t.apply(bh(u)?u:[],n)}return this[r](function(r){return t.apply(bh(r)?r:[],n)})}}),ue(Ct.prototype,function(n,t){var r=Z[t];if(r){var e=r.name+"";bl.call(fs,e)||(fs[e]=[]),fs[e].push({name:t,func:r})}}),fs[Qu(X,vn).name]=[{name:"wrapper",func:X}],Ct.prototype.clone=$t,Ct.prototype.reverse=Yt,Ct.prototype.value=Qt,Z.prototype.at=Qs, 140 | Z.prototype.chain=tf,Z.prototype.commit=rf,Z.prototype.next=ef,Z.prototype.plant=of,Z.prototype.reverse=ff,Z.prototype.toJSON=Z.prototype.valueOf=Z.prototype.value=cf,Z.prototype.first=Z.prototype.head,Ul&&(Z.prototype[Ul]=uf),Z},be=de();"function"==typeof define&&"object"==typeof define.amd&&define.amd?(re._=be,define(function(){return be})):ue?((ue.exports=be)._=be,ee._=be):re._=be}).call(this); -------------------------------------------------------------------------------- /frontend/static/socket.io.4.4.1.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Socket.IO v4.4.1 3 | * (c) 2014-2022 Guillermo Rauch 4 | * Released under the MIT License. 5 | */ 6 | !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).io=e()}(this,(function(){"use strict";function t(e){return t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},t(e)}function e(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function n(t,e){for(var n=0;nt.length)&&(e=t.length);for(var n=0,r=new Array(e);n=t.length?{done:!0}:{done:!1,value:t[r++]}},e:function(t){throw t},f:o}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var i,s=!0,a=!1;return{s:function(){n=n.call(t)},n:function(){var t=n.next();return s=t.done,t},e:function(t){a=!0,i=t},f:function(){try{s||null==n.return||n.return()}finally{if(a)throw i}}}}var d=/^(?:(?![^:@]+:[^:@\/]*@)(http|https|ws|wss):\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/,y=["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],v=function(t){var e=t,n=t.indexOf("["),r=t.indexOf("]");-1!=n&&-1!=r&&(t=t.substring(0,n)+t.substring(n,r).replace(/:/g,";")+t.substring(r,t.length));for(var o,i,s=d.exec(t||""),a={},c=14;c--;)a[y[c]]=s[c]||"";return-1!=n&&-1!=r&&(a.source=e,a.host=a.host.substring(1,a.host.length-1).replace(/;/g,":"),a.authority=a.authority.replace("[","").replace("]","").replace(/;/g,":"),a.ipv6uri=!0),a.pathNames=function(t,e){var n=/\/{2,9}/g,r=e.replace(n,"/").split("/");"/"!=e.substr(0,1)&&0!==e.length||r.splice(0,1);"/"==e.substr(e.length-1,1)&&r.splice(r.length-1,1);return r}(0,a.path),a.queryKey=(o=a.query,i={},o.replace(/(?:^|&)([^&=]*)=?([^&]*)/g,(function(t,e,n){e&&(i[e]=n)})),i),a};var m={exports:{}};try{m.exports="undefined"!=typeof XMLHttpRequest&&"withCredentials"in new XMLHttpRequest}catch(t){m.exports=!1}var g=m.exports,k="undefined"!=typeof self?self:"undefined"!=typeof window?window:Function("return this")();function b(t){var e=t.xdomain;try{if("undefined"!=typeof XMLHttpRequest&&(!e||g))return new XMLHttpRequest}catch(t){}if(!e)try{return new(k[["Active"].concat("Object").join("X")])("Microsoft.XMLHTTP")}catch(t){}}function w(t){for(var e=arguments.length,n=new Array(e>1?e-1:0),r=1;r1?{type:O[n],data:t.substring(1)}:{type:O[n]}:S},M=function(t,e){if(I){var n=function(t){var e,n,r,o,i,s=.75*t.length,a=t.length,c=0;"="===t[t.length-1]&&(s--,"="===t[t.length-2]&&s--);var u=new ArrayBuffer(s),h=new Uint8Array(u);for(e=0;e>4,h[c++]=(15&r)<<4|o>>2,h[c++]=(3&o)<<6|63&i;return u}(t);return U(n,e)}return{base64:!0,data:t}},U=function(t,e){return"blob"===e&&t instanceof ArrayBuffer?new Blob([t]):t},V=String.fromCharCode(30),H=function(t){i(o,t);var n=h(o);function o(t){var r;return e(this,o),(r=n.call(this)).writable=!1,A(c(r),t),r.opts=t,r.query=t.query,r.readyState="",r.socket=t.socket,r}return r(o,[{key:"onError",value:function(t,e){var n=new Error(t);return n.type="TransportError",n.description=e,f(s(o.prototype),"emit",this).call(this,"error",n),this}},{key:"open",value:function(){return"closed"!==this.readyState&&""!==this.readyState||(this.readyState="opening",this.doOpen()),this}},{key:"close",value:function(){return"opening"!==this.readyState&&"open"!==this.readyState||(this.doClose(),this.onClose()),this}},{key:"send",value:function(t){"open"===this.readyState&&this.write(t)}},{key:"onOpen",value:function(){this.readyState="open",this.writable=!0,f(s(o.prototype),"emit",this).call(this,"open")}},{key:"onData",value:function(t){var e=F(t,this.socket.binaryType);this.onPacket(e)}},{key:"onPacket",value:function(t){f(s(o.prototype),"emit",this).call(this,"packet",t)}},{key:"onClose",value:function(){this.readyState="closed",f(s(o.prototype),"emit",this).call(this,"close")}}]),o}(R),K="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_".split(""),Y={},z=0,$=0;function W(t){var e="";do{e=K[t%64]+e,t=Math.floor(t/64)}while(t>0);return e}function J(){var t=W(+new Date);return t!==D?(z=0,D=t):t+"."+W(z++)}for(;$<64;$++)Y[K[$]]=$;J.encode=W,J.decode=function(t){var e=0;for($=0;$0&&void 0!==arguments[0]?arguments[0]:{};return o(t,{xd:this.xd,xs:this.xs},this.opts),new nt(this.uri(),t)}},{key:"doWrite",value:function(t,e){var n=this,r=this.request({method:"POST",data:t});r.on("success",e),r.on("error",(function(t){n.onError("xhr post error",t)}))}},{key:"doPoll",value:function(){var t=this,e=this.request();e.on("data",this.onData.bind(this)),e.on("error",(function(e){t.onError("xhr poll error",e)})),this.pollXhr=e}}]),s}(Q),nt=function(t){i(o,t);var n=h(o);function o(t,r){var i;return e(this,o),A(c(i=n.call(this)),r),i.opts=r,i.method=r.method||"GET",i.uri=t,i.async=!1!==r.async,i.data=void 0!==r.data?r.data:null,i.create(),i}return r(o,[{key:"create",value:function(){var t=this,e=w(this.opts,"agent","pfx","key","passphrase","cert","ca","ciphers","rejectUnauthorized","autoUnref");e.xdomain=!!this.opts.xd,e.xscheme=!!this.opts.xs;var n=this.xhr=new b(e);try{n.open(this.method,this.uri,this.async);try{if(this.opts.extraHeaders)for(var r in n.setDisableHeaderCheck&&n.setDisableHeaderCheck(!0),this.opts.extraHeaders)this.opts.extraHeaders.hasOwnProperty(r)&&n.setRequestHeader(r,this.opts.extraHeaders[r])}catch(t){}if("POST"===this.method)try{n.setRequestHeader("Content-type","text/plain;charset=UTF-8")}catch(t){}try{n.setRequestHeader("Accept","*/*")}catch(t){}"withCredentials"in n&&(n.withCredentials=this.opts.withCredentials),this.opts.requestTimeout&&(n.timeout=this.opts.requestTimeout),n.onreadystatechange=function(){4===n.readyState&&(200===n.status||1223===n.status?t.onLoad():t.setTimeoutFn((function(){t.onError("number"==typeof n.status?n.status:0)}),0))},n.send(this.data)}catch(e){return void this.setTimeoutFn((function(){t.onError(e)}),0)}"undefined"!=typeof document&&(this.index=o.requestsCount++,o.requests[this.index]=this)}},{key:"onSuccess",value:function(){this.emit("success"),this.cleanup()}},{key:"onData",value:function(t){this.emit("data",t),this.onSuccess()}},{key:"onError",value:function(t){this.emit("error",t),this.cleanup(!0)}},{key:"cleanup",value:function(t){if(void 0!==this.xhr&&null!==this.xhr){if(this.xhr.onreadystatechange=Z,t)try{this.xhr.abort()}catch(t){}"undefined"!=typeof document&&delete o.requests[this.index],this.xhr=null}}},{key:"onLoad",value:function(){var t=this.xhr.responseText;null!==t&&this.onData(t)}},{key:"abort",value:function(){this.cleanup()}}]),o}(R);if(nt.requestsCount=0,nt.requests={},"undefined"!=typeof document)if("function"==typeof attachEvent)attachEvent("onunload",rt);else if("function"==typeof addEventListener){addEventListener("onpagehide"in k?"pagehide":"unload",rt,!1)}function rt(){for(var t in nt.requests)nt.requests.hasOwnProperty(t)&&nt.requests[t].abort()}var ot="function"==typeof Promise&&"function"==typeof Promise.resolve?function(t){return Promise.resolve().then(t)}:function(t,e){return e(t,0)},it=k.WebSocket||k.MozWebSocket,st="undefined"!=typeof navigator&&"string"==typeof navigator.product&&"reactnative"===navigator.product.toLowerCase(),at=function(t){i(o,t);var n=h(o);function o(t){var r;return e(this,o),(r=n.call(this,t)).supportsBinary=!t.forceBase64,r}return r(o,[{key:"name",get:function(){return"websocket"}},{key:"doOpen",value:function(){if(this.check()){var t=this.uri(),e=this.opts.protocols,n=st?{}:w(this.opts,"agent","perMessageDeflate","pfx","key","passphrase","cert","ca","ciphers","rejectUnauthorized","localAddress","protocolVersion","origin","maxPayload","family","checkServerIdentity");this.opts.extraHeaders&&(n.headers=this.opts.extraHeaders);try{this.ws=st?new it(t,e,n):e?new it(t,e):new it(t)}catch(t){return this.emit("error",t)}this.ws.binaryType=this.socket.binaryType||"arraybuffer",this.addEventListeners()}}},{key:"addEventListeners",value:function(){var t=this;this.ws.onopen=function(){t.opts.autoUnref&&t.ws._socket.unref(),t.onOpen()},this.ws.onclose=this.onClose.bind(this),this.ws.onmessage=function(e){return t.onData(e.data)},this.ws.onerror=function(e){return t.onError("websocket error",e)}}},{key:"write",value:function(t){var e=this;this.writable=!1;for(var n=function(n){var r=t[n],o=n===t.length-1;x(r,e.supportsBinary,(function(t){try{e.ws.send(t)}catch(t){}o&&ot((function(){e.writable=!0,e.emit("drain")}),e.setTimeoutFn)}))},r=0;r1&&void 0!==arguments[1]?arguments[1]:{};return e(this,a),r=s.call(this),n&&"object"===t(n)&&(i=n,n=null),n?(n=v(n),i.hostname=n.host,i.secure="https"===n.protocol||"wss"===n.protocol,i.port=n.port,n.query&&(i.query=n.query)):i.host&&(i.hostname=v(i.host).host),A(c(r),i),r.secure=null!=i.secure?i.secure:"undefined"!=typeof location&&"https:"===location.protocol,i.hostname&&!i.port&&(i.port=r.secure?"443":"80"),r.hostname=i.hostname||("undefined"!=typeof location?location.hostname:"localhost"),r.port=i.port||("undefined"!=typeof location&&location.port?location.port:r.secure?"443":"80"),r.transports=i.transports||["polling","websocket"],r.readyState="",r.writeBuffer=[],r.prevBufferLen=0,r.opts=o({path:"/engine.io",agent:!1,withCredentials:!1,upgrade:!0,timestampParam:"t",rememberUpgrade:!1,rejectUnauthorized:!0,perMessageDeflate:{threshold:1024},transportOptions:{},closeOnBeforeunload:!0},i),r.opts.path=r.opts.path.replace(/\/$/,"")+"/","string"==typeof r.opts.query&&(r.opts.query=G.decode(r.opts.query)),r.id=null,r.upgrades=null,r.pingInterval=null,r.pingTimeout=null,r.pingTimeoutTimer=null,"function"==typeof addEventListener&&(r.opts.closeOnBeforeunload&&addEventListener("beforeunload",(function(){r.transport&&(r.transport.removeAllListeners(),r.transport.close())}),!1),"localhost"!==r.hostname&&(r.offlineEventListener=function(){r.onClose("transport close")},addEventListener("offline",r.offlineEventListener,!1))),r.open(),r}return r(a,[{key:"createTransport",value:function(t){var e=function(t){var e={};for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);return e}(this.opts.query);e.EIO=4,e.transport=t,this.id&&(e.sid=this.id);var n=o({},this.opts.transportOptions[t],this.opts,{query:e,socket:this,hostname:this.hostname,secure:this.secure,port:this.port});return new ct[t](n)}},{key:"open",value:function(){var t,e=this;if(this.opts.rememberUpgrade&&a.priorWebsocketSuccess&&-1!==this.transports.indexOf("websocket"))t="websocket";else{if(0===this.transports.length)return void this.setTimeoutFn((function(){e.emitReserved("error","No transports available")}),0);t=this.transports[0]}this.readyState="opening";try{t=this.createTransport(t)}catch(t){return this.transports.shift(),void this.open()}t.open(),this.setTransport(t)}},{key:"setTransport",value:function(t){var e=this;this.transport&&this.transport.removeAllListeners(),this.transport=t,t.on("drain",this.onDrain.bind(this)).on("packet",this.onPacket.bind(this)).on("error",this.onError.bind(this)).on("close",(function(){e.onClose("transport close")}))}},{key:"probe",value:function(t){var e=this,n=this.createTransport(t),r=!1;a.priorWebsocketSuccess=!1;var o=function(){r||(n.send([{type:"ping",data:"probe"}]),n.once("packet",(function(t){if(!r)if("pong"===t.type&&"probe"===t.data){if(e.upgrading=!0,e.emitReserved("upgrading",n),!n)return;a.priorWebsocketSuccess="websocket"===n.name,e.transport.pause((function(){r||"closed"!==e.readyState&&(f(),e.setTransport(n),n.send([{type:"upgrade"}]),e.emitReserved("upgrade",n),n=null,e.upgrading=!1,e.flush())}))}else{var o=new Error("probe error");o.transport=n.name,e.emitReserved("upgradeError",o)}})))};function i(){r||(r=!0,f(),n.close(),n=null)}var s=function(t){var r=new Error("probe error: "+t);r.transport=n.name,i(),e.emitReserved("upgradeError",r)};function c(){s("transport closed")}function u(){s("socket closed")}function h(t){n&&t.name!==n.name&&i()}var f=function(){n.removeListener("open",o),n.removeListener("error",s),n.removeListener("close",c),e.off("close",u),e.off("upgrading",h)};n.once("open",o),n.once("error",s),n.once("close",c),this.once("close",u),this.once("upgrading",h),n.open()}},{key:"onOpen",value:function(){if(this.readyState="open",a.priorWebsocketSuccess="websocket"===this.transport.name,this.emitReserved("open"),this.flush(),"open"===this.readyState&&this.opts.upgrade&&this.transport.pause)for(var t=0,e=this.upgrades.length;t0;case bt.ACK:case bt.BINARY_ACK:return Array.isArray(n)}}}]),a}(R);var Et=function(){function t(n){e(this,t),this.packet=n,this.buffers=[],this.reconPack=n}return r(t,[{key:"takeBinaryData",value:function(t){if(this.buffers.push(t),this.buffers.length===this.reconPack.attachments){var e=gt(this.reconPack,this.buffers);return this.finishedReconstruction(),e}return null}},{key:"finishedReconstruction",value:function(){this.reconPack=null,this.buffers=[]}}]),t}(),At=Object.freeze({__proto__:null,protocol:5,get PacketType(){return bt},Encoder:wt,Decoder:_t});function Rt(t,e,n){return t.on(e,n),function(){t.off(e,n)}}var Tt=Object.freeze({connect:1,connect_error:1,disconnect:1,disconnecting:1,newListener:1,removeListener:1}),Ct=function(t){i(o,t);var n=h(o);function o(t,r,i){var s;return e(this,o),(s=n.call(this)).connected=!1,s.disconnected=!0,s.receiveBuffer=[],s.sendBuffer=[],s.ids=0,s.acks={},s.flags={},s.io=t,s.nsp=r,i&&i.auth&&(s.auth=i.auth),s.io._autoConnect&&s.open(),s}return r(o,[{key:"subEvents",value:function(){if(!this.subs){var t=this.io;this.subs=[Rt(t,"open",this.onopen.bind(this)),Rt(t,"packet",this.onpacket.bind(this)),Rt(t,"error",this.onerror.bind(this)),Rt(t,"close",this.onclose.bind(this))]}}},{key:"active",get:function(){return!!this.subs}},{key:"connect",value:function(){return this.connected||(this.subEvents(),this.io._reconnecting||this.io.open(),"open"===this.io._readyState&&this.onopen()),this}},{key:"open",value:function(){return this.connect()}},{key:"send",value:function(){for(var t=arguments.length,e=new Array(t),n=0;n1?e-1:0),r=1;r0&&t.jitter<=1?t.jitter:0,this.attempts=0}St.prototype.duration=function(){var t=this.ms*Math.pow(this.factor,this.attempts++);if(this.jitter){var e=Math.random(),n=Math.floor(e*this.jitter*t);t=0==(1&Math.floor(10*e))?t-n:t+n}return 0|Math.min(t,this.max)},St.prototype.reset=function(){this.attempts=0},St.prototype.setMin=function(t){this.ms=t},St.prototype.setMax=function(t){this.max=t},St.prototype.setJitter=function(t){this.jitter=t};var Bt=function(n){i(s,n);var o=h(s);function s(n,r){var i,a;e(this,s),(i=o.call(this)).nsps={},i.subs=[],n&&"object"===t(n)&&(r=n,n=void 0),(r=r||{}).path=r.path||"/socket.io",i.opts=r,A(c(i),r),i.reconnection(!1!==r.reconnection),i.reconnectionAttempts(r.reconnectionAttempts||1/0),i.reconnectionDelay(r.reconnectionDelay||1e3),i.reconnectionDelayMax(r.reconnectionDelayMax||5e3),i.randomizationFactor(null!==(a=r.randomizationFactor)&&void 0!==a?a:.5),i.backoff=new Ot({min:i.reconnectionDelay(),max:i.reconnectionDelayMax(),jitter:i.randomizationFactor()}),i.timeout(null==r.timeout?2e4:r.timeout),i._readyState="closed",i.uri=n;var u=r.parser||At;return i.encoder=new u.Encoder,i.decoder=new u.Decoder,i._autoConnect=!1!==r.autoConnect,i._autoConnect&&i.open(),i}return r(s,[{key:"reconnection",value:function(t){return arguments.length?(this._reconnection=!!t,this):this._reconnection}},{key:"reconnectionAttempts",value:function(t){return void 0===t?this._reconnectionAttempts:(this._reconnectionAttempts=t,this)}},{key:"reconnectionDelay",value:function(t){var e;return void 0===t?this._reconnectionDelay:(this._reconnectionDelay=t,null===(e=this.backoff)||void 0===e||e.setMin(t),this)}},{key:"randomizationFactor",value:function(t){var e;return void 0===t?this._randomizationFactor:(this._randomizationFactor=t,null===(e=this.backoff)||void 0===e||e.setJitter(t),this)}},{key:"reconnectionDelayMax",value:function(t){var e;return void 0===t?this._reconnectionDelayMax:(this._reconnectionDelayMax=t,null===(e=this.backoff)||void 0===e||e.setMax(t),this)}},{key:"timeout",value:function(t){return arguments.length?(this._timeout=t,this):this._timeout}},{key:"maybeReconnectOnOpen",value:function(){!this._reconnecting&&this._reconnection&&0===this.backoff.attempts&&this.reconnect()}},{key:"open",value:function(t){var e=this;if(~this._readyState.indexOf("open"))return this;this.engine=new ut(this.uri,this.opts);var n=this.engine,r=this;this._readyState="opening",this.skipReconnect=!1;var o=Rt(n,"open",(function(){r.onopen(),t&&t()})),i=Rt(n,"error",(function(n){r.cleanup(),r._readyState="closed",e.emitReserved("error",n),t?t(n):r.maybeReconnectOnOpen()}));if(!1!==this._timeout){var s=this._timeout;0===s&&o();var a=this.setTimeoutFn((function(){o(),n.close(),n.emit("error",new Error("timeout"))}),s);this.opts.autoUnref&&a.unref(),this.subs.push((function(){clearTimeout(a)}))}return this.subs.push(o),this.subs.push(i),this}},{key:"connect",value:function(t){return this.open(t)}},{key:"onopen",value:function(){this.cleanup(),this._readyState="open",this.emitReserved("open");var t=this.engine;this.subs.push(Rt(t,"ping",this.onping.bind(this)),Rt(t,"data",this.ondata.bind(this)),Rt(t,"error",this.onerror.bind(this)),Rt(t,"close",this.onclose.bind(this)),Rt(this.decoder,"decoded",this.ondecoded.bind(this)))}},{key:"onping",value:function(){this.emitReserved("ping")}},{key:"ondata",value:function(t){this.decoder.add(t)}},{key:"ondecoded",value:function(t){this.emitReserved("packet",t)}},{key:"onerror",value:function(t){this.emitReserved("error",t)}},{key:"socket",value:function(t,e){var n=this.nsps[t];return n||(n=new Ct(this,t,e),this.nsps[t]=n),n}},{key:"_destroy",value:function(t){for(var e=0,n=Object.keys(this.nsps);e=this._reconnectionAttempts)this.backoff.reset(),this.emitReserved("reconnect_failed"),this._reconnecting=!1;else{var n=this.backoff.duration();this._reconnecting=!0;var r=this.setTimeoutFn((function(){e.skipReconnect||(t.emitReserved("reconnect_attempt",e.backoff.attempts),e.skipReconnect||e.open((function(n){n?(e._reconnecting=!1,e.reconnect(),t.emitReserved("reconnect_error",n)):e.onreconnect()})))}),n);this.opts.autoUnref&&r.unref(),this.subs.push((function(){clearTimeout(r)}))}}},{key:"onreconnect",value:function(){var t=this.backoff.attempts;this._reconnecting=!1,this.backoff.reset(),this.emitReserved("reconnect",t)}}]),s}(R),Nt={};function xt(e,n){"object"===t(e)&&(n=e,e=void 0);var r,o=function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n=arguments.length>2?arguments[2]:void 0,r=t;n=n||"undefined"!=typeof location&&location,null==t&&(t=n.protocol+"//"+n.host),"string"==typeof t&&("/"===t.charAt(0)&&(t="/"===t.charAt(1)?n.protocol+t:n.host+t),/^(https?|wss?):\/\//.test(t)||(t=void 0!==n?n.protocol+"//"+t:"https://"+t),r=v(t)),r.port||(/^(http|ws)$/.test(r.protocol)?r.port="80":/^(http|ws)s$/.test(r.protocol)&&(r.port="443")),r.path=r.path||"/";var o=-1!==r.host.indexOf(":")?"["+r.host+"]":r.host;return r.id=r.protocol+"://"+o+":"+r.port+e,r.href=r.protocol+"://"+o+(n&&n.port===r.port?"":":"+r.port),r}(e,(n=n||{}).path||"/socket.io"),i=o.source,s=o.id,a=o.path,c=Nt[s]&&a in Nt[s].nsps;return n.forceNew||n["force new connection"]||!1===n.multiplex||c?r=new Bt(i,n):(Nt[s]||(Nt[s]=new Bt(i,n)),r=Nt[s]),o.query&&!n.query&&(n.query=o.queryKey),r.socket(o.path,n)}return o(xt,{Manager:Bt,Socket:Ct,io:xt,connect:xt}),xt})); 7 | //# sourceMappingURL=socket.io.min.js.map 8 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const runCmd = require("./server/utils/runCmd"); 3 | const logger = require("./server/utils/logger"); 4 | 5 | class ZuoDeploy { 6 | constructor() {} 7 | 8 | async start(args) { 9 | // 存储参数,用于多文件传参 10 | fs.writeFileSync("args.json", JSON.stringify(args)); 11 | // 删除原先的服务 12 | runCmd("pm2", ["delete", "zuodeploy"], () => {}); 13 | // // 防止异步并行,sleep 1s 14 | await new Promise((resolve) => setTimeout(resolve, 1000)); 15 | // 开启 pm2 服务 16 | const argv = ["start", __dirname + "/server/index.js", "-n", "zuodeploy"]; 17 | runCmd("pm2", argv, (text) => { 18 | logger.log(text); 19 | }); 20 | // runCmd("node", [__dirname + "/server/index.js"], (text) => { 21 | // logger.log(text); 22 | // }); 23 | } 24 | } 25 | 26 | module.exports = ZuoDeploy; 27 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zuo-deploy", 3 | "version": "1.0.8", 4 | "description": "CI CD server", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/zuoxiaobai/zuo-deploy.git" 12 | }, 13 | "keywords": [ 14 | "ci", 15 | "cd", 16 | "deploy" 17 | ], 18 | "author": "dev-zuo", 19 | "license": "MIT", 20 | "bugs": { 21 | "url": "https://github.com/zuoxiaobai/zuo-deploy/issues" 22 | }, 23 | "homepage": "https://github.com/zuoxiaobai/zuo-deploy#readme", 24 | "devDependencies": { 25 | "eslint": "^7.32.0", 26 | "eslint-config-prettier": "^8.3.0", 27 | "eslint-plugin-prettier": "^4.0.0", 28 | "prettier": "2.5.1" 29 | }, 30 | "bin": { 31 | "zuodeploy": "./bin/zuodeploy.js" 32 | }, 33 | "dependencies": { 34 | "@koa/multer": "3.0.0", 35 | "commander": "9.0.0", 36 | "koa": "2.13.4", 37 | "koa-bodyparser": "4.3.0", 38 | "koa-router": "10.1.1", 39 | "koa-session": "6.2.0", 40 | "koa-static": "5.0.0", 41 | "log4js": "6.4.1", 42 | "multer": "1.4.5-lts.1", 43 | "prompts": "2.4.2", 44 | "socket.io": "4.4.1" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /publish.sh: -------------------------------------------------------------------------------- 1 | npm config set registry=https://registry.npmjs.org 2 | npm login # 登陆 ,如果有 OTP, 邮箱会接收到验证码,输入即可 3 | # 登录成功后,短时间内会保存状态,可以直接 npm pubish 4 | npm publish # 可能会提示名称已存在,换个名字,获取使用作用域包(@xxx/xxx) 5 | npm config set registry=https://registry.npm.taobao.org # 还原淘宝镜像 -------------------------------------------------------------------------------- /server/index.js: -------------------------------------------------------------------------------- 1 | const Koa = require("koa"); 2 | const KoaStatic = require("koa-static"); 3 | const KoaRouter = require("koa-router"); 4 | const session = require("koa-session"); 5 | const bodyParser = require("koa-bodyparser"); 6 | const path = require("path"); 7 | const fs = require("fs"); 8 | const runCmd = require("./utils/runCmd"); 9 | const logger = require("./utils/logger"); 10 | 11 | const app = new Koa(); 12 | const router = new KoaRouter(); 13 | 14 | app.use(bodyParser()); // 处理 post 请求参数 15 | 16 | // 参数获取 17 | let argsInfo = fs.readFileSync("args.json").toString(); 18 | let args = {}; 19 | try { 20 | args = JSON.parse(argsInfo); 21 | } catch (e) { 22 | logger.info(e); 23 | } 24 | 25 | // 集成 session 26 | app.keys = [`${args.password}`]; // 'some secret hurr' 27 | const CONFIG = { 28 | key: "koa:sess" /** (string) cookie key (default is koa:sess) */, 29 | /** (number || 'session') maxAge in ms (default is 1 days) */ 30 | /** 'session' will result in a cookie that expires when session/browser is closed */ 31 | /** Warning: If a session cookie is stolen, this cookie will never expire */ 32 | maxAge: 0.5 * 3600 * 1000, // 0.5h 33 | overwrite: true /** (boolean) can overwrite or not (default true) */, 34 | httpOnly: true /** (boolean) httpOnly or not (default true) */, 35 | signed: true /** (boolean) signed or not (default true) */, 36 | rolling: false /** (boolean) Force a session identifier cookie to be set on every response. The expiration is reset to the original maxAge, resetting the expiration countdown. (default is false) */, 37 | renew: false /** (boolean) renew session when session is nearly expired, so we can always keep user logged in. (default is false)*/, 38 | }; 39 | app.use(session(CONFIG, app)); 40 | 41 | // 开启 socket 服务 42 | let socketList = []; 43 | const server = require("http").Server(app.callback()); 44 | const socketIo = require("socket.io")(server); 45 | socketIo.on("connection", (socket) => { 46 | socketList.push(socket); 47 | logger.info("a user connected"); 48 | }); 49 | 50 | router.get("/isLogin", async (ctx) => { 51 | ctx.body = { 52 | code: 0, 53 | data: !!ctx.session.isLogin, 54 | msg: "false 未登录,true 登录", 55 | }; 56 | }); 57 | 58 | router.post("/login", async (ctx) => { 59 | let code = 0; 60 | let msg = "登录成功"; 61 | let { password } = ctx.request.body; 62 | if (password === `${args.password}`) { 63 | ctx.session.isLogin = true; 64 | } else { 65 | code = -1; 66 | msg = "密码错误"; 67 | } 68 | ctx.body = { 69 | code, 70 | msg, 71 | }; 72 | }); 73 | 74 | router.post("/deploy", async (ctx) => { 75 | if (!ctx.session.isLogin) { 76 | ctx.body = { 77 | code: -2, 78 | msg: "未登录", 79 | }; 80 | return; 81 | } 82 | 83 | // 执行部署脚本 84 | // koa 注意异步 404 的问题 85 | let execFunc = () => { 86 | return new Promise((resolve, reject) => { 87 | try { 88 | runCmd( 89 | "sh", 90 | ["./deploy-master.sh"], 91 | function (text) { 92 | resolve(text); 93 | }, 94 | socketIo, 95 | "deploy-log" 96 | ); 97 | } catch (e) { 98 | logger.info(e); 99 | reject(e); 100 | } 101 | }); 102 | }; 103 | 104 | try { 105 | let res = await execFunc(); 106 | ctx.body = { 107 | code: 0, 108 | msg: res, 109 | }; 110 | } catch (e) { 111 | ctx.body = { 112 | code: -1, 113 | msg: e.message, 114 | }; 115 | } 116 | }); 117 | 118 | router.post("/runShell", async (ctx) => { 119 | if (!ctx.session.isLogin) { 120 | ctx.body = { 121 | code: -2, 122 | msg: "未登录", 123 | }; 124 | return; 125 | } 126 | 127 | let { shellText, shellName = "temp.sh", timeoutMinute = 2 } = ctx.request.body; 128 | const shellFilePath = process.cwd() + "/" + shellName; 129 | console.log("shellFilePath", shellFilePath); 130 | try { 131 | fs.writeFileSync(shellFilePath, shellText); 132 | } catch (e) { 133 | console.log(e); 134 | ctx.body = { 135 | code: -1, 136 | msg: e.message, 137 | }; 138 | } 139 | 140 | // // 执行部署脚本 141 | // // koa 注意异步 404 的问题 142 | let execFunc = () => { 143 | return new Promise((resolve, reject) => { 144 | try { 145 | runCmd( 146 | "sh", 147 | [shellFilePath], 148 | function (text, isError) { 149 | isError ? reject(new Error(text)) : resolve(text); 150 | }, 151 | socketIo, 152 | "runShell", 153 | timeoutMinute 154 | ); 155 | } catch (e) { 156 | logger.info(e); 157 | reject(e); 158 | } 159 | }); 160 | }; 161 | 162 | try { 163 | let res = await execFunc(); 164 | ctx.body = { 165 | code: 0, 166 | msg: res, 167 | }; 168 | } catch (e) { 169 | ctx.body = { 170 | code: -1, 171 | msg: e.message, 172 | }; 173 | } 174 | }); 175 | 176 | router.get("/shell/get", async (ctx) => { 177 | if (!ctx.session.isLogin) { 178 | ctx.body = { 179 | code: -2, 180 | msg: "未登录", 181 | }; 182 | return; 183 | } 184 | 185 | const files = fs.readdirSync(`${process.cwd()}`); 186 | let result = []; 187 | // files [ 'args.json', 'temp.sh', 'test.sh' ] 188 | let filesFilter = files.filter((item) => { 189 | if (["args.json", "temp.sh"].includes(item)) { 190 | return false; 191 | } 192 | if (item.startsWith(".")) { 193 | return false; 194 | } 195 | return true; 196 | }); 197 | console.log(filesFilter); 198 | 199 | filesFilter.forEach((filePath) => { 200 | console.log(`'${filePath}'`); 201 | let info = { name: filePath, content: "", desc: "" }; 202 | try { 203 | const content = fs 204 | .readFileSync(`${process.cwd()}/${filePath}`) 205 | .toString(); 206 | info.content = content; 207 | result.push(info); 208 | } catch (e) { 209 | console.log("非文件", e.message); 210 | } 211 | }); 212 | 213 | // [ 214 | // { name: "1.sh", content: "ls\npwd\n", desc: "定时任务" }, 215 | // { 216 | // name: "2.sh", 217 | // content: "git pull;\n npm i && npm run build\n", 218 | // desc: "项目部署", 219 | // }, 220 | // ], 221 | ctx.body = { 222 | code: 0, 223 | data: { 224 | processCwd: process.cwd(), 225 | shellList: result, 226 | }, 227 | msg: "成功", 228 | }; 229 | }); 230 | 231 | router.post("/runCurShell", async (ctx) => { 232 | if (!ctx.session.isLogin) { 233 | ctx.body = { 234 | code: -2, 235 | msg: "未登录", 236 | }; 237 | return; 238 | } 239 | 240 | let { name, timeoutMinute } = ctx.request.body; 241 | const shellFilePath = process.cwd() + "/" + name; 242 | console.log("cur shellFilePath", shellFilePath); 243 | 244 | // // 执行部署脚本 245 | // // koa 注意异步 404 的问题 246 | let execFunc = () => { 247 | return new Promise((resolve, reject) => { 248 | try { 249 | runCmd( 250 | "sh", 251 | [shellFilePath], 252 | function (text, isError) { 253 | isError ? reject(new Error(text)) : resolve(text); 254 | }, 255 | socketIo, 256 | "shell-log-" + name, 257 | timeoutMinute 258 | ); 259 | } catch (e) { 260 | logger.info(e); 261 | reject(e); 262 | } 263 | }); 264 | }; 265 | 266 | try { 267 | let res = await execFunc(); 268 | ctx.body = { 269 | code: 0, 270 | msg: res, 271 | }; 272 | } catch (e) { 273 | ctx.body = { 274 | code: -1, 275 | msg: e.message, 276 | }; 277 | } 278 | }); 279 | 280 | router.post("/saveFile", async (ctx) => { 281 | if (!ctx.session.isLogin) { 282 | ctx.body = { 283 | code: -2, 284 | msg: "未登录", 285 | }; 286 | return; 287 | } 288 | let { name, content, curPath } = ctx.request.body; 289 | console.log(name, content, curPath); 290 | !curPath && (curPath = "."); 291 | let prePath = curPath.startsWith("/") 292 | ? curPath 293 | : path.join(process.cwd(), curPath); 294 | 295 | const filePath = prePath + (prePath.endsWith("/") ? "" : "/") + name; 296 | console.log("filePath", filePath, prePath); 297 | try { 298 | fs.writeFileSync(filePath, content); 299 | ctx.body = { 300 | code: 0, 301 | msg: "成功", 302 | }; 303 | } catch (e) { 304 | console.log(e); 305 | ctx.body = { 306 | code: -1, 307 | msg: `文件 '${filePath}' 创建失败,` + e.message, 308 | }; 309 | } 310 | }); 311 | 312 | router.post("/editFile", async (ctx) => { 313 | if (!ctx.session.isLogin) { 314 | ctx.body = { 315 | code: -2, 316 | msg: "未登录", 317 | }; 318 | return; 319 | } 320 | let { name, content, curPath } = ctx.request.body; 321 | // console.log(name, content, curPath); 322 | !curPath && (curPath = "."); 323 | let prePath = curPath.startsWith("/") 324 | ? curPath 325 | : path.join(process.cwd(), curPath); 326 | const filePath = prePath + (prePath.endsWith("/") ? "" : "/") + name; 327 | // console.log("filePath", filePath, prePath); 328 | try { 329 | fs.writeFileSync(filePath, content); 330 | ctx.body = { 331 | code: 0, 332 | msg: "成功", 333 | }; 334 | } catch (e) { 335 | console.log(e); 336 | ctx.body = { 337 | code: -1, 338 | msg: `文件 '${filePath}' 修改失败,` + e.message, 339 | }; 340 | } 341 | }); 342 | 343 | router.post("/deleteFile", async (ctx) => { 344 | if (!ctx.session.isLogin) { 345 | ctx.body = { 346 | code: -2, 347 | msg: "未登录", 348 | }; 349 | return; 350 | } 351 | let { name, curPath } = ctx.request.body; 352 | console.log(name, curPath); 353 | !curPath && (curPath = "."); 354 | let prePath = curPath.startsWith("/") 355 | ? curPath 356 | : path.join(process.cwd(), curPath); 357 | const filePath = prePath + (prePath.endsWith("/") ? "" : "/") + name; 358 | // console.log("filePath", filePath, prePath); 359 | try { 360 | fs.rmSync(filePath); 361 | ctx.body = { 362 | code: 0, 363 | msg: "成功", 364 | }; 365 | } catch (e) { 366 | console.log(e); 367 | ctx.body = { 368 | code: -1, 369 | msg: `文件 '${filePath}' 删除失败,` + e.message, 370 | }; 371 | } 372 | }); 373 | 374 | router.get("/nginx/get", async (ctx) => { 375 | if (!ctx.session.isLogin) { 376 | ctx.body = { 377 | code: -2, 378 | msg: "未登录", 379 | }; 380 | return; 381 | } 382 | let { curPath } = ctx.query; 383 | console.log(">>", curPath); 384 | 385 | try { 386 | const content = fs.readFileSync(curPath).toString(); 387 | ctx.body = { 388 | code: 0, 389 | data: content, 390 | msg: "成功", 391 | }; 392 | } catch (e) { 393 | ctx.body = { 394 | code: -3, 395 | msg: e.message, 396 | }; 397 | } 398 | }); 399 | 400 | router.get("/nginx/multipleGet", async (ctx) => { 401 | if (!ctx.session.isLogin) { 402 | ctx.body = { 403 | code: -2, 404 | msg: "未登录", 405 | }; 406 | return; 407 | } 408 | let { curPath } = ctx.query; 409 | console.log(">>", curPath); 410 | 411 | let files = []; 412 | try { 413 | files = fs.readdirSync(curPath); 414 | } catch (e) { 415 | ctx.body = { 416 | code: -3, 417 | msg: e.message, 418 | }; 419 | return; 420 | } 421 | 422 | let result = []; 423 | // files [ 'args.json', 'temp.sh', 'test.sh' ] 424 | let filesFilter = files.filter((item) => { 425 | // if ([].includes(item)) { 426 | // return false; 427 | // } 428 | if (item.startsWith(".")) { 429 | return false; 430 | } 431 | return true; 432 | }); 433 | console.log(filesFilter); 434 | 435 | filesFilter.forEach((filePath) => { 436 | console.log(`'${filePath}'`); 437 | let info = { name: filePath, content: "", desc: "" }; 438 | try { 439 | const content = fs.readFileSync(`${curPath}/${filePath}`).toString(); 440 | info.content = content; 441 | result.push(info); 442 | } catch (e) { 443 | console.log("非文件", e.message); 444 | } 445 | }); 446 | ctx.body = { 447 | code: 0, 448 | data: result, 449 | msg: "成功", 450 | }; 451 | }); 452 | 453 | router.get("/https/get", async (ctx) => { 454 | if (!ctx.session.isLogin) { 455 | ctx.body = { 456 | code: -2, 457 | msg: "未登录", 458 | }; 459 | return; 460 | } 461 | let { curPath } = ctx.query; 462 | console.log(">>", curPath); 463 | 464 | let files = []; 465 | let finalPath = curPath + (curPath.endsWith("/") ? "" : "/") + "cert"; 466 | let isExist = true; 467 | try { 468 | fs.statSync(finalPath); 469 | } catch (e) { 470 | // stats 失败 Error: ENOENT: no such file or directory, stat '/etc/nginx/cert' 471 | // 文件不存在,创建该目录 472 | isExist = false; 473 | } 474 | 475 | try { 476 | !isExist && fs.mkdirSync(finalPath); 477 | files = fs.readdirSync(finalPath); 478 | } catch (e) { 479 | ctx.body = { 480 | code: -3, 481 | msg: e.message, 482 | }; 483 | return; 484 | } 485 | 486 | let result = []; 487 | // files [ 'args.json', 'temp.sh', 'test.sh' ] 488 | let filesFilter = files.filter((item) => { 489 | // if ([].includes(item)) { 490 | // return false; 491 | // } 492 | if (item.startsWith(".")) { 493 | return false; 494 | } 495 | return true; 496 | }); 497 | console.log(filesFilter); 498 | 499 | filesFilter.forEach((filePath) => { 500 | console.log(`'${filePath}'`); 501 | let info = { name: filePath, content: "", desc: "" }; 502 | const content = fs.statSync(`${finalPath}/${filePath}`); 503 | info.content = content; 504 | result.push(info); 505 | }); 506 | ctx.body = { 507 | code: 0, 508 | data: result, 509 | msg: "成功", 510 | }; 511 | }); 512 | 513 | const multer = require("@koa/multer"); 514 | // 文件上传处理 515 | // 前端 append 文件时使用的是 image 字段 516 | let singleFileConfig = multer().single("image"); 517 | let multipleFilesConfig = multer().fields([ 518 | { 519 | name: "image", 520 | maxCount: 5, 521 | }, 522 | ]); 523 | let isMultiple = true; 524 | let fileConfig = isMultiple ? multipleFilesConfig : singleFileConfig; 525 | router.post("/upload", fileConfig, async (ctx) => { 526 | // 文件外的其他 FormData数据 { param1: 'abc' } 527 | console.log("ctx.request.body", ctx.request.body); 528 | console.log("ctx.files", ctx.files); // 多文件,返回 { 字段1: [file数组], 字段2: [file数组] } 529 | console.log("ctx.file", ctx.file); // 单文件,返回 file 对象 530 | let { curPath } = ctx.request.body; 531 | let finalPath = curPath + (curPath.endsWith("/") ? "" : "/"); 532 | 533 | // 如果是单文件取文件内容,如果是多文件,取第一个文件,前端字段传的 image 534 | // 在服务端本地创建文件 535 | try { 536 | if (isMultiple) { 537 | let files = ctx.files["image"]; 538 | files.forEach((item) => { 539 | let { originalname, buffer } = item; 540 | fs.writeFileSync(finalPath + originalname, buffer); 541 | }); 542 | } else { 543 | let { originalname, buffer } = ctx.file; 544 | fs.writeFileSync(finalPath + originalname, buffer); 545 | } 546 | ctx.body = { 547 | code: 0, 548 | msg: "成功", 549 | data: ctx.request.body, 550 | }; 551 | } catch (e) { 552 | ctx.body = { 553 | code: -4, 554 | msg: e.message, 555 | }; 556 | } 557 | // { 558 | // fieldname: 'image', 559 | // originalname: '截屏2020-12-10 下午8.01.44.png', 560 | // encoding: '7bit', 561 | // mimetype: 'image/png', 562 | // buffer: , 563 | // size: 90185 564 | // } 565 | }); 566 | 567 | app.use(new KoaStatic(path.resolve(__dirname, "../frontend"))); 568 | app.use(router.routes()).use(router.allowedMethods()); 569 | server.listen(args.port, () => logger.info(`服务监听 ${args.port} 端口`)); 570 | -------------------------------------------------------------------------------- /server/utils/logger.js: -------------------------------------------------------------------------------- 1 | const log4js = require("log4js"); 2 | const logger = log4js.getLogger(); 3 | logger.level = "debug"; 4 | 5 | module.exports = logger; 6 | -------------------------------------------------------------------------------- /server/utils/runCmd.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const logger = require("./logger"); 3 | const { spawn } = require('child_process'); 4 | 5 | let timeoutTimer = undefined; 6 | 7 | // 使用子进程执行命令 8 | function runCmd(cmd, args, callback, socketIo, msgTag = "common-msg", timeoutMinute = 2) { 9 | const child = spawn(cmd, args); // sh xxx.sh 10 | socketIo && socketIo.emit(msgTag, `[system] runCmd: ${args[0]}, ${msgTag}`); 11 | socketIo && socketIo.emit(msgTag, `[system] 超时限制:${timeoutMinute} 分钟;`); 12 | let resp = ""; 13 | // let resp = "当前执行路径:" + process.cwd() + "\n"; 14 | // logger.info(resp); 15 | // socketIo && socketIo.emit(msgTag, resp); 16 | // let shellCmd = cmd + " " + args + "\n"; 17 | let shellText = args[0].includes(".sh") 18 | ? fs.readFileSync(args[0] || "").toString() 19 | : ""; 20 | // socketIo && socketIo.emit(msgTag, `开始执行脚本: ${shellCmd}`); 21 | socketIo && socketIo.emit(msgTag, `--------------`); 22 | socketIo && socketIo.emit(msgTag, shellText); 23 | socketIo && socketIo.emit(msgTag, `--------------`); 24 | socketIo && 25 | socketIo.emit( 26 | msgTag, 27 | `>>> [system] child pid ${child.pid}, 正在运行中....` 28 | ); 29 | let startTime = +new Date(); 30 | let dataFunc = (buffer) => { 31 | if (child.killed) { 32 | // 如果已结束 33 | callback("运行超时,已停止", "isError"); 34 | timeoutTimer && clearTimeout(timeoutTimer); 35 | socketIo && socketIo.emit(msgTag, `[system] ${child.pid} child.killed, 结束`); 36 | // fix 进程被 kill 后,还在不断接收数据问题(使用 pm2 log 测试得出该结论) 37 | child.stdout.off("data", dataFunc); 38 | return; 39 | } 40 | let info = buffer.toString(); 41 | info = `${new Date().toLocaleString()}: ${info}`; 42 | resp += info; 43 | logger.info(info); 44 | socketIo && socketIo.emit(msgTag, info); 45 | // console.log(child); 46 | // log 较多时,怎么实时将消息通过接口返给前端,只能是 socket ? 47 | // 除了 socket 怎么将 log 数据一点点通过接口传给前端 48 | }; 49 | child.stdout.on("data", dataFunc); 50 | child.stdout.on("end", function () { 51 | console.log(">>stdout end"); 52 | callback(resp); 53 | timeoutTimer && clearTimeout(timeoutTimer); 54 | // socketIo && socketIo.emit(msgTag, `[system] child stdout end`); 55 | }); 56 | 57 | // shell 脚本执行错误信息也返回 58 | // let errorMsg = ""; // 错误信息 end、正常信息 end 可能有先后,统一成一个信息 59 | child.stderr.on("data", (buffer) => { 60 | let info = buffer.toString(); 61 | info = `${new Date().toLocaleString()}: ${info}`; 62 | resp += info; 63 | logger.info(info); 64 | socketIo && socketIo.emit(msgTag, info); 65 | }); 66 | child.stderr.on("end", function () { 67 | console.log(">>err end"); 68 | callback(resp); 69 | timeoutTimer && clearTimeout(timeoutTimer); 70 | // socketIo && socketIo.emit(msgTag, `[system] child stderr end`); 71 | }); 72 | 73 | child.on("close", (code) => { 74 | console.log(">>close", code); 75 | if (code !== 0) { 76 | // let log = `[system] child 子进程非正常退出,ps process exited with code ${code}`; 77 | // socketIo && socketIo.emit(msgTag, log); 78 | } 79 | let useTime = (+new Date() - startTime) / 1000; 80 | socketIo && 81 | socketIo.emit( 82 | msgTag, 83 | `>>> [system] ${child.pid} child close 完成运行! 耗时:${useTime}s` 84 | ); 85 | }); 86 | 87 | const TIME_OUT_SEC = 1000 * 60 * timeoutMinute; 88 | timeoutTimer = setTimeout(() => { 89 | let log = `>>> [system] ${child.pid} 执行超时 ${TIME_OUT_SEC / 1000}s,结束执行!`; 90 | socketIo && socketIo.emit(msgTag, log); 91 | child.kill(); 92 | }, TIME_OUT_SEC); 93 | } 94 | 95 | module.exports = runCmd; 96 | -------------------------------------------------------------------------------- /servertemp.sh: -------------------------------------------------------------------------------- 1 | ls 2 | pwd -------------------------------------------------------------------------------- /v1.0.0.md: -------------------------------------------------------------------------------- 1 | # v1.0.0 TODO 2 | 3 | ## v0.3.2 的缺点 4 | 5 | - 在一个 linux 服务器只能运行在一个项目下,多项目会有问题,仅支持执行当前目录下 deploy-master.sh 脚本 6 | - 不支持修改服务器 nginx 配置 7 | - 不支持实时修改 shell 脚本。需要先在项目中修改在提交 git,服务器拉取再次执行才能生效 8 | 9 | ## TODO 10 | 11 | - 为了保证端口不被占用,先 pm2 delete 服务,但如果之前就没有,pm2 delete 会报错 12 | 13 | - 支持多项目部署,与多个项目保持独立,独立于一个文件夹 14 | - 支持动态修改 shell 脚本,指定执行的 shell 文件,增删查改 15 | 16 | - 支持 nginx 配置文件的增删查改 17 | - shell 取消执行 18 | 19 | zuodeploy start -y 支持,不需要按回车就可以更新服务 20 | 21 | 当前linux面板版本更新后,怎么自己更新自己 22 | 23 | 剩余功能 24 | 25 | - nginx多项目独立配置文件:新增、修改、删除 [ok] 26 | - https证书管理 27 | 28 | - 登录态丢失之后 window.location.reload() 29 | 30 | - nginx https 证书配置 31 | 32 | - EACCES: permission denied, open '/etc/nginx/cert/ex.zuoguoqing.com_bundle.crt 33 | - sudo chmod 777 /etc/nginx/cert 34 | // chmod 帮助文档:man chmod 35 | --------------------------------------------------------------------------------