├── .gitignore
├── LICENSE
├── Makefile
├── README.adoc
├── bitcoin-websocket-client
├── Makefile
├── README.adoc
├── bitfinex.html
├── bitfinex.js
├── package-lock.json
└── package.json
├── chat-websockets.gif
├── index.html
├── load-balancer.pptx
├── package-lock.json
├── package.json
├── public
├── estilo.css
└── index.js
├── server.js
└── websocket.html
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .idea
3 | *.iml
4 | .DS_Store
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Manoel Campos da Silva Filho
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 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | linux:
2 | @# Instala o nodejs e o gerenciador de pacotes (bibliotecas) npm
3 | sudo apt install nodejs npm -y
4 |
5 | @# Usa o npm para instalar o nodemon globalmente (e não na pasta atual) para iniciar facilmente a app servidora
6 | sudo npm i -g nodemon
7 |
8 | @# Adiciona o caminho das bibliotecas do node ao path do sistema, assim executáveis como o nodemon serão localizados ao serem digitados no terminal
9 | cat ~/.profile | grep 'PATH:~/node_modules/.bin' > /dev/null || echo 'export PATH=$$PATH:~/node_modules/.bin' >> ~/.profile
10 |
11 | @# O comando ". arquivo_script" é o mesmo que "source arquivo_script", mas funciona em diferentes shells.
12 | . ~/.profile
13 |
14 | macos:
15 | brew -v > /dev/null || (echo "Faça download do gerenciador de pacotes Homebrew em http://brew.sh" && exit -1)
16 | brew install nodejs npm
17 | sudo npm i -g nodemon
18 | cat ~/.profile | grep 'PATH:~/node_modules/.bin' > /dev/null || echo 'export PATH=$$PATH:~/node_modules/.bin' >> ~/.profile
19 |
20 | @# O comando ". arquivo_script" é o mesmo que "source arquivo_script", mas funciona em diferentes shells.
21 | . ~/.profile
22 |
23 | install:
24 | @# Instala as dependências da aplicação servidora (as bibliotecas utilizadas)
25 | npm i
26 |
27 | clean:
28 | rm -rf node_modules
29 |
30 | remove:
31 | @# Caso esteja ocorrendo erro na instalação, tente fazer make remove para desinstalar o nodejs e npm
32 | sudo apt-get remove nodejs npm && sudo apt-get autoremove
--------------------------------------------------------------------------------
/README.adoc:
--------------------------------------------------------------------------------
1 | :source-highlighter: highlightjs
2 | :numbered:
3 | :icons: font
4 |
5 | ifdef::env-github[]
6 | :outfilesuffix: .adoc
7 | :caution-caption: :fire:
8 | :important-caption: :exclamation:
9 | :note-caption: :paperclip:
10 | :tip-caption: :bulb:
11 | :warning-caption: :warning:
12 | endif::[]
13 |
14 | = Aplicação de Mensagens Instantâneas utilizando WebSocket com Node.js
15 |
16 | NOTE: Acesse uma Playlist de vídeos mostrando todo o processo de desenvolvimento da aplicação https://www.youtube.com/watch?v=hEPAr4MPQjU&list=PLyo0RUAM69UvnqUq5SFeVahS_YTUVgq4v[aqui].
17 |
18 | image:chat-websockets.gif[]
19 |
20 | Web chat utilizando http://nodejs.org:[Node.js]. Com Node.js podemos usar JavaScript no lado servidor. A aplicação utiliza http://websocket.org[WebSockets (recurso do HTML5)] com a biblioteca http://socket.io para implementar o chat.
21 |
22 | A biblioteca socket.io apenas facilita o uso do recurso de WebSocket.
23 | WebSocket é um protocolo https://pt.wikipedia.org/wiki/Duplex#Full-duplex[full-duplex] leve para transmissão de dados em aplicações web.
24 | Se tal biblioteca for usada em uma aplicação web em Node.js, quando é feita uma conexão WebSocket ao servidor, todo o extenso cabeçalho e corpo de uma mensagem HTTP é trafegado pela rede. Depois que a conexão é realizada,
25 | ela fica estabelecida com o servidor e, a partir daí, somente os dados enviados pela aplicação
26 | (normalmente digitados pelo usuário) e um pequeno cabeçalho (usualmente de apenas https://tools.ietf.org/html/rfc6455#section-5.2[32 bits]) serão enviados ao servidor.
27 |
28 | Apesar de ser possível abrir uma conexão HTTP e mantê-la aberta para requisições
29 | subsequentes, cada requisição trafega o cabeçalho e corpo das mensagens HTTP, aumentando
30 | o tráfego de rede e tempo para recebimento de respostas.
31 | No Firefox, podemos monitorar o tráfego HTTP e ver a quantidade de dados trafegados
32 | por meio do menu Ferramentas >> Web Developer >> Network (F12).
33 |
34 | No Chrome devemos acessar o botão `...`, depois `More Tools >> Developer Tools >> Network` (F12).
35 | Na mesma aba, na parte inferior, podemos ver os frames WebSocket enviados
36 | e como tais frames são pequenos.
37 |
38 | Para aplicações web de tempo real como jogos, mensagens instantâneas e edição colaborativa de documentos, o uso de conexões leves como WebSockets reduz problemas de escalabilidade geográfica e escalabilidade de tamanho (número de usuários).
39 |
40 | Com WebSockets, diferente de uma aplicação web tradicional usando HTTP,
41 | o servidor pode enviar dados para um cliente conectado, sem que o cliente primeiro requisite tais dados.
42 | Isto faz todo o sentido nas aplicações descritas acima, onde um usuário conectado pode receber dados de outro usuário, mesmo sem ter solicitado tais dados (um usuário pode estar conectado e receber uma mensagem de outro, sem ele ser obrigado à enviar uma requisição ao sevidor para solicitar o recebimento de tais dados).
43 |
44 | Este projeto baseado no exemplo disponível no https://socket.io/get-started/chat/[site do socket.io].
45 |
46 | == Estrutura do Projeto
47 |
48 | - link:server.js[server.js]: representa a aplicação Node.js que permitirá aos clientes (por meio do navegador) interagirem no chat.
49 | - link:package.json[package.json]: representa o arquivo de configuração da aplicação servidora. Ele foi criando por meio de um assistante, digitando-se `npm init` no terminal. As dependências (bibliotecas utilizadas pela aplicação) foram baixadas e salvas em tal arquivo digitando-se `npm i express socket.io`. No entanto, como o `package.json` já está configurado, não é preciso executar estes dois comandos.
50 | - link:index.html[index.html]: página web que será disponibilizada aos clientes quando eles acessarem o
51 | servidor por meio do navegador. Tal página representa a parte cliente
52 | do chat. Por meio dela os usuários podem interagir entre si, utilizando
53 | o servidor como intermediário.
54 | - link:Makefile[Makefile]: arquivo que pode ser executado com o comando `make` no Linux/macOS para instalar as ferramentas necessárias. Ver seção de instalação abaixo. É interessante abrir tal arquivo para descobrir quais comandos estão sendo executados ao realizar o processo de instalação (como descrito a seguir).
55 |
56 | == Instalação
57 |
58 | O projeto usa o http://nodejs.org:[Node.js] para rodar o servidor e o http://npmjs.com:[npm] para gerenciar pacotes utilizados pela aplicação (como por exemplo, para baixar tais pacotes diretamente pelo terminal).
59 |
60 | Opcionalmente, pode-se usar o https://nodemon.io:[nodemon] para permitir monitorar alterações no código do servidor e reiniciá-lo automaticamente. Isto facilita muito o desenvolvimento pois não temos que parar o servidor manualmente cada vez que fizermos uma alteração no código.
61 |
62 | A seguir é mostrado como instalar tais ferramentas automaticamente no macOS, Linux e Windows.
63 |
64 | === macOS
65 |
66 | Para instalar as ferramentas no macOS, pode-se baixar o gerenciador de pacotes homebrew.
67 | A https://brew.sh[página oficial] mostra logo no topo a única instrução necessária para isto.
68 | Após instalar o homebrew, basta abrir um terminal no diretório raiz do projeto e executar `make macos`.
69 |
70 | === Linux
71 |
72 | Para instalar as ferramentas acima em Linux baseados em Debian (como Ubuntu e derivados),
73 | basta abrir um terminal no diretório raiz do projeto e executar `make linux`.
74 | No entanto, se ao executar o comando ocorrer erro indicando que o programa make não foi encontrado,
75 | execute um `sudo apt-get install make`.
76 |
77 | === Windows
78 |
79 | Os comandos acima são para Linux e macOS.
80 | Se você usa Windows, pode baixar manualmente o http://nodejs.org[Node.js] que os comandos npm descritos anteriormente
81 | possivelmente vão funcionar sem precisar de configurações adicionais.
82 |
83 | Mas se você quiser usar os mesmos comandos Linux da seção anterior
84 | (e ter disponíveis vários outros comandos existentes em Linux),
85 | pode baixar o https://docs.microsoft.com/en-us/windows/wsl/install-win10[Windows Subsystem for Linux].
86 | Depois disso, basta seguir os passos da seção anterior.
87 |
88 | === Dependências da aplicação servidora
89 |
90 | Os pacotes (dependências) que são utilizados pela aplicação servidora são salvos na pasta `node_modules`. Esta pasta não é incluída e pode ser removida a qualquer momento (uma vez que podemos usar um comando para baixar os pacotes novamente). Assim, para baixar tais pacotes em tal pasta, basta executar `make install`.
91 |
92 | == Executando a Aplicação
93 |
94 | === Servidor
95 |
96 | Para iniciar o servidor, podemos executar:
97 |
98 | [source, bash]
99 | ----
100 | npm start
101 | ----
102 |
103 | Porém, utilizando o nodemon, basta fazer `nodemon` que ele vai procurar um arquivo `server.js` e iniciá-lo automaticamente.
104 |
105 | === Cliente
106 |
107 | Após iniciar o servidor, ele vai mostrar no terminal o endereço que a aplicação pode ser acessada pelo navegador (cliente).
108 | O endereço padrão é http://localhost:8000.
109 | Cada aba ou janela do navegador aberta em tal endereço representará um usuário do chat.
110 |
111 | == Aplicação Cliente sem o uso da biblioteca socket.io
112 |
113 | A biblioteca socket.io facilita bastante a criação de aplicações clientes e servidoras que usem o protocolo WebSocket.
114 | No entanto, ao usar tal biblioteca, a interoperabilidade de tais aplicações é prejudicada.
115 | Logo, fazer uma aplicação cliente que não usa socket.io se comunicar com um servidor socket.io é mais complicado.
116 | Isto pode ser percebido ao analisar o código da página link:websocket.html[websocket.html].
117 | Esta é uma aplicação cliente que pode ser aberta simplesmente dando dois cliques no arquivo.
118 | Ela necessita que o servidor implementado aqui esteja em execução.
119 | Tal aplicação cliente usa os recursos de WebSockets nativos dos navegadores modernos,
120 | sem nenhuma biblioteca externa.
121 |
122 | == Hospedagem da Aplicação em Provedor de Nuvem
123 |
124 | Para podermos testar a aplicação remotamente, ela foi hospedada
125 | no https://render.com, um provedor de nuvem que fornece serviços que chamamos de Platform as a Service (PaaS). Tal provedor fornece gratuitamente uma plataforma para implantação (deploy) de aplicações, de modo que todo o processo de instalação das ferramentas necessárias para a execução da aplicação é automatizado e não temos que nos preocupar com nada disso.
126 | Isto inclui a instalação de:
127 |
128 | - ferramentas de execução (máquinas virtuais para Java, Node.js, Python, PHP, etc);
129 | - servidores web e de aplicação;
130 | - bibliotecas que tais aplicações utilizam.
131 |
132 | O Render é um serviço fantástico por se integrar com o GitHub.
133 | Ele detecta quando enviamos alterações para um repositório no GitHub (com git push), baixa o código e implanta a aplicação.
134 | Se tivermos aplicações em Java e outras linguagens que precisam ser compiladas, ele automatiza todo esse processo.
135 | Obviamente, seu projeto deve estar corretamente configurado, usando ferramentas de gerenciamento de dependências/automação
136 | de build como Maven e npm (este último que estamos usando aqui).
137 |
138 | Como esta aplicação é desenvolvida utilizando Node.js, o Render identifica isso pela existência do arquivo package.json e assim criar todo um ambiente de execução de aplicações Node pra gente.
139 |
--------------------------------------------------------------------------------
/bitcoin-websocket-client/Makefile:
--------------------------------------------------------------------------------
1 | linux:
2 | @# Instala o nodejs e o gerenciador de pacotes (bibliotecas) npm
3 | sudo apt install nodejs npm -y
4 |
5 | @# Usa o npm para instalar o nodemon globalmente (e não na pasta atual) para iniciar facilmente a app servidora
6 | sudo npm i -g nodemon
7 |
8 | @# Adiciona o caminho das bibliotecas do node ao path do sistema, assim executáveis como o nodemon serão localizados ao serem digitados no terminal
9 | cat ~/.profile | grep 'PATH:~/node_modules/.bin' > /dev/null || echo 'export PATH=$$PATH:~/node_modules/.bin' >> ~/.profile
10 |
11 | @# O comando ". arquivo_script" é o mesmo que "source arquivo_script", mas funciona em diferentes shells.
12 | . ~/.profile
13 |
14 | macos:
15 | brew -v > /dev/null || (echo "Faça download do gerenciador de pacotes Homebrew em http://brew.sh" && exit -1)
16 | brew install nodejs npm
17 | sudo npm i -g nodemon
18 | cat ~/.profile | grep 'PATH:~/node_modules/.bin' > /dev/null || echo 'export PATH=$$PATH:~/node_modules/.bin' >> ~/.profile
19 |
20 | @# O comando ". arquivo_script" é o mesmo que "source arquivo_script", mas funciona em diferentes shells.
21 | . ~/.profile
22 |
23 | install:
24 | @# Instala as dependências da aplicação servidora (as bibliotecas utilizadas)
25 | npm i
26 |
27 | clean:
28 | rm -rf node_modules
29 |
30 | remove:
31 | @# Caso esteja ocorrendo erro na instalação, tente fazer make remove para desinstalar o nodejs e npm
32 | sudo apt-get remove nodejs npm && sudo apt-get autoremove
--------------------------------------------------------------------------------
/bitcoin-websocket-client/README.adoc:
--------------------------------------------------------------------------------
1 | :source-highlighter: highlightjs
2 | :numbered:
3 |
4 | ifdef::env-github[]
5 | :outfilesuffix: .adoc
6 | :caution-caption: :fire:
7 | :important-caption: :exclamation:
8 | :note-caption: :paperclip:
9 | :tip-caption: :bulb:
10 | :warning-caption: :warning:
11 | endif::[]
12 |
13 | = Cotação de Criptomoedas usando WebSockets e API da bitfinex (link:https://kinolien.github.io/gitzip/?download=/manoelcampos/sd-websockets/tree/master/2.3-bitcoin-websocket-api[zip])
14 |
15 | Aplicação que usa a API do serviço https://docs.bitfinex.com/reference/ws-public-ticker[bitfinex] para obter a cotação do BitCoin (e outroas criptomoedas)
16 | em tempo real. A aplicação envia um requisição para assinar um canal por onde receberá notificações sempre que o preço da criptomoeda solicitada mudar.
17 |
18 | == Estrutura do Projeto
19 |
20 | O projeto é composto de duas aplicações de exemplo independentes, para mostrar como obter a cotação de criptomoedas tanto no lado servidor quanto no lado cliente. Temos então:
21 |
22 | - um backend usando http://nodejs.org:[Node.js] e a biblioteca https://www.npmjs.com/package/ws[ws] para fazer acesso a serviços usando o protocolo WebSockets.
23 | - um frontend que não depende de nenhum backend, utilizando a classe WebSocket nativa do HTML5.
24 |
25 | === Backend
26 |
27 | O backend é composto pelos arquivos:
28 |
29 | - link:bitfinex.js[bitfinex.js]: representa a aplicação Node.js que obterá a cotação de uma criptomoeda e imprimirá no terminal.
30 | - link:package.json[package.json]: representa o arquivo de configuração da aplicação servidora. Ele foi criando por meio de um assistante, digitando-se `npm init` no terminal. As dependências (bibliotecas utilizadas pela aplicação) foram baixadas e salvas em tal arquivo digitando-se `npm install ws`. No entanto, como o `package.json` já está configurado, não é preciso executar estes dois comandos.
31 | - link:Makefile[Makefile]: arquivo que pode ser executado com o comando `make` no Linux/macOS para instalar as ferramentas necessárias. Ver seção de instalação abaixo. É interessante abrir tal arquivo para descobrir quais comandos estão sendo executados ao realizar o processo de instalação (como descrito a seguir).
32 |
33 | === Frontend
34 |
35 | O frontend é composto apenas pelo arquivo link:bitfinex.html[bitfinex.html]. Ele usa a biblioteca JQuery apenas para facilitar a manipulação dos campos HTML e exibir uma pequena animação quando a cotação da moeda é alterada. Basta dar dois cliques em tal arquivo para abrir o frontend.
36 |
37 | Você pode testar o frontend online http://manoelcampos.com/sd-websockets/2.3-bitcoin-websocket-api/bitfinex.html[aqui].
38 |
39 | === Diferenças dos dois projetos
40 |
41 | Observe que apesar de ser usado JavaScript nos dois projetos, o código é levemente diferente.
42 | A implementação do WebSockets disponível no HTML5 é levemente diferente da implementação da biblioteca https://www.npmjs.com/package/ws[ws] que usamos no Node.js.
43 |
44 | == Servidor
45 |
46 | === Instalação
47 |
48 | O projeto usa o http://nodejs.org:[Node.js] para rodar o servidor e o http://npmjs.com:[npm] para gerenciar pacotes utilizados pela aplicação (como por exemplo, para baixar tais pacotes diretamente pelo terminal).
49 |
50 | Opcionalmente, pode-se usar o https://nodemon.io:[nodemon] para permitir monitorar alterações no código do servidor e reiniciá-lo automaticamente. Isto facilita muito o desenvolvimento pois não temos que parar o servidor manualmente cada vez que fizermos uma alteração no código.
51 |
52 | A seguir é mostrado como instalar tais ferramentas automaticamente no macOS, Linux e Windows.
53 |
54 | ==== macOS
55 |
56 | Para instalar as ferramentas no macOS, pode-se baixar o gerenciador de pacotes homebrew.
57 | A https://brew.sh[página oficial] mostra logo no topo a única instrução necessária para isto.
58 | Após instalar o homebrew, basta abrir um terminal no diretório raiz do projeto e executar `make macos`.
59 |
60 | ==== Linux
61 |
62 | Para instalar as ferramentas acima em Linux baseados em Debian (como Ubuntu e derivados),
63 | basta abrir um terminal no diretório raiz do projeto e executar `make linux`.
64 | No entanto, se ao executar o comando ocorrer erro indicando que o programa make não foi encontrado,
65 | execute um `sudo apt-get install make`.
66 |
67 | ==== Windows
68 |
69 | Os comandos acima são para Linux e macOS.
70 | Se você usa Windows, pode baixar manualmente o http://nodejs.org[Node.js] que os comandos npm descritos anteriormente
71 | possivelmente vão funcionar sem precisar de configurações adicionais.
72 |
73 | Mas se você quiser usar os mesmos comandos Linux da seção anterior
74 | (e ter disponíveis vários outros comandos existentes em Linux),
75 | pode baixar o https://docs.microsoft.com/en-us/windows/wsl/install-win10[Windows Subsystem for Linux].
76 | Depois disso, basta seguir os passos da seção anterior.
77 |
78 | === Dependências do Servidor
79 |
80 | Os pacotes (dependências) que são utilizados pela aplicação servidora são salvos na pasta `node_modules`. Esta pasta não é incluída e pode ser removida a qualquer momento (uma vez que podemos usar um comando para baixar os pacotes novamente). Assim, para baixar tais pacotes em tal pasta, basta executar `make install`.
81 |
82 | === Executando o Servidor
83 |
84 | Para iniciar o servidor, podemos executar:
85 |
86 | [source, bash]
87 | ----
88 | npm start
89 | ----
90 |
91 | Porém, utilizando o nodemon, basta fazer `nodemon` que ele vai procurar um arquivo `index.js` e iniciá-lo automaticamente.
92 |
93 | Como não temos um frontend para tal aplicação, todas as informações são impressas no terminal.
94 |
--------------------------------------------------------------------------------
/bitcoin-websocket-client/bitfinex.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Cotação de Criptomoedas
8 |
9 |
10 |
11 | Aplicação cliente que usa a API do serviço bitfinex
12 |
13 |
14 | Usa a API do bitfinex para obter a cotação do bitcoin (e outras criptomoedas) em tempo real.
15 | Ela envia um requisição para assinar um canal por onde receberá notificações sempre que o preço
16 | da criptomoeda solicitada mudar.
17 | Tal aplicação utiliza apenas os recursos de WebSockets do HTML5 disponibilizados pelo navegador.
18 | Assim, ela não depende de uma aplicação servidora para obter a cotação da moeda.
19 | O projeto Node.js existente é uma aplicação servidora independente,
20 | mostrando como fazer a mesma coisa do lado do servidor e obter
21 | cotação em background.
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
91 |
92 |
--------------------------------------------------------------------------------
/bitcoin-websocket-client/bitfinex.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Aplicação backend que usa a API do serviço bitfinex
3 | * para obter a cotação do Bitcoin (e outras criptomoedas)
4 | * em background.
5 | * Basta iniciar o servidor com npm start
6 | *
7 | * Ao iniciar, o backend envia requisição para assinar um canal por onde
8 | * a aplicação receberá notificações sempre que o preço
9 | * da criptomoeda solicitada mudar.
10 | *
11 | * A aplicação não usa o arquivo bitfinex.html,
12 | * que é apenas um exemplo de como fazer o mesmo mas
13 | * do lado do cliente com JavaScript puro.
14 | *
15 | * Referência: https://docs.bitfinex.com/reference/ws-public-ticker
16 | */
17 |
18 | //Biblioteca cliente de WebSocket
19 | const WebSocket = require('ws')
20 |
21 | //Mensagem pra solicitar assinatura de cotação do valor do BitCoin em dolar.
22 | const subscriptionMsg = {
23 | event: 'subscribe',
24 | channel: 'ticker',
25 | from: 'BTC',
26 | to: 'USD'
27 | }
28 |
29 | //Campo exibido pela API do bitfinex
30 | subscriptionMsg.symbol = 't' + subscriptionMsg.from + subscriptionMsg.to
31 |
32 | //Endereço de acesso ao serviço (API)
33 | const ws = new WebSocket('wss://api-pub.bitfinex.com/ws/2')
34 |
35 | //Id do canal por onde as notificações de preço da criptomoeda serão entregues
36 | let channelId = 0
37 |
38 | /**
39 | * Registra um listener para indicar que, sempre
40 | * que uma mensagem for recebida pela conexão de websocket,
41 | * deve-se verificar o tipo da mensagem e extrair algum
42 | * informação dela.
43 | */
44 | ws.onmessage = (msg) => {
45 | /* Se o conteúdo da mensagem for String, tal comando converte para JSON,
46 | ou seja, para um objeto javascript que poderemos acessar os campos facilmente. */
47 | msg.data = JSON.parse(msg.data)
48 |
49 | /* Se o tipo do evento for 'subscribed', que a assinatura no canal para receber
50 | cotação de uma determinada criptomoeda foi aceita*/
51 | if (msg.data['event'] === 'subscribed'){
52 | //Obtém o id do canal da nossa assinatura para podermos exibir mensagens recebidas apenas deste canal
53 | channelId = msg.data.chanId
54 | console.log('Registrada assinatura de cotação de ' + subscriptionMsg.from + ' para ' + subscriptionMsg.to)
55 | } else if (msg.data[0] === channelId && msg.data[1][6] !== undefined){
56 | /* Se a mensagem recebida for do canal ao qual fomos registrados anteriormente,
57 | então imprime os dados da mensagem.
58 | O conteúdo da mensagem é descrito no link no início deste arquivo. */
59 | console.log(subscriptionMsg.from + ' = ' + subscriptionMsg.to + ' ' + msg.data[1][6])
60 | }
61 | }
62 |
63 | //Envia solicitação de assinatura para ficar recebendo a cotação de uma criptomoeda em tempo real
64 | ws.onopen = () => ws.send(JSON.stringify(subscriptionMsg))
65 |
--------------------------------------------------------------------------------
/bitcoin-websocket-client/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bitfinex-websocket-backend",
3 | "version": "1.0.0",
4 | "lockfileVersion": 2,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "bitfinex-websocket-backend",
9 | "version": "1.0.0",
10 | "license": "MIT",
11 | "dependencies": {
12 | "ws": "^7.1.2"
13 | }
14 | },
15 | "node_modules/ws": {
16 | "version": "7.5.9",
17 | "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
18 | "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
19 | "engines": {
20 | "node": ">=8.3.0"
21 | },
22 | "peerDependencies": {
23 | "bufferutil": "^4.0.1",
24 | "utf-8-validate": "^5.0.2"
25 | },
26 | "peerDependenciesMeta": {
27 | "bufferutil": {
28 | "optional": true
29 | },
30 | "utf-8-validate": {
31 | "optional": true
32 | }
33 | }
34 | }
35 | },
36 | "dependencies": {
37 | "ws": {
38 | "version": "7.5.9",
39 | "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
40 | "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
41 | "requires": {}
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/bitcoin-websocket-client/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bitfinex-websocket-backend",
3 | "version": "1.0.0",
4 | "description": "Acessa cotações de criptomoedas usando a API de WebSockets da bitfinex.com",
5 | "main": "bitfinex.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "start": "node bitfinex.js"
9 | },
10 | "keywords": [
11 | "websockets",
12 | "cryptocurrency",
13 | "client",
14 | "bitfinex"
15 | ],
16 | "author": "Manoel Campos da Silva Filho",
17 | "license": "MIT",
18 | "dependencies": {
19 | "ws": "^7.1.2"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/chat-websockets.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manoelcampos/sd-websockets/9271479a1858f401c0107ab986ff6227e82526c7/chat-websockets.gif
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Chat
5 |
6 |
7 |
8 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/load-balancer.pptx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manoelcampos/sd-websockets/9271479a1858f401c0107ab986ff6227e82526c7/load-balancer.pptx
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "chat-nodejs-socket-io",
3 | "version": "1.0.0",
4 | "lockfileVersion": 2,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "chat-nodejs-socket-io",
9 | "version": "1.0.0",
10 | "license": "MIT",
11 | "dependencies": {
12 | "express": "^4.18.2",
13 | "socket.io": "^4.7.2"
14 | },
15 | "devDependencies": {
16 | "nodemon": "^3.0.1",
17 | "xmlhttprequest-ssl": ">=1.6.1"
18 | }
19 | },
20 | "node_modules/@socket.io/component-emitter": {
21 | "version": "3.1.0",
22 | "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
23 | "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg=="
24 | },
25 | "node_modules/@types/cookie": {
26 | "version": "0.4.1",
27 | "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz",
28 | "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q=="
29 | },
30 | "node_modules/@types/cors": {
31 | "version": "2.8.14",
32 | "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.14.tgz",
33 | "integrity": "sha512-RXHUvNWYICtbP6s18PnOCaqToK8y14DnLd75c6HfyKf228dxy7pHNOQkxPtvXKp/hINFMDjbYzsj63nnpPMSRQ==",
34 | "dependencies": {
35 | "@types/node": "*"
36 | }
37 | },
38 | "node_modules/@types/node": {
39 | "version": "20.8.2",
40 | "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.2.tgz",
41 | "integrity": "sha512-Vvycsc9FQdwhxE3y3DzeIxuEJbWGDsnrxvMADzTDF/lcdR9/K+AQIeAghTQsHtotg/q0j3WEOYS/jQgSdWue3w=="
42 | },
43 | "node_modules/abbrev": {
44 | "version": "1.1.1",
45 | "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
46 | "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
47 | "dev": true
48 | },
49 | "node_modules/accepts": {
50 | "version": "1.3.8",
51 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
52 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
53 | "dependencies": {
54 | "mime-types": "~2.1.34",
55 | "negotiator": "0.6.3"
56 | },
57 | "engines": {
58 | "node": ">= 0.6"
59 | }
60 | },
61 | "node_modules/anymatch": {
62 | "version": "3.1.3",
63 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
64 | "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
65 | "dev": true,
66 | "dependencies": {
67 | "normalize-path": "^3.0.0",
68 | "picomatch": "^2.0.4"
69 | },
70 | "engines": {
71 | "node": ">= 8"
72 | }
73 | },
74 | "node_modules/array-flatten": {
75 | "version": "1.1.1",
76 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
77 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
78 | },
79 | "node_modules/balanced-match": {
80 | "version": "1.0.2",
81 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
82 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
83 | "dev": true
84 | },
85 | "node_modules/base64id": {
86 | "version": "2.0.0",
87 | "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
88 | "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==",
89 | "engines": {
90 | "node": "^4.5.0 || >= 5.9"
91 | }
92 | },
93 | "node_modules/binary-extensions": {
94 | "version": "2.2.0",
95 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
96 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
97 | "dev": true,
98 | "engines": {
99 | "node": ">=8"
100 | }
101 | },
102 | "node_modules/body-parser": {
103 | "version": "1.20.1",
104 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
105 | "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
106 | "dependencies": {
107 | "bytes": "3.1.2",
108 | "content-type": "~1.0.4",
109 | "debug": "2.6.9",
110 | "depd": "2.0.0",
111 | "destroy": "1.2.0",
112 | "http-errors": "2.0.0",
113 | "iconv-lite": "0.4.24",
114 | "on-finished": "2.4.1",
115 | "qs": "6.11.0",
116 | "raw-body": "2.5.1",
117 | "type-is": "~1.6.18",
118 | "unpipe": "1.0.0"
119 | },
120 | "engines": {
121 | "node": ">= 0.8",
122 | "npm": "1.2.8000 || >= 1.4.16"
123 | }
124 | },
125 | "node_modules/brace-expansion": {
126 | "version": "1.1.11",
127 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
128 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
129 | "dev": true,
130 | "dependencies": {
131 | "balanced-match": "^1.0.0",
132 | "concat-map": "0.0.1"
133 | }
134 | },
135 | "node_modules/braces": {
136 | "version": "3.0.2",
137 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
138 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
139 | "dev": true,
140 | "dependencies": {
141 | "fill-range": "^7.0.1"
142 | },
143 | "engines": {
144 | "node": ">=8"
145 | }
146 | },
147 | "node_modules/bytes": {
148 | "version": "3.1.2",
149 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
150 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
151 | "engines": {
152 | "node": ">= 0.8"
153 | }
154 | },
155 | "node_modules/call-bind": {
156 | "version": "1.0.2",
157 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
158 | "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
159 | "dependencies": {
160 | "function-bind": "^1.1.1",
161 | "get-intrinsic": "^1.0.2"
162 | },
163 | "funding": {
164 | "url": "https://github.com/sponsors/ljharb"
165 | }
166 | },
167 | "node_modules/chokidar": {
168 | "version": "3.5.3",
169 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
170 | "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
171 | "dev": true,
172 | "funding": [
173 | {
174 | "type": "individual",
175 | "url": "https://paulmillr.com/funding/"
176 | }
177 | ],
178 | "dependencies": {
179 | "anymatch": "~3.1.2",
180 | "braces": "~3.0.2",
181 | "glob-parent": "~5.1.2",
182 | "is-binary-path": "~2.1.0",
183 | "is-glob": "~4.0.1",
184 | "normalize-path": "~3.0.0",
185 | "readdirp": "~3.6.0"
186 | },
187 | "engines": {
188 | "node": ">= 8.10.0"
189 | },
190 | "optionalDependencies": {
191 | "fsevents": "~2.3.2"
192 | }
193 | },
194 | "node_modules/concat-map": {
195 | "version": "0.0.1",
196 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
197 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
198 | "dev": true
199 | },
200 | "node_modules/content-disposition": {
201 | "version": "0.5.4",
202 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
203 | "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
204 | "dependencies": {
205 | "safe-buffer": "5.2.1"
206 | },
207 | "engines": {
208 | "node": ">= 0.6"
209 | }
210 | },
211 | "node_modules/content-type": {
212 | "version": "1.0.5",
213 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
214 | "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
215 | "engines": {
216 | "node": ">= 0.6"
217 | }
218 | },
219 | "node_modules/cookie": {
220 | "version": "0.5.0",
221 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
222 | "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
223 | "engines": {
224 | "node": ">= 0.6"
225 | }
226 | },
227 | "node_modules/cookie-signature": {
228 | "version": "1.0.6",
229 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
230 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
231 | },
232 | "node_modules/cors": {
233 | "version": "2.8.5",
234 | "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
235 | "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
236 | "dependencies": {
237 | "object-assign": "^4",
238 | "vary": "^1"
239 | },
240 | "engines": {
241 | "node": ">= 0.10"
242 | }
243 | },
244 | "node_modules/debug": {
245 | "version": "2.6.9",
246 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
247 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
248 | "dependencies": {
249 | "ms": "2.0.0"
250 | }
251 | },
252 | "node_modules/depd": {
253 | "version": "2.0.0",
254 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
255 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
256 | "engines": {
257 | "node": ">= 0.8"
258 | }
259 | },
260 | "node_modules/destroy": {
261 | "version": "1.2.0",
262 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
263 | "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
264 | "engines": {
265 | "node": ">= 0.8",
266 | "npm": "1.2.8000 || >= 1.4.16"
267 | }
268 | },
269 | "node_modules/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 | "node_modules/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 | "engines": {
279 | "node": ">= 0.8"
280 | }
281 | },
282 | "node_modules/engine.io": {
283 | "version": "6.5.2",
284 | "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.2.tgz",
285 | "integrity": "sha512-IXsMcGpw/xRfjra46sVZVHiSWo/nJ/3g1337q9KNXtS6YRzbW5yIzTCb9DjhrBe7r3GZQR0I4+nq+4ODk5g/cA==",
286 | "dependencies": {
287 | "@types/cookie": "^0.4.1",
288 | "@types/cors": "^2.8.12",
289 | "@types/node": ">=10.0.0",
290 | "accepts": "~1.3.4",
291 | "base64id": "2.0.0",
292 | "cookie": "~0.4.1",
293 | "cors": "~2.8.5",
294 | "debug": "~4.3.1",
295 | "engine.io-parser": "~5.2.1",
296 | "ws": "~8.11.0"
297 | },
298 | "engines": {
299 | "node": ">=10.2.0"
300 | }
301 | },
302 | "node_modules/engine.io-parser": {
303 | "version": "5.2.1",
304 | "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.1.tgz",
305 | "integrity": "sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==",
306 | "engines": {
307 | "node": ">=10.0.0"
308 | }
309 | },
310 | "node_modules/engine.io/node_modules/cookie": {
311 | "version": "0.4.2",
312 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
313 | "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==",
314 | "engines": {
315 | "node": ">= 0.6"
316 | }
317 | },
318 | "node_modules/engine.io/node_modules/debug": {
319 | "version": "4.3.4",
320 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
321 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
322 | "dependencies": {
323 | "ms": "2.1.2"
324 | },
325 | "engines": {
326 | "node": ">=6.0"
327 | },
328 | "peerDependenciesMeta": {
329 | "supports-color": {
330 | "optional": true
331 | }
332 | }
333 | },
334 | "node_modules/engine.io/node_modules/ms": {
335 | "version": "2.1.2",
336 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
337 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
338 | },
339 | "node_modules/escape-html": {
340 | "version": "1.0.3",
341 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
342 | "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
343 | },
344 | "node_modules/etag": {
345 | "version": "1.8.1",
346 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
347 | "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
348 | "engines": {
349 | "node": ">= 0.6"
350 | }
351 | },
352 | "node_modules/express": {
353 | "version": "4.18.2",
354 | "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
355 | "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
356 | "dependencies": {
357 | "accepts": "~1.3.8",
358 | "array-flatten": "1.1.1",
359 | "body-parser": "1.20.1",
360 | "content-disposition": "0.5.4",
361 | "content-type": "~1.0.4",
362 | "cookie": "0.5.0",
363 | "cookie-signature": "1.0.6",
364 | "debug": "2.6.9",
365 | "depd": "2.0.0",
366 | "encodeurl": "~1.0.2",
367 | "escape-html": "~1.0.3",
368 | "etag": "~1.8.1",
369 | "finalhandler": "1.2.0",
370 | "fresh": "0.5.2",
371 | "http-errors": "2.0.0",
372 | "merge-descriptors": "1.0.1",
373 | "methods": "~1.1.2",
374 | "on-finished": "2.4.1",
375 | "parseurl": "~1.3.3",
376 | "path-to-regexp": "0.1.7",
377 | "proxy-addr": "~2.0.7",
378 | "qs": "6.11.0",
379 | "range-parser": "~1.2.1",
380 | "safe-buffer": "5.2.1",
381 | "send": "0.18.0",
382 | "serve-static": "1.15.0",
383 | "setprototypeof": "1.2.0",
384 | "statuses": "2.0.1",
385 | "type-is": "~1.6.18",
386 | "utils-merge": "1.0.1",
387 | "vary": "~1.1.2"
388 | },
389 | "engines": {
390 | "node": ">= 0.10.0"
391 | }
392 | },
393 | "node_modules/fill-range": {
394 | "version": "7.0.1",
395 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
396 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
397 | "dev": true,
398 | "dependencies": {
399 | "to-regex-range": "^5.0.1"
400 | },
401 | "engines": {
402 | "node": ">=8"
403 | }
404 | },
405 | "node_modules/finalhandler": {
406 | "version": "1.2.0",
407 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
408 | "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
409 | "dependencies": {
410 | "debug": "2.6.9",
411 | "encodeurl": "~1.0.2",
412 | "escape-html": "~1.0.3",
413 | "on-finished": "2.4.1",
414 | "parseurl": "~1.3.3",
415 | "statuses": "2.0.1",
416 | "unpipe": "~1.0.0"
417 | },
418 | "engines": {
419 | "node": ">= 0.8"
420 | }
421 | },
422 | "node_modules/forwarded": {
423 | "version": "0.2.0",
424 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
425 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
426 | "engines": {
427 | "node": ">= 0.6"
428 | }
429 | },
430 | "node_modules/fresh": {
431 | "version": "0.5.2",
432 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
433 | "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
434 | "engines": {
435 | "node": ">= 0.6"
436 | }
437 | },
438 | "node_modules/fsevents": {
439 | "version": "2.3.3",
440 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
441 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
442 | "dev": true,
443 | "hasInstallScript": true,
444 | "optional": true,
445 | "os": [
446 | "darwin"
447 | ],
448 | "engines": {
449 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
450 | }
451 | },
452 | "node_modules/function-bind": {
453 | "version": "1.1.1",
454 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
455 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
456 | },
457 | "node_modules/get-intrinsic": {
458 | "version": "1.2.1",
459 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz",
460 | "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==",
461 | "dependencies": {
462 | "function-bind": "^1.1.1",
463 | "has": "^1.0.3",
464 | "has-proto": "^1.0.1",
465 | "has-symbols": "^1.0.3"
466 | },
467 | "funding": {
468 | "url": "https://github.com/sponsors/ljharb"
469 | }
470 | },
471 | "node_modules/glob-parent": {
472 | "version": "5.1.2",
473 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
474 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
475 | "dev": true,
476 | "dependencies": {
477 | "is-glob": "^4.0.1"
478 | },
479 | "engines": {
480 | "node": ">= 6"
481 | }
482 | },
483 | "node_modules/has": {
484 | "version": "1.0.4",
485 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz",
486 | "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==",
487 | "engines": {
488 | "node": ">= 0.4.0"
489 | }
490 | },
491 | "node_modules/has-flag": {
492 | "version": "3.0.0",
493 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
494 | "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
495 | "dev": true,
496 | "engines": {
497 | "node": ">=4"
498 | }
499 | },
500 | "node_modules/has-proto": {
501 | "version": "1.0.1",
502 | "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz",
503 | "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==",
504 | "engines": {
505 | "node": ">= 0.4"
506 | },
507 | "funding": {
508 | "url": "https://github.com/sponsors/ljharb"
509 | }
510 | },
511 | "node_modules/has-symbols": {
512 | "version": "1.0.3",
513 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
514 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
515 | "engines": {
516 | "node": ">= 0.4"
517 | },
518 | "funding": {
519 | "url": "https://github.com/sponsors/ljharb"
520 | }
521 | },
522 | "node_modules/http-errors": {
523 | "version": "2.0.0",
524 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
525 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
526 | "dependencies": {
527 | "depd": "2.0.0",
528 | "inherits": "2.0.4",
529 | "setprototypeof": "1.2.0",
530 | "statuses": "2.0.1",
531 | "toidentifier": "1.0.1"
532 | },
533 | "engines": {
534 | "node": ">= 0.8"
535 | }
536 | },
537 | "node_modules/iconv-lite": {
538 | "version": "0.4.24",
539 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
540 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
541 | "dependencies": {
542 | "safer-buffer": ">= 2.1.2 < 3"
543 | },
544 | "engines": {
545 | "node": ">=0.10.0"
546 | }
547 | },
548 | "node_modules/ignore-by-default": {
549 | "version": "1.0.1",
550 | "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
551 | "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
552 | "dev": true
553 | },
554 | "node_modules/inherits": {
555 | "version": "2.0.4",
556 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
557 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
558 | },
559 | "node_modules/ipaddr.js": {
560 | "version": "1.9.1",
561 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
562 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
563 | "engines": {
564 | "node": ">= 0.10"
565 | }
566 | },
567 | "node_modules/is-binary-path": {
568 | "version": "2.1.0",
569 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
570 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
571 | "dev": true,
572 | "dependencies": {
573 | "binary-extensions": "^2.0.0"
574 | },
575 | "engines": {
576 | "node": ">=8"
577 | }
578 | },
579 | "node_modules/is-extglob": {
580 | "version": "2.1.1",
581 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
582 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
583 | "dev": true,
584 | "engines": {
585 | "node": ">=0.10.0"
586 | }
587 | },
588 | "node_modules/is-glob": {
589 | "version": "4.0.3",
590 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
591 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
592 | "dev": true,
593 | "dependencies": {
594 | "is-extglob": "^2.1.1"
595 | },
596 | "engines": {
597 | "node": ">=0.10.0"
598 | }
599 | },
600 | "node_modules/is-number": {
601 | "version": "7.0.0",
602 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
603 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
604 | "dev": true,
605 | "engines": {
606 | "node": ">=0.12.0"
607 | }
608 | },
609 | "node_modules/lru-cache": {
610 | "version": "6.0.0",
611 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
612 | "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
613 | "dev": true,
614 | "dependencies": {
615 | "yallist": "^4.0.0"
616 | },
617 | "engines": {
618 | "node": ">=10"
619 | }
620 | },
621 | "node_modules/media-typer": {
622 | "version": "0.3.0",
623 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
624 | "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
625 | "engines": {
626 | "node": ">= 0.6"
627 | }
628 | },
629 | "node_modules/merge-descriptors": {
630 | "version": "1.0.1",
631 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
632 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
633 | },
634 | "node_modules/methods": {
635 | "version": "1.1.2",
636 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
637 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=",
638 | "engines": {
639 | "node": ">= 0.6"
640 | }
641 | },
642 | "node_modules/mime": {
643 | "version": "1.6.0",
644 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
645 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
646 | "bin": {
647 | "mime": "cli.js"
648 | },
649 | "engines": {
650 | "node": ">=4"
651 | }
652 | },
653 | "node_modules/mime-db": {
654 | "version": "1.52.0",
655 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
656 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
657 | "engines": {
658 | "node": ">= 0.6"
659 | }
660 | },
661 | "node_modules/mime-types": {
662 | "version": "2.1.35",
663 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
664 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
665 | "dependencies": {
666 | "mime-db": "1.52.0"
667 | },
668 | "engines": {
669 | "node": ">= 0.6"
670 | }
671 | },
672 | "node_modules/minimatch": {
673 | "version": "3.1.2",
674 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
675 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
676 | "dev": true,
677 | "dependencies": {
678 | "brace-expansion": "^1.1.7"
679 | },
680 | "engines": {
681 | "node": "*"
682 | }
683 | },
684 | "node_modules/ms": {
685 | "version": "2.0.0",
686 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
687 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
688 | },
689 | "node_modules/negotiator": {
690 | "version": "0.6.3",
691 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
692 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
693 | "engines": {
694 | "node": ">= 0.6"
695 | }
696 | },
697 | "node_modules/nodemon": {
698 | "version": "3.0.1",
699 | "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.1.tgz",
700 | "integrity": "sha512-g9AZ7HmkhQkqXkRc20w+ZfQ73cHLbE8hnPbtaFbFtCumZsjyMhKk9LajQ07U5Ux28lvFjZ5X7HvWR1xzU8jHVw==",
701 | "dev": true,
702 | "dependencies": {
703 | "chokidar": "^3.5.2",
704 | "debug": "^3.2.7",
705 | "ignore-by-default": "^1.0.1",
706 | "minimatch": "^3.1.2",
707 | "pstree.remy": "^1.1.8",
708 | "semver": "^7.5.3",
709 | "simple-update-notifier": "^2.0.0",
710 | "supports-color": "^5.5.0",
711 | "touch": "^3.1.0",
712 | "undefsafe": "^2.0.5"
713 | },
714 | "bin": {
715 | "nodemon": "bin/nodemon.js"
716 | },
717 | "engines": {
718 | "node": ">=10"
719 | },
720 | "funding": {
721 | "type": "opencollective",
722 | "url": "https://opencollective.com/nodemon"
723 | }
724 | },
725 | "node_modules/nodemon/node_modules/debug": {
726 | "version": "3.2.7",
727 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
728 | "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
729 | "dev": true,
730 | "dependencies": {
731 | "ms": "^2.1.1"
732 | }
733 | },
734 | "node_modules/nodemon/node_modules/ms": {
735 | "version": "2.1.3",
736 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
737 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
738 | "dev": true
739 | },
740 | "node_modules/nopt": {
741 | "version": "1.0.10",
742 | "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
743 | "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==",
744 | "dev": true,
745 | "dependencies": {
746 | "abbrev": "1"
747 | },
748 | "bin": {
749 | "nopt": "bin/nopt.js"
750 | },
751 | "engines": {
752 | "node": "*"
753 | }
754 | },
755 | "node_modules/normalize-path": {
756 | "version": "3.0.0",
757 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
758 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
759 | "dev": true,
760 | "engines": {
761 | "node": ">=0.10.0"
762 | }
763 | },
764 | "node_modules/object-assign": {
765 | "version": "4.1.1",
766 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
767 | "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
768 | "engines": {
769 | "node": ">=0.10.0"
770 | }
771 | },
772 | "node_modules/object-inspect": {
773 | "version": "1.12.3",
774 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
775 | "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==",
776 | "funding": {
777 | "url": "https://github.com/sponsors/ljharb"
778 | }
779 | },
780 | "node_modules/on-finished": {
781 | "version": "2.4.1",
782 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
783 | "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
784 | "dependencies": {
785 | "ee-first": "1.1.1"
786 | },
787 | "engines": {
788 | "node": ">= 0.8"
789 | }
790 | },
791 | "node_modules/parseurl": {
792 | "version": "1.3.3",
793 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
794 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
795 | "engines": {
796 | "node": ">= 0.8"
797 | }
798 | },
799 | "node_modules/path-to-regexp": {
800 | "version": "0.1.7",
801 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
802 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
803 | },
804 | "node_modules/picomatch": {
805 | "version": "2.3.1",
806 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
807 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
808 | "dev": true,
809 | "engines": {
810 | "node": ">=8.6"
811 | },
812 | "funding": {
813 | "url": "https://github.com/sponsors/jonschlinkert"
814 | }
815 | },
816 | "node_modules/proxy-addr": {
817 | "version": "2.0.7",
818 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
819 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
820 | "dependencies": {
821 | "forwarded": "0.2.0",
822 | "ipaddr.js": "1.9.1"
823 | },
824 | "engines": {
825 | "node": ">= 0.10"
826 | }
827 | },
828 | "node_modules/pstree.remy": {
829 | "version": "1.1.8",
830 | "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
831 | "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==",
832 | "dev": true
833 | },
834 | "node_modules/qs": {
835 | "version": "6.11.0",
836 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
837 | "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
838 | "dependencies": {
839 | "side-channel": "^1.0.4"
840 | },
841 | "engines": {
842 | "node": ">=0.6"
843 | },
844 | "funding": {
845 | "url": "https://github.com/sponsors/ljharb"
846 | }
847 | },
848 | "node_modules/range-parser": {
849 | "version": "1.2.1",
850 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
851 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
852 | "engines": {
853 | "node": ">= 0.6"
854 | }
855 | },
856 | "node_modules/raw-body": {
857 | "version": "2.5.1",
858 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
859 | "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
860 | "dependencies": {
861 | "bytes": "3.1.2",
862 | "http-errors": "2.0.0",
863 | "iconv-lite": "0.4.24",
864 | "unpipe": "1.0.0"
865 | },
866 | "engines": {
867 | "node": ">= 0.8"
868 | }
869 | },
870 | "node_modules/readdirp": {
871 | "version": "3.6.0",
872 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
873 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
874 | "dev": true,
875 | "dependencies": {
876 | "picomatch": "^2.2.1"
877 | },
878 | "engines": {
879 | "node": ">=8.10.0"
880 | }
881 | },
882 | "node_modules/safe-buffer": {
883 | "version": "5.2.1",
884 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
885 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
886 | "funding": [
887 | {
888 | "type": "github",
889 | "url": "https://github.com/sponsors/feross"
890 | },
891 | {
892 | "type": "patreon",
893 | "url": "https://www.patreon.com/feross"
894 | },
895 | {
896 | "type": "consulting",
897 | "url": "https://feross.org/support"
898 | }
899 | ]
900 | },
901 | "node_modules/safer-buffer": {
902 | "version": "2.1.2",
903 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
904 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
905 | },
906 | "node_modules/semver": {
907 | "version": "7.5.4",
908 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
909 | "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
910 | "dev": true,
911 | "dependencies": {
912 | "lru-cache": "^6.0.0"
913 | },
914 | "bin": {
915 | "semver": "bin/semver.js"
916 | },
917 | "engines": {
918 | "node": ">=10"
919 | }
920 | },
921 | "node_modules/send": {
922 | "version": "0.18.0",
923 | "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
924 | "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
925 | "dependencies": {
926 | "debug": "2.6.9",
927 | "depd": "2.0.0",
928 | "destroy": "1.2.0",
929 | "encodeurl": "~1.0.2",
930 | "escape-html": "~1.0.3",
931 | "etag": "~1.8.1",
932 | "fresh": "0.5.2",
933 | "http-errors": "2.0.0",
934 | "mime": "1.6.0",
935 | "ms": "2.1.3",
936 | "on-finished": "2.4.1",
937 | "range-parser": "~1.2.1",
938 | "statuses": "2.0.1"
939 | },
940 | "engines": {
941 | "node": ">= 0.8.0"
942 | }
943 | },
944 | "node_modules/send/node_modules/ms": {
945 | "version": "2.1.3",
946 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
947 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
948 | },
949 | "node_modules/serve-static": {
950 | "version": "1.15.0",
951 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
952 | "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
953 | "dependencies": {
954 | "encodeurl": "~1.0.2",
955 | "escape-html": "~1.0.3",
956 | "parseurl": "~1.3.3",
957 | "send": "0.18.0"
958 | },
959 | "engines": {
960 | "node": ">= 0.8.0"
961 | }
962 | },
963 | "node_modules/setprototypeof": {
964 | "version": "1.2.0",
965 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
966 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
967 | },
968 | "node_modules/side-channel": {
969 | "version": "1.0.4",
970 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
971 | "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
972 | "dependencies": {
973 | "call-bind": "^1.0.0",
974 | "get-intrinsic": "^1.0.2",
975 | "object-inspect": "^1.9.0"
976 | },
977 | "funding": {
978 | "url": "https://github.com/sponsors/ljharb"
979 | }
980 | },
981 | "node_modules/simple-update-notifier": {
982 | "version": "2.0.0",
983 | "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz",
984 | "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==",
985 | "dev": true,
986 | "dependencies": {
987 | "semver": "^7.5.3"
988 | },
989 | "engines": {
990 | "node": ">=10"
991 | }
992 | },
993 | "node_modules/socket.io": {
994 | "version": "4.7.2",
995 | "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.2.tgz",
996 | "integrity": "sha512-bvKVS29/I5fl2FGLNHuXlQaUH/BlzX1IN6S+NKLNZpBsPZIDH+90eQmCs2Railn4YUiww4SzUedJ6+uzwFnKLw==",
997 | "dependencies": {
998 | "accepts": "~1.3.4",
999 | "base64id": "~2.0.0",
1000 | "cors": "~2.8.5",
1001 | "debug": "~4.3.2",
1002 | "engine.io": "~6.5.2",
1003 | "socket.io-adapter": "~2.5.2",
1004 | "socket.io-parser": "~4.2.4"
1005 | },
1006 | "engines": {
1007 | "node": ">=10.2.0"
1008 | }
1009 | },
1010 | "node_modules/socket.io-adapter": {
1011 | "version": "2.5.2",
1012 | "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz",
1013 | "integrity": "sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==",
1014 | "dependencies": {
1015 | "ws": "~8.11.0"
1016 | }
1017 | },
1018 | "node_modules/socket.io-parser": {
1019 | "version": "4.2.4",
1020 | "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
1021 | "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
1022 | "dependencies": {
1023 | "@socket.io/component-emitter": "~3.1.0",
1024 | "debug": "~4.3.1"
1025 | },
1026 | "engines": {
1027 | "node": ">=10.0.0"
1028 | }
1029 | },
1030 | "node_modules/socket.io-parser/node_modules/debug": {
1031 | "version": "4.3.4",
1032 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
1033 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
1034 | "dependencies": {
1035 | "ms": "2.1.2"
1036 | },
1037 | "engines": {
1038 | "node": ">=6.0"
1039 | },
1040 | "peerDependenciesMeta": {
1041 | "supports-color": {
1042 | "optional": true
1043 | }
1044 | }
1045 | },
1046 | "node_modules/socket.io-parser/node_modules/ms": {
1047 | "version": "2.1.2",
1048 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
1049 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
1050 | },
1051 | "node_modules/socket.io/node_modules/debug": {
1052 | "version": "4.3.4",
1053 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
1054 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
1055 | "dependencies": {
1056 | "ms": "2.1.2"
1057 | },
1058 | "engines": {
1059 | "node": ">=6.0"
1060 | },
1061 | "peerDependenciesMeta": {
1062 | "supports-color": {
1063 | "optional": true
1064 | }
1065 | }
1066 | },
1067 | "node_modules/socket.io/node_modules/ms": {
1068 | "version": "2.1.2",
1069 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
1070 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
1071 | },
1072 | "node_modules/statuses": {
1073 | "version": "2.0.1",
1074 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
1075 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
1076 | "engines": {
1077 | "node": ">= 0.8"
1078 | }
1079 | },
1080 | "node_modules/supports-color": {
1081 | "version": "5.5.0",
1082 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
1083 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
1084 | "dev": true,
1085 | "dependencies": {
1086 | "has-flag": "^3.0.0"
1087 | },
1088 | "engines": {
1089 | "node": ">=4"
1090 | }
1091 | },
1092 | "node_modules/to-regex-range": {
1093 | "version": "5.0.1",
1094 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
1095 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
1096 | "dev": true,
1097 | "dependencies": {
1098 | "is-number": "^7.0.0"
1099 | },
1100 | "engines": {
1101 | "node": ">=8.0"
1102 | }
1103 | },
1104 | "node_modules/toidentifier": {
1105 | "version": "1.0.1",
1106 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
1107 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
1108 | "engines": {
1109 | "node": ">=0.6"
1110 | }
1111 | },
1112 | "node_modules/touch": {
1113 | "version": "3.1.0",
1114 | "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
1115 | "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==",
1116 | "dev": true,
1117 | "dependencies": {
1118 | "nopt": "~1.0.10"
1119 | },
1120 | "bin": {
1121 | "nodetouch": "bin/nodetouch.js"
1122 | }
1123 | },
1124 | "node_modules/type-is": {
1125 | "version": "1.6.18",
1126 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
1127 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
1128 | "dependencies": {
1129 | "media-typer": "0.3.0",
1130 | "mime-types": "~2.1.24"
1131 | },
1132 | "engines": {
1133 | "node": ">= 0.6"
1134 | }
1135 | },
1136 | "node_modules/undefsafe": {
1137 | "version": "2.0.5",
1138 | "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
1139 | "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
1140 | "dev": true
1141 | },
1142 | "node_modules/unpipe": {
1143 | "version": "1.0.0",
1144 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
1145 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
1146 | "engines": {
1147 | "node": ">= 0.8"
1148 | }
1149 | },
1150 | "node_modules/utils-merge": {
1151 | "version": "1.0.1",
1152 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
1153 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
1154 | "engines": {
1155 | "node": ">= 0.4.0"
1156 | }
1157 | },
1158 | "node_modules/vary": {
1159 | "version": "1.1.2",
1160 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
1161 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
1162 | "engines": {
1163 | "node": ">= 0.8"
1164 | }
1165 | },
1166 | "node_modules/ws": {
1167 | "version": "8.11.0",
1168 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
1169 | "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==",
1170 | "engines": {
1171 | "node": ">=10.0.0"
1172 | },
1173 | "peerDependencies": {
1174 | "bufferutil": "^4.0.1",
1175 | "utf-8-validate": "^5.0.2"
1176 | },
1177 | "peerDependenciesMeta": {
1178 | "bufferutil": {
1179 | "optional": true
1180 | },
1181 | "utf-8-validate": {
1182 | "optional": true
1183 | }
1184 | }
1185 | },
1186 | "node_modules/xmlhttprequest-ssl": {
1187 | "version": "1.6.2",
1188 | "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.6.2.tgz",
1189 | "integrity": "sha512-tYOaldF/0BLfKuoA39QMwD4j2m8lq4DIncqj1yuNELX4vz9+z/ieG/vwmctjJce+boFHXstqhWnHSxc4W8f4qg==",
1190 | "dev": true,
1191 | "engines": {
1192 | "node": ">=0.4.0"
1193 | }
1194 | },
1195 | "node_modules/yallist": {
1196 | "version": "4.0.0",
1197 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
1198 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
1199 | "dev": true
1200 | }
1201 | },
1202 | "dependencies": {
1203 | "@socket.io/component-emitter": {
1204 | "version": "3.1.0",
1205 | "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
1206 | "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg=="
1207 | },
1208 | "@types/cookie": {
1209 | "version": "0.4.1",
1210 | "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz",
1211 | "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q=="
1212 | },
1213 | "@types/cors": {
1214 | "version": "2.8.14",
1215 | "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.14.tgz",
1216 | "integrity": "sha512-RXHUvNWYICtbP6s18PnOCaqToK8y14DnLd75c6HfyKf228dxy7pHNOQkxPtvXKp/hINFMDjbYzsj63nnpPMSRQ==",
1217 | "requires": {
1218 | "@types/node": "*"
1219 | }
1220 | },
1221 | "@types/node": {
1222 | "version": "20.8.2",
1223 | "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.2.tgz",
1224 | "integrity": "sha512-Vvycsc9FQdwhxE3y3DzeIxuEJbWGDsnrxvMADzTDF/lcdR9/K+AQIeAghTQsHtotg/q0j3WEOYS/jQgSdWue3w=="
1225 | },
1226 | "abbrev": {
1227 | "version": "1.1.1",
1228 | "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
1229 | "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
1230 | "dev": true
1231 | },
1232 | "accepts": {
1233 | "version": "1.3.8",
1234 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
1235 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
1236 | "requires": {
1237 | "mime-types": "~2.1.34",
1238 | "negotiator": "0.6.3"
1239 | }
1240 | },
1241 | "anymatch": {
1242 | "version": "3.1.3",
1243 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
1244 | "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
1245 | "dev": true,
1246 | "requires": {
1247 | "normalize-path": "^3.0.0",
1248 | "picomatch": "^2.0.4"
1249 | }
1250 | },
1251 | "array-flatten": {
1252 | "version": "1.1.1",
1253 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
1254 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
1255 | },
1256 | "balanced-match": {
1257 | "version": "1.0.2",
1258 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
1259 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
1260 | "dev": true
1261 | },
1262 | "base64id": {
1263 | "version": "2.0.0",
1264 | "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
1265 | "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog=="
1266 | },
1267 | "binary-extensions": {
1268 | "version": "2.2.0",
1269 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
1270 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
1271 | "dev": true
1272 | },
1273 | "body-parser": {
1274 | "version": "1.20.1",
1275 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
1276 | "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
1277 | "requires": {
1278 | "bytes": "3.1.2",
1279 | "content-type": "~1.0.4",
1280 | "debug": "2.6.9",
1281 | "depd": "2.0.0",
1282 | "destroy": "1.2.0",
1283 | "http-errors": "2.0.0",
1284 | "iconv-lite": "0.4.24",
1285 | "on-finished": "2.4.1",
1286 | "qs": "6.11.0",
1287 | "raw-body": "2.5.1",
1288 | "type-is": "~1.6.18",
1289 | "unpipe": "1.0.0"
1290 | }
1291 | },
1292 | "brace-expansion": {
1293 | "version": "1.1.11",
1294 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
1295 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
1296 | "dev": true,
1297 | "requires": {
1298 | "balanced-match": "^1.0.0",
1299 | "concat-map": "0.0.1"
1300 | }
1301 | },
1302 | "braces": {
1303 | "version": "3.0.2",
1304 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
1305 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
1306 | "dev": true,
1307 | "requires": {
1308 | "fill-range": "^7.0.1"
1309 | }
1310 | },
1311 | "bytes": {
1312 | "version": "3.1.2",
1313 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
1314 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="
1315 | },
1316 | "call-bind": {
1317 | "version": "1.0.2",
1318 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
1319 | "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
1320 | "requires": {
1321 | "function-bind": "^1.1.1",
1322 | "get-intrinsic": "^1.0.2"
1323 | }
1324 | },
1325 | "chokidar": {
1326 | "version": "3.5.3",
1327 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
1328 | "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
1329 | "dev": true,
1330 | "requires": {
1331 | "anymatch": "~3.1.2",
1332 | "braces": "~3.0.2",
1333 | "fsevents": "~2.3.2",
1334 | "glob-parent": "~5.1.2",
1335 | "is-binary-path": "~2.1.0",
1336 | "is-glob": "~4.0.1",
1337 | "normalize-path": "~3.0.0",
1338 | "readdirp": "~3.6.0"
1339 | }
1340 | },
1341 | "concat-map": {
1342 | "version": "0.0.1",
1343 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
1344 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
1345 | "dev": true
1346 | },
1347 | "content-disposition": {
1348 | "version": "0.5.4",
1349 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
1350 | "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
1351 | "requires": {
1352 | "safe-buffer": "5.2.1"
1353 | }
1354 | },
1355 | "content-type": {
1356 | "version": "1.0.5",
1357 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
1358 | "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="
1359 | },
1360 | "cookie": {
1361 | "version": "0.5.0",
1362 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
1363 | "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw=="
1364 | },
1365 | "cookie-signature": {
1366 | "version": "1.0.6",
1367 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
1368 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
1369 | },
1370 | "cors": {
1371 | "version": "2.8.5",
1372 | "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
1373 | "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
1374 | "requires": {
1375 | "object-assign": "^4",
1376 | "vary": "^1"
1377 | }
1378 | },
1379 | "debug": {
1380 | "version": "2.6.9",
1381 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
1382 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
1383 | "requires": {
1384 | "ms": "2.0.0"
1385 | }
1386 | },
1387 | "depd": {
1388 | "version": "2.0.0",
1389 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
1390 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
1391 | },
1392 | "destroy": {
1393 | "version": "1.2.0",
1394 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
1395 | "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="
1396 | },
1397 | "ee-first": {
1398 | "version": "1.1.1",
1399 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
1400 | "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
1401 | },
1402 | "encodeurl": {
1403 | "version": "1.0.2",
1404 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
1405 | "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="
1406 | },
1407 | "engine.io": {
1408 | "version": "6.5.2",
1409 | "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.2.tgz",
1410 | "integrity": "sha512-IXsMcGpw/xRfjra46sVZVHiSWo/nJ/3g1337q9KNXtS6YRzbW5yIzTCb9DjhrBe7r3GZQR0I4+nq+4ODk5g/cA==",
1411 | "requires": {
1412 | "@types/cookie": "^0.4.1",
1413 | "@types/cors": "^2.8.12",
1414 | "@types/node": ">=10.0.0",
1415 | "accepts": "~1.3.4",
1416 | "base64id": "2.0.0",
1417 | "cookie": "~0.4.1",
1418 | "cors": "~2.8.5",
1419 | "debug": "~4.3.1",
1420 | "engine.io-parser": "~5.2.1",
1421 | "ws": "~8.11.0"
1422 | },
1423 | "dependencies": {
1424 | "cookie": {
1425 | "version": "0.4.2",
1426 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
1427 | "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA=="
1428 | },
1429 | "debug": {
1430 | "version": "4.3.4",
1431 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
1432 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
1433 | "requires": {
1434 | "ms": "2.1.2"
1435 | }
1436 | },
1437 | "ms": {
1438 | "version": "2.1.2",
1439 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
1440 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
1441 | }
1442 | }
1443 | },
1444 | "engine.io-parser": {
1445 | "version": "5.2.1",
1446 | "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.1.tgz",
1447 | "integrity": "sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ=="
1448 | },
1449 | "escape-html": {
1450 | "version": "1.0.3",
1451 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
1452 | "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
1453 | },
1454 | "etag": {
1455 | "version": "1.8.1",
1456 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
1457 | "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="
1458 | },
1459 | "express": {
1460 | "version": "4.18.2",
1461 | "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
1462 | "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
1463 | "requires": {
1464 | "accepts": "~1.3.8",
1465 | "array-flatten": "1.1.1",
1466 | "body-parser": "1.20.1",
1467 | "content-disposition": "0.5.4",
1468 | "content-type": "~1.0.4",
1469 | "cookie": "0.5.0",
1470 | "cookie-signature": "1.0.6",
1471 | "debug": "2.6.9",
1472 | "depd": "2.0.0",
1473 | "encodeurl": "~1.0.2",
1474 | "escape-html": "~1.0.3",
1475 | "etag": "~1.8.1",
1476 | "finalhandler": "1.2.0",
1477 | "fresh": "0.5.2",
1478 | "http-errors": "2.0.0",
1479 | "merge-descriptors": "1.0.1",
1480 | "methods": "~1.1.2",
1481 | "on-finished": "2.4.1",
1482 | "parseurl": "~1.3.3",
1483 | "path-to-regexp": "0.1.7",
1484 | "proxy-addr": "~2.0.7",
1485 | "qs": "6.11.0",
1486 | "range-parser": "~1.2.1",
1487 | "safe-buffer": "5.2.1",
1488 | "send": "0.18.0",
1489 | "serve-static": "1.15.0",
1490 | "setprototypeof": "1.2.0",
1491 | "statuses": "2.0.1",
1492 | "type-is": "~1.6.18",
1493 | "utils-merge": "1.0.1",
1494 | "vary": "~1.1.2"
1495 | }
1496 | },
1497 | "fill-range": {
1498 | "version": "7.0.1",
1499 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
1500 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
1501 | "dev": true,
1502 | "requires": {
1503 | "to-regex-range": "^5.0.1"
1504 | }
1505 | },
1506 | "finalhandler": {
1507 | "version": "1.2.0",
1508 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
1509 | "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
1510 | "requires": {
1511 | "debug": "2.6.9",
1512 | "encodeurl": "~1.0.2",
1513 | "escape-html": "~1.0.3",
1514 | "on-finished": "2.4.1",
1515 | "parseurl": "~1.3.3",
1516 | "statuses": "2.0.1",
1517 | "unpipe": "~1.0.0"
1518 | }
1519 | },
1520 | "forwarded": {
1521 | "version": "0.2.0",
1522 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
1523 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="
1524 | },
1525 | "fresh": {
1526 | "version": "0.5.2",
1527 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
1528 | "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="
1529 | },
1530 | "fsevents": {
1531 | "version": "2.3.3",
1532 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
1533 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
1534 | "dev": true,
1535 | "optional": true
1536 | },
1537 | "function-bind": {
1538 | "version": "1.1.1",
1539 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
1540 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
1541 | },
1542 | "get-intrinsic": {
1543 | "version": "1.2.1",
1544 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz",
1545 | "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==",
1546 | "requires": {
1547 | "function-bind": "^1.1.1",
1548 | "has": "^1.0.3",
1549 | "has-proto": "^1.0.1",
1550 | "has-symbols": "^1.0.3"
1551 | }
1552 | },
1553 | "glob-parent": {
1554 | "version": "5.1.2",
1555 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
1556 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
1557 | "dev": true,
1558 | "requires": {
1559 | "is-glob": "^4.0.1"
1560 | }
1561 | },
1562 | "has": {
1563 | "version": "1.0.4",
1564 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz",
1565 | "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ=="
1566 | },
1567 | "has-flag": {
1568 | "version": "3.0.0",
1569 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
1570 | "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
1571 | "dev": true
1572 | },
1573 | "has-proto": {
1574 | "version": "1.0.1",
1575 | "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz",
1576 | "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg=="
1577 | },
1578 | "has-symbols": {
1579 | "version": "1.0.3",
1580 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
1581 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="
1582 | },
1583 | "http-errors": {
1584 | "version": "2.0.0",
1585 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
1586 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
1587 | "requires": {
1588 | "depd": "2.0.0",
1589 | "inherits": "2.0.4",
1590 | "setprototypeof": "1.2.0",
1591 | "statuses": "2.0.1",
1592 | "toidentifier": "1.0.1"
1593 | }
1594 | },
1595 | "iconv-lite": {
1596 | "version": "0.4.24",
1597 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
1598 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
1599 | "requires": {
1600 | "safer-buffer": ">= 2.1.2 < 3"
1601 | }
1602 | },
1603 | "ignore-by-default": {
1604 | "version": "1.0.1",
1605 | "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
1606 | "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
1607 | "dev": true
1608 | },
1609 | "inherits": {
1610 | "version": "2.0.4",
1611 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
1612 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
1613 | },
1614 | "ipaddr.js": {
1615 | "version": "1.9.1",
1616 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
1617 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
1618 | },
1619 | "is-binary-path": {
1620 | "version": "2.1.0",
1621 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
1622 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
1623 | "dev": true,
1624 | "requires": {
1625 | "binary-extensions": "^2.0.0"
1626 | }
1627 | },
1628 | "is-extglob": {
1629 | "version": "2.1.1",
1630 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
1631 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
1632 | "dev": true
1633 | },
1634 | "is-glob": {
1635 | "version": "4.0.3",
1636 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
1637 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
1638 | "dev": true,
1639 | "requires": {
1640 | "is-extglob": "^2.1.1"
1641 | }
1642 | },
1643 | "is-number": {
1644 | "version": "7.0.0",
1645 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
1646 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
1647 | "dev": true
1648 | },
1649 | "lru-cache": {
1650 | "version": "6.0.0",
1651 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
1652 | "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
1653 | "dev": true,
1654 | "requires": {
1655 | "yallist": "^4.0.0"
1656 | }
1657 | },
1658 | "media-typer": {
1659 | "version": "0.3.0",
1660 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
1661 | "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="
1662 | },
1663 | "merge-descriptors": {
1664 | "version": "1.0.1",
1665 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
1666 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
1667 | },
1668 | "methods": {
1669 | "version": "1.1.2",
1670 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
1671 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
1672 | },
1673 | "mime": {
1674 | "version": "1.6.0",
1675 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
1676 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
1677 | },
1678 | "mime-db": {
1679 | "version": "1.52.0",
1680 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
1681 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
1682 | },
1683 | "mime-types": {
1684 | "version": "2.1.35",
1685 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
1686 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
1687 | "requires": {
1688 | "mime-db": "1.52.0"
1689 | }
1690 | },
1691 | "minimatch": {
1692 | "version": "3.1.2",
1693 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
1694 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
1695 | "dev": true,
1696 | "requires": {
1697 | "brace-expansion": "^1.1.7"
1698 | }
1699 | },
1700 | "ms": {
1701 | "version": "2.0.0",
1702 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
1703 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
1704 | },
1705 | "negotiator": {
1706 | "version": "0.6.3",
1707 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
1708 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="
1709 | },
1710 | "nodemon": {
1711 | "version": "3.0.1",
1712 | "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.1.tgz",
1713 | "integrity": "sha512-g9AZ7HmkhQkqXkRc20w+ZfQ73cHLbE8hnPbtaFbFtCumZsjyMhKk9LajQ07U5Ux28lvFjZ5X7HvWR1xzU8jHVw==",
1714 | "dev": true,
1715 | "requires": {
1716 | "chokidar": "^3.5.2",
1717 | "debug": "^3.2.7",
1718 | "ignore-by-default": "^1.0.1",
1719 | "minimatch": "^3.1.2",
1720 | "pstree.remy": "^1.1.8",
1721 | "semver": "^7.5.3",
1722 | "simple-update-notifier": "^2.0.0",
1723 | "supports-color": "^5.5.0",
1724 | "touch": "^3.1.0",
1725 | "undefsafe": "^2.0.5"
1726 | },
1727 | "dependencies": {
1728 | "debug": {
1729 | "version": "3.2.7",
1730 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
1731 | "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
1732 | "dev": true,
1733 | "requires": {
1734 | "ms": "^2.1.1"
1735 | }
1736 | },
1737 | "ms": {
1738 | "version": "2.1.3",
1739 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
1740 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
1741 | "dev": true
1742 | }
1743 | }
1744 | },
1745 | "nopt": {
1746 | "version": "1.0.10",
1747 | "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
1748 | "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==",
1749 | "dev": true,
1750 | "requires": {
1751 | "abbrev": "1"
1752 | }
1753 | },
1754 | "normalize-path": {
1755 | "version": "3.0.0",
1756 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
1757 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
1758 | "dev": true
1759 | },
1760 | "object-assign": {
1761 | "version": "4.1.1",
1762 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
1763 | "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="
1764 | },
1765 | "object-inspect": {
1766 | "version": "1.12.3",
1767 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
1768 | "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g=="
1769 | },
1770 | "on-finished": {
1771 | "version": "2.4.1",
1772 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
1773 | "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
1774 | "requires": {
1775 | "ee-first": "1.1.1"
1776 | }
1777 | },
1778 | "parseurl": {
1779 | "version": "1.3.3",
1780 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
1781 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
1782 | },
1783 | "path-to-regexp": {
1784 | "version": "0.1.7",
1785 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
1786 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
1787 | },
1788 | "picomatch": {
1789 | "version": "2.3.1",
1790 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
1791 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
1792 | "dev": true
1793 | },
1794 | "proxy-addr": {
1795 | "version": "2.0.7",
1796 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
1797 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
1798 | "requires": {
1799 | "forwarded": "0.2.0",
1800 | "ipaddr.js": "1.9.1"
1801 | }
1802 | },
1803 | "pstree.remy": {
1804 | "version": "1.1.8",
1805 | "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
1806 | "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==",
1807 | "dev": true
1808 | },
1809 | "qs": {
1810 | "version": "6.11.0",
1811 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
1812 | "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
1813 | "requires": {
1814 | "side-channel": "^1.0.4"
1815 | }
1816 | },
1817 | "range-parser": {
1818 | "version": "1.2.1",
1819 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
1820 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
1821 | },
1822 | "raw-body": {
1823 | "version": "2.5.1",
1824 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
1825 | "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
1826 | "requires": {
1827 | "bytes": "3.1.2",
1828 | "http-errors": "2.0.0",
1829 | "iconv-lite": "0.4.24",
1830 | "unpipe": "1.0.0"
1831 | }
1832 | },
1833 | "readdirp": {
1834 | "version": "3.6.0",
1835 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
1836 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
1837 | "dev": true,
1838 | "requires": {
1839 | "picomatch": "^2.2.1"
1840 | }
1841 | },
1842 | "safe-buffer": {
1843 | "version": "5.2.1",
1844 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
1845 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
1846 | },
1847 | "safer-buffer": {
1848 | "version": "2.1.2",
1849 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
1850 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
1851 | },
1852 | "semver": {
1853 | "version": "7.5.4",
1854 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
1855 | "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
1856 | "dev": true,
1857 | "requires": {
1858 | "lru-cache": "^6.0.0"
1859 | }
1860 | },
1861 | "send": {
1862 | "version": "0.18.0",
1863 | "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
1864 | "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
1865 | "requires": {
1866 | "debug": "2.6.9",
1867 | "depd": "2.0.0",
1868 | "destroy": "1.2.0",
1869 | "encodeurl": "~1.0.2",
1870 | "escape-html": "~1.0.3",
1871 | "etag": "~1.8.1",
1872 | "fresh": "0.5.2",
1873 | "http-errors": "2.0.0",
1874 | "mime": "1.6.0",
1875 | "ms": "2.1.3",
1876 | "on-finished": "2.4.1",
1877 | "range-parser": "~1.2.1",
1878 | "statuses": "2.0.1"
1879 | },
1880 | "dependencies": {
1881 | "ms": {
1882 | "version": "2.1.3",
1883 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
1884 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
1885 | }
1886 | }
1887 | },
1888 | "serve-static": {
1889 | "version": "1.15.0",
1890 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
1891 | "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
1892 | "requires": {
1893 | "encodeurl": "~1.0.2",
1894 | "escape-html": "~1.0.3",
1895 | "parseurl": "~1.3.3",
1896 | "send": "0.18.0"
1897 | }
1898 | },
1899 | "setprototypeof": {
1900 | "version": "1.2.0",
1901 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
1902 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
1903 | },
1904 | "side-channel": {
1905 | "version": "1.0.4",
1906 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
1907 | "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
1908 | "requires": {
1909 | "call-bind": "^1.0.0",
1910 | "get-intrinsic": "^1.0.2",
1911 | "object-inspect": "^1.9.0"
1912 | }
1913 | },
1914 | "simple-update-notifier": {
1915 | "version": "2.0.0",
1916 | "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz",
1917 | "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==",
1918 | "dev": true,
1919 | "requires": {
1920 | "semver": "^7.5.3"
1921 | }
1922 | },
1923 | "socket.io": {
1924 | "version": "4.7.2",
1925 | "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.2.tgz",
1926 | "integrity": "sha512-bvKVS29/I5fl2FGLNHuXlQaUH/BlzX1IN6S+NKLNZpBsPZIDH+90eQmCs2Railn4YUiww4SzUedJ6+uzwFnKLw==",
1927 | "requires": {
1928 | "accepts": "~1.3.4",
1929 | "base64id": "~2.0.0",
1930 | "cors": "~2.8.5",
1931 | "debug": "~4.3.2",
1932 | "engine.io": "~6.5.2",
1933 | "socket.io-adapter": "~2.5.2",
1934 | "socket.io-parser": "~4.2.4"
1935 | },
1936 | "dependencies": {
1937 | "debug": {
1938 | "version": "4.3.4",
1939 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
1940 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
1941 | "requires": {
1942 | "ms": "2.1.2"
1943 | }
1944 | },
1945 | "ms": {
1946 | "version": "2.1.2",
1947 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
1948 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
1949 | }
1950 | }
1951 | },
1952 | "socket.io-adapter": {
1953 | "version": "2.5.2",
1954 | "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz",
1955 | "integrity": "sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==",
1956 | "requires": {
1957 | "ws": "~8.11.0"
1958 | }
1959 | },
1960 | "socket.io-parser": {
1961 | "version": "4.2.4",
1962 | "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
1963 | "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
1964 | "requires": {
1965 | "@socket.io/component-emitter": "~3.1.0",
1966 | "debug": "~4.3.1"
1967 | },
1968 | "dependencies": {
1969 | "debug": {
1970 | "version": "4.3.4",
1971 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
1972 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
1973 | "requires": {
1974 | "ms": "2.1.2"
1975 | }
1976 | },
1977 | "ms": {
1978 | "version": "2.1.2",
1979 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
1980 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
1981 | }
1982 | }
1983 | },
1984 | "statuses": {
1985 | "version": "2.0.1",
1986 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
1987 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
1988 | },
1989 | "supports-color": {
1990 | "version": "5.5.0",
1991 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
1992 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
1993 | "dev": true,
1994 | "requires": {
1995 | "has-flag": "^3.0.0"
1996 | }
1997 | },
1998 | "to-regex-range": {
1999 | "version": "5.0.1",
2000 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
2001 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
2002 | "dev": true,
2003 | "requires": {
2004 | "is-number": "^7.0.0"
2005 | }
2006 | },
2007 | "toidentifier": {
2008 | "version": "1.0.1",
2009 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
2010 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
2011 | },
2012 | "touch": {
2013 | "version": "3.1.0",
2014 | "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
2015 | "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==",
2016 | "dev": true,
2017 | "requires": {
2018 | "nopt": "~1.0.10"
2019 | }
2020 | },
2021 | "type-is": {
2022 | "version": "1.6.18",
2023 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
2024 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
2025 | "requires": {
2026 | "media-typer": "0.3.0",
2027 | "mime-types": "~2.1.24"
2028 | }
2029 | },
2030 | "undefsafe": {
2031 | "version": "2.0.5",
2032 | "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
2033 | "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
2034 | "dev": true
2035 | },
2036 | "unpipe": {
2037 | "version": "1.0.0",
2038 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
2039 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="
2040 | },
2041 | "utils-merge": {
2042 | "version": "1.0.1",
2043 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
2044 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
2045 | },
2046 | "vary": {
2047 | "version": "1.1.2",
2048 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
2049 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
2050 | },
2051 | "ws": {
2052 | "version": "8.11.0",
2053 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
2054 | "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==",
2055 | "requires": {}
2056 | },
2057 | "xmlhttprequest-ssl": {
2058 | "version": "1.6.2",
2059 | "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.6.2.tgz",
2060 | "integrity": "sha512-tYOaldF/0BLfKuoA39QMwD4j2m8lq4DIncqj1yuNELX4vz9+z/ieG/vwmctjJce+boFHXstqhWnHSxc4W8f4qg==",
2061 | "dev": true
2062 | },
2063 | "yallist": {
2064 | "version": "4.0.0",
2065 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
2066 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
2067 | "dev": true
2068 | }
2069 | }
2070 | }
2071 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "chat-nodejs-socket-io",
3 | "version": "1.0.0",
4 | "description": "Web chat utilizando nodejs. Com Node.js podemos usar JavaScript no lado servidor e no cliente. A aplicação utiliza WebSockets com a biblioteca http://socket.io para implementar o chat.",
5 | "main": "server.js",
6 | "dependencies": {
7 | "express": "^4.18.2",
8 | "socket.io": "^4.7.2"
9 | },
10 | "devDependencies": {
11 | "nodemon": "^3.0.1",
12 | "xmlhttprequest-ssl": ">=1.6.1"
13 | },
14 | "scripts": {
15 | "dev": "nodemon"
16 | },
17 | "keywords": [
18 | "client/server",
19 | "chat",
20 | "nodejs",
21 | "javascript",
22 | "websockets",
23 | "socket.io"
24 | ],
25 | "author": "Manoel Campos da Silva Filho",
26 | "license": "MIT"
27 | }
28 |
--------------------------------------------------------------------------------
/public/estilo.css:
--------------------------------------------------------------------------------
1 | /*
2 | CSS Adatado de https://github.com/Roger-Melo/lyrics-search/blob/master/style.css
3 | @author Roger Melo
4 | */
5 |
6 | * {
7 | box-sizing: border-box;
8 | }
9 |
10 | body {
11 | font-family: Arial, Helvetica, sans-serif;
12 | margin: 0;
13 | background-color: rgb(211, 211, 211);
14 | }
15 |
16 | ul {
17 | list-style: none;
18 | text-indent: -2em;
19 | }
20 |
21 | ul li:before {
22 | content: "\1F63A";
23 | margin: 0 0.5em;
24 | }
25 |
26 | button {
27 | cursor: pointer;
28 | }
29 |
30 | button:active {
31 | transform: scale(0.95);
32 | }
33 |
34 | input:focus, button:focus {
35 | outline: none;
36 | }
37 |
38 | header {
39 | display: flex;
40 | flex-direction: column;
41 | align-items: center;
42 | justify-content: center;
43 | padding: 10px 0;
44 | position: relative;
45 | }
46 |
47 | header * {
48 | z-index: 1;
49 | }
50 |
51 | header h1 {
52 | margin: 0 0 30px;
53 | }
54 |
55 | form {
56 | position: relative;
57 | width: 500px;
58 | max-width: 100%;
59 | }
60 |
61 | form input {
62 | border: 0;
63 | border-radius: 50px;
64 | font-size: 16px;
65 | padding: 15px 30px;
66 | width: 100%;
67 | }
68 |
69 | form button {
70 | position: absolute;
71 | top: 2px;
72 | right: 1px;
73 | background-color: #10cce0;
74 | border: 0;
75 | border-radius: 50px;
76 | color: #fff;
77 | font-size: 16px;
78 | padding: 13px 30px;
79 | }
--------------------------------------------------------------------------------
/public/index.js:
--------------------------------------------------------------------------------
1 | $(function () {
2 | const socket = io()
3 |
4 | socket.nickname = ''
5 |
6 | $('form').submit(() => submeterForm(socket))
7 |
8 | socket.on('chat msg', exibirMsg)
9 | })
10 |
11 | function exibirMsg(msg) {
12 | $('#messages').append($('').text(msg))
13 | }
14 |
15 | function submeterForm(socket) {
16 | if (socket.nickname === '') {
17 | socket.nickname = $('#msg').val()
18 | socket.emit('login', socket.nickname)
19 |
20 | $('#msg').prop('placeholder', 'Digite uma mensagem');
21 | $('#button1').html('Enviar');
22 |
23 | socket.on('status', exibirMsgStatus)
24 | $('#msg').keypress(() => informaUsuariosInicioDigitacao(socket))
25 |
26 | $('#msg').keyup(() => socket.emit('status', ''))
27 | } else {
28 | socket.emit('chat msg', $('#msg').val())
29 | }
30 |
31 | $('#msg').val('')
32 | return false
33 | }
34 |
35 | function informaUsuariosInicioDigitacao(socket) {
36 | if (socket.nickname === '') {
37 | return
38 | }
39 |
40 | socket.emit('status', socket.nickname + ' está escrevendo...')
41 | }
42 |
43 | function exibirMsgStatus(msg) {
44 | $('#status').html(msg)
45 | console.log(msg)
46 | }
--------------------------------------------------------------------------------
/server.js:
--------------------------------------------------------------------------------
1 | const express = require('express')
2 |
3 | // https://expressjs.com/en/4x/api.html
4 | const app = express()
5 | app.use(express.static("public"))
6 |
7 | // https://nodejs.org/api/http.html
8 | const http = require('http').Server(app)
9 |
10 | // https://socket.io
11 | const serverSocket = require('socket.io')(http)
12 |
13 | const PORTA = process.env.PORT || 8080
14 |
15 | const host = "http://localhost"
16 |
17 | http.listen(PORTA, () => {
18 | const portaStr = PORTA === 80 ? '' : ':' + PORTA
19 | if (process.env.HEROKU_APP_NAME)
20 | console.log('Servidor iniciado. Abra o navegador em ' + host)
21 | else console.log('Servidor iniciado. Abra o navegador em ' + host + portaStr)
22 | })
23 |
24 | app.get('/', (req, res) => res.sendFile(__dirname + '/index.html'))
25 |
26 | function recebeConexaoUsuario(socket) {
27 | socket.on('login', (nickname) => registraLoginUsuario(socket, nickname))
28 | socket.on('disconnect', () => console.log('Cliente desconectado: ' + socket.nickname))
29 | socket.on('chat msg', (msg) => encaminhaMsgsUsuarios(socket, msg))
30 | socket.on('status', (msg) => encaminhaMsgStatus(socket, msg))
31 | }
32 |
33 | function encaminhaMsgStatus(socket, msg) {
34 | console.log(msg)
35 | socket.broadcast.emit('status', msg)
36 | }
37 |
38 | function encaminhaMsgsUsuarios(socket, msg) {
39 | serverSocket.emit('chat msg', `${socket.nickname} diz: ${msg}`)
40 | }
41 |
42 | function registraLoginUsuario(socket, nickname) {
43 | socket.nickname = nickname
44 | const msg = nickname + ' conectou'
45 | console.log(msg)
46 | serverSocket.emit('chat msg', msg)
47 | }
48 |
49 | serverSocket.on('connect', recebeConexaoUsuario)
50 |
--------------------------------------------------------------------------------
/websocket.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Chat usando WebSocket
8 |
9 |
10 |
11 | Aplicação de Chat que interopera com o servidor socket.io . Veja as instruções no README.adoc de como instalar e iniciar a aplicação servidora.
12 | Somente depois de iniciada, é que esta página funcionará.
13 |
14 |
15 | Note que esta página é totalmente independente do código do servidor.
16 | Uma vez que o servidor esteja rodando, podendo executar esta página até
17 | mesmo dando dois cliques nela que conseguiremos nos comunicar com o servidor.
18 | Isto mostra como é possível ter uma aplicação servidora independente,
19 | feita por um desenvolvedor, enquanto o cliente pode ser feito por outro
20 | desenvolvedor.
21 |
22 |
23 | Apesar da biblioteca socket.io facilitar o desenvolvimento de aplicações
24 | usando WebSocket, o uso dela no servidor dificulta o desenvolvimento de aplicações clientes que não utilizem
25 | a biblioteca. Isto pode ser percebido ao analisar o código para envio e tratamento de mensagens
26 | recebidas nesta página.
27 |
28 | Desta forma, para facilitar a interoperabilidade entre aplicações WebSocket desenvolvidas
29 | em diferentes linguagens e por diferentes programadores,
30 | o uso da biblioteca socket.io não é aconselhável.
31 |
32 |
33 |
41 |
42 |
43 |
44 |
152 |
153 |
154 |
--------------------------------------------------------------------------------