├── server ├── .gitignore ├── utils │ ├── messages.js │ └── users.js ├── nginx.conf ├── package.json ├── server.js └── package-lock.json ├── client ├── README.md ├── index.html ├── chat.html ├── js │ └── main.js └── css │ └── style.css ├── screenshots ├── archi.png ├── edge.PNG └── chrome.PNG └── README.md /server/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | nginx -------------------------------------------------------------------------------- /client/README.md: -------------------------------------------------------------------------------- 1 | ```bash 2 | http-server . --cors --port=5500 3 | ``` -------------------------------------------------------------------------------- /screenshots/archi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmgchess/socketio-redis-pubsub-demo/HEAD/screenshots/archi.png -------------------------------------------------------------------------------- /screenshots/edge.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmgchess/socketio-redis-pubsub-demo/HEAD/screenshots/edge.PNG -------------------------------------------------------------------------------- /screenshots/chrome.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmgchess/socketio-redis-pubsub-demo/HEAD/screenshots/chrome.PNG -------------------------------------------------------------------------------- /server/utils/messages.js: -------------------------------------------------------------------------------- 1 | const moment = require('moment') 2 | 3 | function formatMessage(username, text,port) { 4 | return { 5 | username: username, 6 | text: port +': '+text, 7 | time: moment().format('h:mm a') 8 | } 9 | } 10 | 11 | module.exports = formatMessage; -------------------------------------------------------------------------------- /server/nginx.conf: -------------------------------------------------------------------------------- 1 | http { 2 | 3 | upstream backend { 4 | hash '$remote_addr $cookie_zzz $http_user_agent'; 5 | server 127.0.0.1:1212; 6 | server 127.0.0.1:1213; 7 | } 8 | 9 | server { 10 | listen 80; 11 | root E:\\socket\\server; 12 | 13 | location / { 14 | proxy_pass http://backend; 15 | } 16 | } 17 | } 18 | 19 | events { } -------------------------------------------------------------------------------- /server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "socket", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "server.js", 6 | "scripts": { 7 | "start": "node server", 8 | "dev": "nodemon server", 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "@socket.io/redis-adapter": "^7.2.0", 15 | "express": "^4.18.1", 16 | "moment": "^2.29.4", 17 | "redis": "^4.2.0", 18 | "socket.io": "^4.5.1" 19 | }, 20 | "devDependencies": { 21 | "nodemon": "^2.0.19" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /server/utils/users.js: -------------------------------------------------------------------------------- 1 | const users = []; 2 | 3 | //join users to chat 4 | 5 | function userJoin(id, username, room) { 6 | const user = { id, username, room }; 7 | users.push(user); 8 | return user; 9 | } 10 | 11 | // get current user 12 | 13 | function getCurrentUser(id) { 14 | return users.find((user) => id === user.id); 15 | } 16 | 17 | // user leaves chat 18 | function userLeave(id){ 19 | const index = users.findIndex((user) => user.id === id); 20 | 21 | if(index !== -1){ 22 | return users.splice(index,1)[0]; 23 | } 24 | } 25 | 26 | //get room users 27 | function getRoomUsers(room){ 28 | return users.filter((user) => user.room === room); 29 | } 30 | 31 | 32 | module.exports = { 33 | getCurrentUser, 34 | userJoin, 35 | userLeave, 36 | getRoomUsers 37 | }; 38 | -------------------------------------------------------------------------------- /client/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 13 | 14 | 15 | ChatCord App 16 | 17 | 18 |
19 |
20 |

ChatCord

21 |
22 |
23 |
24 |
25 | 26 | 33 |
34 |
35 | 36 | 44 |
45 | 46 |
47 |
48 |
49 | 50 | 51 | -------------------------------------------------------------------------------- /client/chat.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | ChatCord App 9 | 10 | 11 |
12 |
13 |

ChatCord

14 | Leave Room 15 |
16 |
17 |
18 |

Room Name:

19 |

20 |

Users

21 |
    22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | 36 | 37 |
38 |
39 |
40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /client/js/main.js: -------------------------------------------------------------------------------- 1 | const chatForm = document.getElementById('chat-form'); 2 | const chatMessages = document.querySelector('.chat-messages'); 3 | const roomName = document.getElementById('room-name'); 4 | const userList = document.getElementById('users'); 5 | 6 | //Get username and room from url 7 | const { username, room } = Qs.parse(location.search, { 8 | ignoreQueryPrefix: true, 9 | }); 10 | 11 | const socket = io('http://localhost:80'); 12 | // const socket = io(); 13 | 14 | socket.emit('joinRoom', { username, room }); 15 | 16 | //get room and users 17 | socket.on('roomUsers', ({ room, users }) => { 18 | outputRoomName(room); 19 | outputUsers(users); 20 | }); 21 | 22 | //message from server 23 | socket.on('message', ({ username, text, time }) => { 24 | console.log({ username, text, time }); 25 | outputMessage(username, text, time); 26 | 27 | //scroll down 28 | chatMessages.scrollTop = chatMessages.scrollHeight; 29 | }); 30 | 31 | //Message-submit 32 | chatForm.addEventListener('submit', (e) => { 33 | e.preventDefault(); 34 | 35 | ///Get message text 36 | const msg = e.target.elements.msg.value; 37 | 38 | //Emit message to server 39 | socket.emit('chatMessage', msg); 40 | 41 | //clear input 42 | e.target.elements.msg.value = ''; 43 | e.target.elements.msg.focus(); 44 | }); 45 | 46 | //output msg to dom 47 | function outputMessage(username, text, time) { 48 | const div = document.createElement('div'); 49 | div.classList.add('message'); 50 | div.innerHTML = `

${username} ${time}

51 |

52 | ${text} 53 |

`; 54 | document.querySelector('.chat-messages').appendChild(div); 55 | } 56 | 57 | //add room name to dom 58 | function outputRoomName(room) { 59 | roomName.innerText = room; 60 | } 61 | 62 | //add users to dom 63 | function outputUsers(users) { 64 | userList.innerHTML = ` 65 | ${users.map((user) => `
  • ${user.username}
  • `).join('')} 66 | `; 67 | } 68 | -------------------------------------------------------------------------------- /server/server.js: -------------------------------------------------------------------------------- 1 | const http = require('http'); 2 | const express = require('express'); 3 | 4 | const { createClient } = require('redis'); 5 | const { createAdapter } = require('@socket.io/redis-adapter'); 6 | const socketio = require('socket.io'); 7 | 8 | const formatMessage = require('./utils/messages'); 9 | const { 10 | userJoin, 11 | getCurrentUser, 12 | userLeave, 13 | getRoomUsers, 14 | } = require('./utils/users'); 15 | 16 | const PORT = process.env.PORT; 17 | 18 | const app = express(); 19 | const server = http.createServer(app); 20 | 21 | //https://socket.io/docs/v4/using-multiple-nodes/#enabling-sticky-session 22 | const io = socketio(server, { 23 | cors: { 24 | origin: ['http://127.0.0.1:5500'], 25 | methods: ['GET', 'POST'], 26 | transports: ['websocket', 'polling'], 27 | credentials: true, 28 | }, 29 | }); 30 | 31 | const url = 'redis://127.0.0.1:6379'; 32 | pubClient = createClient({ url }); 33 | subClient = pubClient.duplicate(); 34 | 35 | //https://socket.io/docs/v4/redis-adapter/#usage 36 | const initPubSub = async () => { 37 | await Promise.all([pubClient.connect(), subClient.connect()]); 38 | io.adapter(createAdapter(pubClient, subClient)); 39 | }; 40 | 41 | initPubSub(); 42 | 43 | const BOT_NAME = 'Chatcord-BOT'; 44 | 45 | //Run when client connects 46 | io.on('connection', (socket) => { 47 | console.log(`connected to ${PORT}`); 48 | socket.on('joinRoom', ({ username, room }) => { 49 | console.log(`connected to room ${PORT}`); 50 | const user = userJoin(socket.id, username, room); 51 | 52 | socket.join(user.room); 53 | 54 | //Welcome current user 55 | socket.emit( 56 | 'message', 57 | formatMessage(BOT_NAME, 'Welcome to chatcord!', PORT) 58 | ); 59 | 60 | //broadcase when a user connects 61 | socket.broadcast 62 | .to(user.room) 63 | .emit( 64 | 'message', 65 | formatMessage(BOT_NAME, `${user.username} has joined the chat`, PORT) 66 | ); 67 | 68 | //send users and room info 69 | io.to(user.room).emit('roomUsers', { 70 | room: user.room, 71 | users: getRoomUsers(user.room), 72 | }); 73 | }); 74 | 75 | //Listen for chatMessage 76 | socket.on('chatMessage', (msg) => { 77 | const user = getCurrentUser(socket.id); 78 | console.log(`Chat Message: ${msg} from ${user.username} from PORT ${PORT}`); 79 | io.to(user.room).emit('message', formatMessage(user.username, msg, PORT)); 80 | }); 81 | 82 | socket.on('disconnect', () => { 83 | const user = userLeave(socket.id); 84 | if (user) { 85 | io.to(user.room).emit( 86 | 'message', 87 | formatMessage(BOT_NAME, `${user.username} has left the chat`, PORT) 88 | ); 89 | 90 | //send users and room info 91 | io.to(user.room).emit('roomUsers', { 92 | room: user.room, 93 | users: getRoomUsers(user.room), 94 | }); 95 | } 96 | }); 97 | }); 98 | 99 | server.listen(PORT, () => console.log(`Server running on port ${PORT}`)); 100 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | **Prerequisites** 3 | 4 | - [Realtime Chat With Users & Rooms - Socket.io, Node & Express](https://www.youtube.com/watch?v=jD7FnbI76Hg "Realtime Chat With Users & Rooms - Socket.io, Node & Express") 5 | - [REPO - bradtraversy/chatcord](https://github.com/bradtraversy/chatcord) 6 | 7 | **Additional helpful resources** 8 | 9 | - [Scaling Websockets with Redis, HAProxy and Node JS - High-availability Group Chat Application](https://www.youtube.com/watch?v=gzIcGhJC8hA "Scaling Websockets with Redis, HAProxy and Node JS - High-availability Group Chat Application") 10 | - [Load Balancing NodeJS applications using NginX](https://www.youtube.com/watch?v=eYXXEWVTZpk "Load Balancing NodeJS applications using NginX") 11 | - [Socket.IO Docs - Using multiple nodes](https://socket.io/docs/v4/using-multiple-nodes/) 12 | - [Socket.IO Docs - Adapters](https://socket.io/docs/v4/adapter/) 13 | - [Socket.IO Docs - Redis adapter](https://socket.io/docs/v4/redis-adapter/) 14 | 15 | **Additional Tools** 16 | 17 | - [nginx](http://nginx.org/en/download.html) 18 | - [Redis](https://redis.io/download/) 19 | - [Node.js](https://nodejs.org/en/download/) v14+ 20 | - [http-server](https://www.npmjs.com/package/http-server) 21 | 22 | [Here](https://kasunprageethdissanayake.medium.com/installing-redis-x64-3-2-100-on-windows-and-running-redis-server-94db3a98ae3d) is a MSI installer I found for Redis. 23 | 24 | **Setup** 25 | 26 | 1. Clone repository 27 | 2. cd into `server` and `npm install` 28 | 29 | 30 | **Nginx conf** 31 | 32 | ```bash 33 | http { 34 | 35 | upstream backend { 36 | hash '$remote_addr $cookie_zzz $http_user_agent'; 37 | server 127.0.0.1:1212; 38 | server 127.0.0.1:1213; 39 | } 40 | 41 | server { 42 | listen 80; 43 | root E:\\socket\\server; 44 | 45 | location / { 46 | proxy_pass http://backend; 47 | } 48 | } 49 | } 50 | 51 | events { } 52 | 53 | ``` 54 | https://stackoverflow.com/questions/59124543/nginx-not-loadbalancing-in-case-of-ip-hash 55 | 56 | **Running client** 57 | 1. cd into`client` 58 | 2. run `http-server . --cors --port=5500` 59 | 60 | **Running server** 61 | 62 | 1. cd into `server` and open 2 terminals for the same directory 63 | 2. Set 2 different ports ( ex: `export PORT=1212` in one terminal and `export PORT=1213` in the other) 64 | 3. Start nginx with the given configuration 65 | 4. `npm start` the server on both terminals 66 | 67 | Now Server 1 will be started on `PORT=1212` and Server 2 on `PORT=1213` and the Client on `PORT=5500`. Two servers will be load balanced using nginx on `PORT=80` so the client will be directed to either Server 1 or 2 when it hits Port 80. Hash based load balancing is enabled (to achieve stickiness) since nginx open source doesn't allow cookie based load balancing. Go to http://127.0.0.1:5500/ with 2 browsers (Edge and Chrome for example) then the 2 instances will be connected to Server 1 and 2 respectively. 68 | Redis will act as a [PubSub](https://redis.io/docs/manual/pubsub/) mechanism and is enabled using [Socket.IO Redis Adapter](https://socket.io/docs/v4/redis-adapter/). 69 | **NOTE: Redis adapter will not store anything, it will only do PubSub.** 70 | If you want you can store data in Redis as well. 71 | 72 | 73 | ![Architecture](/screenshots/archi.png?raw=true "Architecture") 74 | 75 | ![User logged in Edge Browser](/screenshots/edge.PNG?raw=true "User logged in Edge Browser") 76 | ![User logged in Chrome Browser](/screenshots/chrome.PNG?raw=true "User logged in Chrome Browser") 77 | -------------------------------------------------------------------------------- /client/css/style.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css?family=Roboto&display=swap'); 2 | 3 | :root { 4 | --dark-color-a: #667aff; 5 | --dark-color-b: #7386ff; 6 | --light-color: #e6e9ff; 7 | --success-color: #5cb85c; 8 | --error-color: #d9534f; 9 | } 10 | 11 | * { 12 | box-sizing: border-box; 13 | margin: 0; 14 | padding: 0; 15 | } 16 | 17 | body { 18 | font-family: 'Roboto', sans-serif; 19 | font-size: 16px; 20 | background: var(--light-color); 21 | margin: 20px; 22 | } 23 | 24 | ul { 25 | list-style: none; 26 | } 27 | 28 | a { 29 | text-decoration: none; 30 | } 31 | 32 | .btn { 33 | cursor: pointer; 34 | padding: 5px 15px; 35 | background: var(--light-color); 36 | color: var(--dark-color-a); 37 | border: 0; 38 | font-size: 17px; 39 | } 40 | 41 | /* Chat Page */ 42 | 43 | .chat-container { 44 | max-width: 1100px; 45 | background: #fff; 46 | margin: 30px auto; 47 | overflow: hidden; 48 | } 49 | 50 | .chat-header { 51 | background: var(--dark-color-a); 52 | color: #fff; 53 | border-top-left-radius: 5px; 54 | border-top-right-radius: 5px; 55 | padding: 15px; 56 | display: flex; 57 | align-items: center; 58 | justify-content: space-between; 59 | } 60 | 61 | .chat-main { 62 | display: grid; 63 | grid-template-columns: 1fr 3fr; 64 | } 65 | 66 | .chat-sidebar { 67 | background: var(--dark-color-b); 68 | color: #fff; 69 | padding: 20px 20px 60px; 70 | overflow-y: scroll; 71 | } 72 | 73 | .chat-sidebar h2 { 74 | font-size: 20px; 75 | background: rgba(0, 0, 0, 0.1); 76 | padding: 10px; 77 | margin-bottom: 20px; 78 | } 79 | 80 | .chat-sidebar h3 { 81 | margin-bottom: 15px; 82 | } 83 | 84 | .chat-sidebar ul li { 85 | padding: 10px 0; 86 | } 87 | 88 | .chat-messages { 89 | padding: 30px; 90 | max-height: 500px; 91 | overflow-y: scroll; 92 | } 93 | 94 | .chat-messages .message { 95 | padding: 10px; 96 | margin-bottom: 15px; 97 | background-color: var(--light-color); 98 | border-radius: 5px; 99 | } 100 | 101 | .chat-messages .message .meta { 102 | font-size: 15px; 103 | font-weight: bold; 104 | color: var(--dark-color-b); 105 | opacity: 0.7; 106 | margin-bottom: 7px; 107 | } 108 | 109 | .chat-messages .message .meta span { 110 | color: #777; 111 | } 112 | 113 | .chat-form-container { 114 | padding: 20px 30px; 115 | background-color: var(--dark-color-a); 116 | } 117 | 118 | .chat-form-container form { 119 | display: flex; 120 | } 121 | 122 | .chat-form-container input[type='text'] { 123 | font-size: 16px; 124 | padding: 5px; 125 | height: 40px; 126 | flex: 1; 127 | } 128 | 129 | /* Join Page */ 130 | .join-container { 131 | max-width: 500px; 132 | margin: 80px auto; 133 | color: #fff; 134 | } 135 | 136 | .join-header { 137 | text-align: center; 138 | padding: 20px; 139 | background: var(--dark-color-a); 140 | border-top-left-radius: 5px; 141 | border-top-right-radius: 5px; 142 | } 143 | 144 | .join-main { 145 | padding: 30px 40px; 146 | background: var(--dark-color-b); 147 | } 148 | 149 | .join-main p { 150 | margin-bottom: 20px; 151 | } 152 | 153 | .join-main .form-control { 154 | margin-bottom: 20px; 155 | } 156 | 157 | .join-main label { 158 | display: block; 159 | margin-bottom: 5px; 160 | } 161 | 162 | .join-main input[type='text'] { 163 | font-size: 16px; 164 | padding: 5px; 165 | height: 40px; 166 | width: 100%; 167 | } 168 | 169 | .join-main select { 170 | font-size: 16px; 171 | padding: 5px; 172 | height: 40px; 173 | width: 100%; 174 | } 175 | 176 | .join-main .btn { 177 | margin-top: 20px; 178 | width: 100%; 179 | } 180 | 181 | @media (max-width: 700px) { 182 | .chat-main { 183 | display: block; 184 | } 185 | 186 | .chat-sidebar { 187 | display: none; 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /server/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "socket", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@redis/bloom": { 8 | "version": "1.0.2", 9 | "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.0.2.tgz", 10 | "integrity": "sha512-EBw7Ag1hPgFzdznK2PBblc1kdlj5B5Cw3XwI9/oG7tSn85/HKy3X9xHy/8tm/eNXJYHLXHJL/pkwBpFMVVefkw==" 11 | }, 12 | "@redis/client": { 13 | "version": "1.2.0", 14 | "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.2.0.tgz", 15 | "integrity": "sha512-a8Nlw5fv2EIAFJxTDSSDVUT7yfBGpZO96ybZXzQpgkyLg/dxtQ1uiwTc0EGfzg1mrPjZokeBSEGTbGXekqTNOg==", 16 | "requires": { 17 | "cluster-key-slot": "1.1.0", 18 | "generic-pool": "3.8.2", 19 | "yallist": "4.0.0" 20 | } 21 | }, 22 | "@redis/graph": { 23 | "version": "1.0.1", 24 | "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.0.1.tgz", 25 | "integrity": "sha512-oDE4myMCJOCVKYMygEMWuriBgqlS5FqdWerikMoJxzmmTUErnTRRgmIDa2VcgytACZMFqpAOWDzops4DOlnkfQ==" 26 | }, 27 | "@redis/json": { 28 | "version": "1.0.3", 29 | "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.3.tgz", 30 | "integrity": "sha512-4X0Qv0BzD9Zlb0edkUoau5c1bInWSICqXAGrpwEltkncUwcxJIGEcVryZhLgb0p/3PkKaLIWkjhHRtLe9yiA7Q==" 31 | }, 32 | "@redis/search": { 33 | "version": "1.0.6", 34 | "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.0.6.tgz", 35 | "integrity": "sha512-pP+ZQRis5P21SD6fjyCeLcQdps+LuTzp2wdUbzxEmNhleighDDTD5ck8+cYof+WLec4csZX7ks+BuoMw0RaZrA==" 36 | }, 37 | "@redis/time-series": { 38 | "version": "1.0.3", 39 | "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.3.tgz", 40 | "integrity": "sha512-OFp0q4SGrTH0Mruf6oFsHGea58u8vS/iI5+NpYdicaM+7BgqBZH8FFvNZ8rYYLrUO/QRqMq72NpXmxLVNcdmjA==" 41 | }, 42 | "@socket.io/redis-adapter": { 43 | "version": "7.2.0", 44 | "resolved": "https://registry.npmjs.org/@socket.io/redis-adapter/-/redis-adapter-7.2.0.tgz", 45 | "integrity": "sha512-/r6oF6Myz0K9uatB/pfCi0BhKg/KRMh1OokrqcjlNz6aq40WiXdFLRbHJQuwGHq/KvB+D6141K+IynbVxZGvhw==", 46 | "requires": { 47 | "debug": "~4.3.1", 48 | "notepack.io": "~2.2.0", 49 | "socket.io-adapter": "^2.4.0", 50 | "uid2": "0.0.3" 51 | } 52 | }, 53 | "@types/component-emitter": { 54 | "version": "1.2.11", 55 | "resolved": "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.11.tgz", 56 | "integrity": "sha512-SRXjM+tfsSlA9VuG8hGO2nft2p8zjXCK1VcC6N4NXbBbYbSia9kzCChYQajIjzIqOOOuh5Ock6MmV2oux4jDZQ==" 57 | }, 58 | "@types/cookie": { 59 | "version": "0.4.1", 60 | "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", 61 | "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" 62 | }, 63 | "@types/cors": { 64 | "version": "2.8.12", 65 | "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", 66 | "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==" 67 | }, 68 | "@types/node": { 69 | "version": "18.6.1", 70 | "resolved": "https://registry.npmjs.org/@types/node/-/node-18.6.1.tgz", 71 | "integrity": "sha512-z+2vB6yDt1fNwKOeGbckpmirO+VBDuQqecXkgeIqDlaOtmKn6hPR/viQ8cxCfqLU4fTlvM3+YjM367TukWdxpg==" 72 | }, 73 | "abbrev": { 74 | "version": "1.1.1", 75 | "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", 76 | "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", 77 | "dev": true 78 | }, 79 | "accepts": { 80 | "version": "1.3.8", 81 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", 82 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", 83 | "requires": { 84 | "mime-types": "~2.1.34", 85 | "negotiator": "0.6.3" 86 | } 87 | }, 88 | "anymatch": { 89 | "version": "3.1.2", 90 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", 91 | "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", 92 | "dev": true, 93 | "requires": { 94 | "normalize-path": "^3.0.0", 95 | "picomatch": "^2.0.4" 96 | } 97 | }, 98 | "array-flatten": { 99 | "version": "1.1.1", 100 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 101 | "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" 102 | }, 103 | "balanced-match": { 104 | "version": "1.0.2", 105 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 106 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 107 | "dev": true 108 | }, 109 | "base64id": { 110 | "version": "2.0.0", 111 | "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", 112 | "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==" 113 | }, 114 | "binary-extensions": { 115 | "version": "2.2.0", 116 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", 117 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", 118 | "dev": true 119 | }, 120 | "body-parser": { 121 | "version": "1.20.0", 122 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", 123 | "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", 124 | "requires": { 125 | "bytes": "3.1.2", 126 | "content-type": "~1.0.4", 127 | "debug": "2.6.9", 128 | "depd": "2.0.0", 129 | "destroy": "1.2.0", 130 | "http-errors": "2.0.0", 131 | "iconv-lite": "0.4.24", 132 | "on-finished": "2.4.1", 133 | "qs": "6.10.3", 134 | "raw-body": "2.5.1", 135 | "type-is": "~1.6.18", 136 | "unpipe": "1.0.0" 137 | }, 138 | "dependencies": { 139 | "debug": { 140 | "version": "2.6.9", 141 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 142 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 143 | "requires": { 144 | "ms": "2.0.0" 145 | } 146 | }, 147 | "ms": { 148 | "version": "2.0.0", 149 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 150 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" 151 | } 152 | } 153 | }, 154 | "brace-expansion": { 155 | "version": "1.1.11", 156 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 157 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 158 | "dev": true, 159 | "requires": { 160 | "balanced-match": "^1.0.0", 161 | "concat-map": "0.0.1" 162 | } 163 | }, 164 | "braces": { 165 | "version": "3.0.2", 166 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 167 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 168 | "dev": true, 169 | "requires": { 170 | "fill-range": "^7.0.1" 171 | } 172 | }, 173 | "bytes": { 174 | "version": "3.1.2", 175 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", 176 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" 177 | }, 178 | "call-bind": { 179 | "version": "1.0.2", 180 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", 181 | "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", 182 | "requires": { 183 | "function-bind": "^1.1.1", 184 | "get-intrinsic": "^1.0.2" 185 | } 186 | }, 187 | "chokidar": { 188 | "version": "3.5.3", 189 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", 190 | "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", 191 | "dev": true, 192 | "requires": { 193 | "anymatch": "~3.1.2", 194 | "braces": "~3.0.2", 195 | "fsevents": "~2.3.2", 196 | "glob-parent": "~5.1.2", 197 | "is-binary-path": "~2.1.0", 198 | "is-glob": "~4.0.1", 199 | "normalize-path": "~3.0.0", 200 | "readdirp": "~3.6.0" 201 | } 202 | }, 203 | "cluster-key-slot": { 204 | "version": "1.1.0", 205 | "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz", 206 | "integrity": "sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==" 207 | }, 208 | "component-emitter": { 209 | "version": "1.3.0", 210 | "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", 211 | "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" 212 | }, 213 | "concat-map": { 214 | "version": "0.0.1", 215 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 216 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", 217 | "dev": true 218 | }, 219 | "content-disposition": { 220 | "version": "0.5.4", 221 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", 222 | "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", 223 | "requires": { 224 | "safe-buffer": "5.2.1" 225 | } 226 | }, 227 | "content-type": { 228 | "version": "1.0.4", 229 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 230 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" 231 | }, 232 | "cookie": { 233 | "version": "0.5.0", 234 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", 235 | "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" 236 | }, 237 | "cookie-signature": { 238 | "version": "1.0.6", 239 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 240 | "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" 241 | }, 242 | "cors": { 243 | "version": "2.8.5", 244 | "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", 245 | "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", 246 | "requires": { 247 | "object-assign": "^4", 248 | "vary": "^1" 249 | } 250 | }, 251 | "debug": { 252 | "version": "4.3.4", 253 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 254 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 255 | "requires": { 256 | "ms": "2.1.2" 257 | } 258 | }, 259 | "depd": { 260 | "version": "2.0.0", 261 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", 262 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" 263 | }, 264 | "destroy": { 265 | "version": "1.2.0", 266 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", 267 | "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" 268 | }, 269 | "ee-first": { 270 | "version": "1.1.1", 271 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 272 | "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" 273 | }, 274 | "encodeurl": { 275 | "version": "1.0.2", 276 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 277 | "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" 278 | }, 279 | "engine.io": { 280 | "version": "6.2.0", 281 | "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.0.tgz", 282 | "integrity": "sha512-4KzwW3F3bk+KlzSOY57fj/Jx6LyRQ1nbcyIadehl+AnXjKT7gDO0ORdRi/84ixvMKTym6ZKuxvbzN62HDDU1Lg==", 283 | "requires": { 284 | "@types/cookie": "^0.4.1", 285 | "@types/cors": "^2.8.12", 286 | "@types/node": ">=10.0.0", 287 | "accepts": "~1.3.4", 288 | "base64id": "2.0.0", 289 | "cookie": "~0.4.1", 290 | "cors": "~2.8.5", 291 | "debug": "~4.3.1", 292 | "engine.io-parser": "~5.0.3", 293 | "ws": "~8.2.3" 294 | }, 295 | "dependencies": { 296 | "cookie": { 297 | "version": "0.4.2", 298 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", 299 | "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==" 300 | } 301 | } 302 | }, 303 | "engine.io-parser": { 304 | "version": "5.0.4", 305 | "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz", 306 | "integrity": "sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg==" 307 | }, 308 | "escape-html": { 309 | "version": "1.0.3", 310 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 311 | "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" 312 | }, 313 | "etag": { 314 | "version": "1.8.1", 315 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 316 | "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" 317 | }, 318 | "express": { 319 | "version": "4.18.1", 320 | "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz", 321 | "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==", 322 | "requires": { 323 | "accepts": "~1.3.8", 324 | "array-flatten": "1.1.1", 325 | "body-parser": "1.20.0", 326 | "content-disposition": "0.5.4", 327 | "content-type": "~1.0.4", 328 | "cookie": "0.5.0", 329 | "cookie-signature": "1.0.6", 330 | "debug": "2.6.9", 331 | "depd": "2.0.0", 332 | "encodeurl": "~1.0.2", 333 | "escape-html": "~1.0.3", 334 | "etag": "~1.8.1", 335 | "finalhandler": "1.2.0", 336 | "fresh": "0.5.2", 337 | "http-errors": "2.0.0", 338 | "merge-descriptors": "1.0.1", 339 | "methods": "~1.1.2", 340 | "on-finished": "2.4.1", 341 | "parseurl": "~1.3.3", 342 | "path-to-regexp": "0.1.7", 343 | "proxy-addr": "~2.0.7", 344 | "qs": "6.10.3", 345 | "range-parser": "~1.2.1", 346 | "safe-buffer": "5.2.1", 347 | "send": "0.18.0", 348 | "serve-static": "1.15.0", 349 | "setprototypeof": "1.2.0", 350 | "statuses": "2.0.1", 351 | "type-is": "~1.6.18", 352 | "utils-merge": "1.0.1", 353 | "vary": "~1.1.2" 354 | }, 355 | "dependencies": { 356 | "debug": { 357 | "version": "2.6.9", 358 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 359 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 360 | "requires": { 361 | "ms": "2.0.0" 362 | } 363 | }, 364 | "ms": { 365 | "version": "2.0.0", 366 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 367 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" 368 | } 369 | } 370 | }, 371 | "fill-range": { 372 | "version": "7.0.1", 373 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 374 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 375 | "dev": true, 376 | "requires": { 377 | "to-regex-range": "^5.0.1" 378 | } 379 | }, 380 | "finalhandler": { 381 | "version": "1.2.0", 382 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", 383 | "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", 384 | "requires": { 385 | "debug": "2.6.9", 386 | "encodeurl": "~1.0.2", 387 | "escape-html": "~1.0.3", 388 | "on-finished": "2.4.1", 389 | "parseurl": "~1.3.3", 390 | "statuses": "2.0.1", 391 | "unpipe": "~1.0.0" 392 | }, 393 | "dependencies": { 394 | "debug": { 395 | "version": "2.6.9", 396 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 397 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 398 | "requires": { 399 | "ms": "2.0.0" 400 | } 401 | }, 402 | "ms": { 403 | "version": "2.0.0", 404 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 405 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" 406 | } 407 | } 408 | }, 409 | "forwarded": { 410 | "version": "0.2.0", 411 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", 412 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" 413 | }, 414 | "fresh": { 415 | "version": "0.5.2", 416 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 417 | "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" 418 | }, 419 | "fsevents": { 420 | "version": "2.3.2", 421 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 422 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 423 | "dev": true, 424 | "optional": true 425 | }, 426 | "function-bind": { 427 | "version": "1.1.1", 428 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 429 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" 430 | }, 431 | "generic-pool": { 432 | "version": "3.8.2", 433 | "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.8.2.tgz", 434 | "integrity": "sha512-nGToKy6p3PAbYQ7p1UlWl6vSPwfwU6TMSWK7TTu+WUY4ZjyZQGniGGt2oNVvyNSpyZYSB43zMXVLcBm08MTMkg==" 435 | }, 436 | "get-intrinsic": { 437 | "version": "1.1.2", 438 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", 439 | "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", 440 | "requires": { 441 | "function-bind": "^1.1.1", 442 | "has": "^1.0.3", 443 | "has-symbols": "^1.0.3" 444 | } 445 | }, 446 | "glob-parent": { 447 | "version": "5.1.2", 448 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 449 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 450 | "dev": true, 451 | "requires": { 452 | "is-glob": "^4.0.1" 453 | } 454 | }, 455 | "has": { 456 | "version": "1.0.3", 457 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 458 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 459 | "requires": { 460 | "function-bind": "^1.1.1" 461 | } 462 | }, 463 | "has-flag": { 464 | "version": "3.0.0", 465 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 466 | "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", 467 | "dev": true 468 | }, 469 | "has-symbols": { 470 | "version": "1.0.3", 471 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", 472 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" 473 | }, 474 | "http-errors": { 475 | "version": "2.0.0", 476 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", 477 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", 478 | "requires": { 479 | "depd": "2.0.0", 480 | "inherits": "2.0.4", 481 | "setprototypeof": "1.2.0", 482 | "statuses": "2.0.1", 483 | "toidentifier": "1.0.1" 484 | } 485 | }, 486 | "iconv-lite": { 487 | "version": "0.4.24", 488 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 489 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 490 | "requires": { 491 | "safer-buffer": ">= 2.1.2 < 3" 492 | } 493 | }, 494 | "ignore-by-default": { 495 | "version": "1.0.1", 496 | "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", 497 | "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", 498 | "dev": true 499 | }, 500 | "inherits": { 501 | "version": "2.0.4", 502 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 503 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 504 | }, 505 | "ipaddr.js": { 506 | "version": "1.9.1", 507 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 508 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" 509 | }, 510 | "is-binary-path": { 511 | "version": "2.1.0", 512 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 513 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 514 | "dev": true, 515 | "requires": { 516 | "binary-extensions": "^2.0.0" 517 | } 518 | }, 519 | "is-extglob": { 520 | "version": "2.1.1", 521 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 522 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 523 | "dev": true 524 | }, 525 | "is-glob": { 526 | "version": "4.0.3", 527 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 528 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 529 | "dev": true, 530 | "requires": { 531 | "is-extglob": "^2.1.1" 532 | } 533 | }, 534 | "is-number": { 535 | "version": "7.0.0", 536 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 537 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 538 | "dev": true 539 | }, 540 | "media-typer": { 541 | "version": "0.3.0", 542 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 543 | "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" 544 | }, 545 | "merge-descriptors": { 546 | "version": "1.0.1", 547 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 548 | "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" 549 | }, 550 | "methods": { 551 | "version": "1.1.2", 552 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 553 | "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" 554 | }, 555 | "mime": { 556 | "version": "1.6.0", 557 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 558 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" 559 | }, 560 | "mime-db": { 561 | "version": "1.52.0", 562 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 563 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" 564 | }, 565 | "mime-types": { 566 | "version": "2.1.35", 567 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 568 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 569 | "requires": { 570 | "mime-db": "1.52.0" 571 | } 572 | }, 573 | "minimatch": { 574 | "version": "3.1.2", 575 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 576 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 577 | "dev": true, 578 | "requires": { 579 | "brace-expansion": "^1.1.7" 580 | } 581 | }, 582 | "moment": { 583 | "version": "2.29.4", 584 | "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", 585 | "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" 586 | }, 587 | "ms": { 588 | "version": "2.1.2", 589 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 590 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 591 | }, 592 | "negotiator": { 593 | "version": "0.6.3", 594 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", 595 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" 596 | }, 597 | "nodemon": { 598 | "version": "2.0.19", 599 | "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.19.tgz", 600 | "integrity": "sha512-4pv1f2bMDj0Eeg/MhGqxrtveeQ5/G/UVe9iO6uTZzjnRluSA4PVWf8CW99LUPwGB3eNIA7zUFoP77YuI7hOc0A==", 601 | "dev": true, 602 | "requires": { 603 | "chokidar": "^3.5.2", 604 | "debug": "^3.2.7", 605 | "ignore-by-default": "^1.0.1", 606 | "minimatch": "^3.0.4", 607 | "pstree.remy": "^1.1.8", 608 | "semver": "^5.7.1", 609 | "simple-update-notifier": "^1.0.7", 610 | "supports-color": "^5.5.0", 611 | "touch": "^3.1.0", 612 | "undefsafe": "^2.0.5" 613 | }, 614 | "dependencies": { 615 | "debug": { 616 | "version": "3.2.7", 617 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", 618 | "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", 619 | "dev": true, 620 | "requires": { 621 | "ms": "^2.1.1" 622 | } 623 | } 624 | } 625 | }, 626 | "nopt": { 627 | "version": "1.0.10", 628 | "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", 629 | "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", 630 | "dev": true, 631 | "requires": { 632 | "abbrev": "1" 633 | } 634 | }, 635 | "normalize-path": { 636 | "version": "3.0.0", 637 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 638 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 639 | "dev": true 640 | }, 641 | "notepack.io": { 642 | "version": "2.2.0", 643 | "resolved": "https://registry.npmjs.org/notepack.io/-/notepack.io-2.2.0.tgz", 644 | "integrity": "sha512-9b5w3t5VSH6ZPosoYnyDONnUTF8o0UkBw7JLA6eBlYJWyGT1Q3vQa8Hmuj1/X6RYvHjjygBDgw6fJhe0JEojfw==" 645 | }, 646 | "object-assign": { 647 | "version": "4.1.1", 648 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 649 | "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" 650 | }, 651 | "object-inspect": { 652 | "version": "1.12.2", 653 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", 654 | "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" 655 | }, 656 | "on-finished": { 657 | "version": "2.4.1", 658 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", 659 | "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", 660 | "requires": { 661 | "ee-first": "1.1.1" 662 | } 663 | }, 664 | "parseurl": { 665 | "version": "1.3.3", 666 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 667 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" 668 | }, 669 | "path-to-regexp": { 670 | "version": "0.1.7", 671 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 672 | "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" 673 | }, 674 | "picomatch": { 675 | "version": "2.3.1", 676 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 677 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 678 | "dev": true 679 | }, 680 | "proxy-addr": { 681 | "version": "2.0.7", 682 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", 683 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", 684 | "requires": { 685 | "forwarded": "0.2.0", 686 | "ipaddr.js": "1.9.1" 687 | } 688 | }, 689 | "pstree.remy": { 690 | "version": "1.1.8", 691 | "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", 692 | "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", 693 | "dev": true 694 | }, 695 | "qs": { 696 | "version": "6.10.3", 697 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", 698 | "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", 699 | "requires": { 700 | "side-channel": "^1.0.4" 701 | } 702 | }, 703 | "range-parser": { 704 | "version": "1.2.1", 705 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 706 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" 707 | }, 708 | "raw-body": { 709 | "version": "2.5.1", 710 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", 711 | "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", 712 | "requires": { 713 | "bytes": "3.1.2", 714 | "http-errors": "2.0.0", 715 | "iconv-lite": "0.4.24", 716 | "unpipe": "1.0.0" 717 | } 718 | }, 719 | "readdirp": { 720 | "version": "3.6.0", 721 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 722 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 723 | "dev": true, 724 | "requires": { 725 | "picomatch": "^2.2.1" 726 | } 727 | }, 728 | "redis": { 729 | "version": "4.2.0", 730 | "resolved": "https://registry.npmjs.org/redis/-/redis-4.2.0.tgz", 731 | "integrity": "sha512-bCR0gKVhIXFg8zCQjXEANzgI01DDixtPZgIUZHBCmwqixnu+MK3Tb2yqGjh+HCLASQVVgApiwhNkv+FoedZOGQ==", 732 | "requires": { 733 | "@redis/bloom": "1.0.2", 734 | "@redis/client": "1.2.0", 735 | "@redis/graph": "1.0.1", 736 | "@redis/json": "1.0.3", 737 | "@redis/search": "1.0.6", 738 | "@redis/time-series": "1.0.3" 739 | } 740 | }, 741 | "safe-buffer": { 742 | "version": "5.2.1", 743 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 744 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" 745 | }, 746 | "safer-buffer": { 747 | "version": "2.1.2", 748 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 749 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 750 | }, 751 | "semver": { 752 | "version": "5.7.1", 753 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", 754 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", 755 | "dev": true 756 | }, 757 | "send": { 758 | "version": "0.18.0", 759 | "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", 760 | "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", 761 | "requires": { 762 | "debug": "2.6.9", 763 | "depd": "2.0.0", 764 | "destroy": "1.2.0", 765 | "encodeurl": "~1.0.2", 766 | "escape-html": "~1.0.3", 767 | "etag": "~1.8.1", 768 | "fresh": "0.5.2", 769 | "http-errors": "2.0.0", 770 | "mime": "1.6.0", 771 | "ms": "2.1.3", 772 | "on-finished": "2.4.1", 773 | "range-parser": "~1.2.1", 774 | "statuses": "2.0.1" 775 | }, 776 | "dependencies": { 777 | "debug": { 778 | "version": "2.6.9", 779 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 780 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 781 | "requires": { 782 | "ms": "2.0.0" 783 | }, 784 | "dependencies": { 785 | "ms": { 786 | "version": "2.0.0", 787 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 788 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" 789 | } 790 | } 791 | }, 792 | "ms": { 793 | "version": "2.1.3", 794 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 795 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 796 | } 797 | } 798 | }, 799 | "serve-static": { 800 | "version": "1.15.0", 801 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", 802 | "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", 803 | "requires": { 804 | "encodeurl": "~1.0.2", 805 | "escape-html": "~1.0.3", 806 | "parseurl": "~1.3.3", 807 | "send": "0.18.0" 808 | } 809 | }, 810 | "setprototypeof": { 811 | "version": "1.2.0", 812 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", 813 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" 814 | }, 815 | "side-channel": { 816 | "version": "1.0.4", 817 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", 818 | "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", 819 | "requires": { 820 | "call-bind": "^1.0.0", 821 | "get-intrinsic": "^1.0.2", 822 | "object-inspect": "^1.9.0" 823 | } 824 | }, 825 | "simple-update-notifier": { 826 | "version": "1.0.7", 827 | "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.0.7.tgz", 828 | "integrity": "sha512-BBKgR84BJQJm6WjWFMHgLVuo61FBDSj1z/xSFUIozqO6wO7ii0JxCqlIud7Enr/+LhlbNI0whErq96P2qHNWew==", 829 | "dev": true, 830 | "requires": { 831 | "semver": "~7.0.0" 832 | }, 833 | "dependencies": { 834 | "semver": { 835 | "version": "7.0.0", 836 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", 837 | "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", 838 | "dev": true 839 | } 840 | } 841 | }, 842 | "socket.io": { 843 | "version": "4.5.1", 844 | "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.1.tgz", 845 | "integrity": "sha512-0y9pnIso5a9i+lJmsCdtmTTgJFFSvNQKDnPQRz28mGNnxbmqYg2QPtJTLFxhymFZhAIn50eHAKzJeiNaKr+yUQ==", 846 | "requires": { 847 | "accepts": "~1.3.4", 848 | "base64id": "~2.0.0", 849 | "debug": "~4.3.2", 850 | "engine.io": "~6.2.0", 851 | "socket.io-adapter": "~2.4.0", 852 | "socket.io-parser": "~4.0.4" 853 | } 854 | }, 855 | "socket.io-adapter": { 856 | "version": "2.4.0", 857 | "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz", 858 | "integrity": "sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg==" 859 | }, 860 | "socket.io-parser": { 861 | "version": "4.0.5", 862 | "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.0.5.tgz", 863 | "integrity": "sha512-sNjbT9dX63nqUFIOv95tTVm6elyIU4RvB1m8dOeZt+IgWwcWklFDOdmGcfo3zSiRsnR/3pJkjY5lfoGqEe4Eig==", 864 | "requires": { 865 | "@types/component-emitter": "^1.2.10", 866 | "component-emitter": "~1.3.0", 867 | "debug": "~4.3.1" 868 | } 869 | }, 870 | "statuses": { 871 | "version": "2.0.1", 872 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", 873 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" 874 | }, 875 | "supports-color": { 876 | "version": "5.5.0", 877 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 878 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 879 | "dev": true, 880 | "requires": { 881 | "has-flag": "^3.0.0" 882 | } 883 | }, 884 | "to-regex-range": { 885 | "version": "5.0.1", 886 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 887 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 888 | "dev": true, 889 | "requires": { 890 | "is-number": "^7.0.0" 891 | } 892 | }, 893 | "toidentifier": { 894 | "version": "1.0.1", 895 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", 896 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" 897 | }, 898 | "touch": { 899 | "version": "3.1.0", 900 | "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", 901 | "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", 902 | "dev": true, 903 | "requires": { 904 | "nopt": "~1.0.10" 905 | } 906 | }, 907 | "type-is": { 908 | "version": "1.6.18", 909 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 910 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 911 | "requires": { 912 | "media-typer": "0.3.0", 913 | "mime-types": "~2.1.24" 914 | } 915 | }, 916 | "uid2": { 917 | "version": "0.0.3", 918 | "resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.3.tgz", 919 | "integrity": "sha512-5gSP1liv10Gjp8cMEnFd6shzkL/D6W1uhXSFNCxDC+YI8+L8wkCYCbJ7n77Ezb4wE/xzMogecE+DtamEe9PZjg==" 920 | }, 921 | "undefsafe": { 922 | "version": "2.0.5", 923 | "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", 924 | "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", 925 | "dev": true 926 | }, 927 | "unpipe": { 928 | "version": "1.0.0", 929 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 930 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" 931 | }, 932 | "utils-merge": { 933 | "version": "1.0.1", 934 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 935 | "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" 936 | }, 937 | "vary": { 938 | "version": "1.1.2", 939 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 940 | "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" 941 | }, 942 | "ws": { 943 | "version": "8.2.3", 944 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", 945 | "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==" 946 | }, 947 | "yallist": { 948 | "version": "4.0.0", 949 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", 950 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" 951 | } 952 | } 953 | } 954 | --------------------------------------------------------------------------------