diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..691304456 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,9 @@ +coverage +initdb +node_modules +dist +.build +Dockerfile +docker-compose.yml +.git +.gitignore \ No newline at end of file diff --git a/.editorconfig b/.editorconfig index 65a74a7a4..be859fe4c 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,5 +9,5 @@ end_of_line = lf insert_final_newline = false charset = utf-8 indent_style = space -indent_size = 4 +indent_size = 2 trim_trailing_whitespace = true diff --git a/.env b/.env new file mode 100644 index 000000000..8cbc0bb4c --- /dev/null +++ b/.env @@ -0,0 +1,3 @@ +HTTP_SERVER_PORT=3000 +DATABASE_URL=postgres://postgres:123456@localhost:5432 +CURRENCYAPI_API_KEY=cur_live_cuO1rc3J9p5XJE9QYRgyadj3ERuP57GKFUdt9yOh \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..b43123061 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +coverage +node_modules +dist +.DS_Store \ No newline at end of file diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..bbcd12cfd --- /dev/null +++ b/.prettierignore @@ -0,0 +1,7 @@ +node_modules +dist +coverage +README.md +README.pt.md +tsconfig.json +yarn.lock \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 000000000..eba5a682d --- /dev/null +++ b/.prettierrc @@ -0,0 +1,7 @@ +{ + "semi": true, + "singleQuote": true, + "trailingComma": "es5", + "printWidth": 80, + "tabWidth": 2 +} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..5290fc800 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +FROM node:20.14.0 + +WORKDIR /usr/src/app + +COPY package.json yarn.lock ./ + +RUN yarn install + +COPY . . + +EXPOSE 3000 + +CMD ["yarn", "start"] \ No newline at end of file diff --git a/README.md b/README.md index 22af01577..25bef45ee 100644 --- a/README.md +++ b/README.md @@ -1,82 +1,239 @@ # Hurb Bravo Challenge -[[English](README.md) | [Portuguese](README.pt.md)] +## Descrição + +Esta é uma API para conversão monetária. Ela suporta conversões entre diversas moedas, incluindo moedas fiduciárias, criptomoedas e moedas fictícias. A moeda de lastro utilizada é o USD, e as cotações foram obtidas de APIs públicas para garantir que sejam reais e atuais. + +A solução foi desenvolvida utilizando, TDD, DDD, Ports & Adapters, Clean Architecture, design-patterns e outras estratégias arquiteturais. Sei que essa arquitetura pode ser considerada demasiadamente robusta para um projeto tão pequeno, mas o intuito é mostrar o que tenho em minha "caixa de ferramentas" e também dar a vocês material de análise de minha forma de codificar. No dia a dia gosto de dimensionar a solução de software para alcançar o melhor proveito no negócio. + +## Tecnologias Utilizadas + +- Node.js +- TypeScript +- Express +- Hapi +- Swagger UI +- PostgreSQL +- Docker +- Jest + +## Endpoints + +Indico fortemente a utilização do swagger para consultar a documentação da API e também para executar as requests. Essa documentação pode ser acessada no endereço `http://locahost:3000/api-docs`, mas caso queira ou precise testar utilizando uma ferramenta de requisições http como Postman, o endereço base para as requisições é o `http://localhost:3000/api/v1`. + +### Lista Paginada de Moedas + +Este endpoint não foi solicitado no desafio mas decidi fazer para ter um bom exemplo da utilização de CQRS. Eu fiz a _query_ do _[ GET ] /currencies/{code}_ também mas ela sozinha não realça as vantagens da separação de comandos e consultas. É importante também mencionar que este endpoint apenas estará disponível se o projeto for inicializado com `yarn start` ou `yarn dev`. O único objetivo desse comportamento é mostrar que as rotas também são configuráveis sem afetar a aplicação. + +`[ GET ] /currencies` + +```json +// query +{ + "currencies": [], // Código das moedas a serem filtradas + "page": 1, // Página corrente + "perPage": 10, // Quantidade de registros por página + "sortBy": "name", // Campo pelo qual a consulta será ordenada + "sortOrder": "asc", // Direção da ordenação +} +``` + +```json +// response schema +{ + "meta": { + "page": 0, + "perPage": 0, + "pageCount": 0, + "totalCount": 0 + }, + "data": [ + { + "id": "string", + "name": "string", + "code": "string", + "symbol": "string", + "decimalDigits": 0, + "rate": 0.1 + } + ] +} +``` + +### Adiciona uma nova moeda + +O desafio não define ou esclarece quem utilizará essa API, então pensando em praticidade, ao invés de pedir o _rate_ (valor proporcional de uma moeda em relação à moeda de lastro), que resultaria em um cadastro simples, eu preferi solicitar o valor da nova moeda bem como de uma moeda equivalente. Podemos inclusive seguir o exemplo citado no desafio do cadastro de uma moeda fictícia do GTA onde \$ 1.250.000,00 no jogo custam R$ 83,50 no mundo real. Com isso calculamos o valor proporcional da moeda em dólar. + +`[ POST ] /currencies` + +```json +// body +{ + "name": "Grand Theft Auto Dollar", + "code": "GTA", + "symbol": "GTA$", + "baseAmount": 1250000.00, + "equivalentCurrencyAmount": 83.50, + "equivalentCurrencyCode": "BRL" +} +``` + +```json +// response schema +{ + "currencyId": "string" +} +``` + +### Converte uma moeda em outra + +A descrição do desafio propõe a API de conversão de moeda mas não diz como deve ser seu retorno. Por isso tomei a liberdade de devolver um objeto com algumas informações que julguei serem uteis em uma API real de conversão. + +`[ POST ] /currencies/convert` + +```json +// query +{ + "from": "string", + "to": "string", + "amount": 0.1, +} +``` + +```json +// response schema +{ + "from": "string", + "to": "string", + "givenAmount": 0.1, + "convertedAmount": 0.1, + "convertedAmountFormatted": "string", + "decimalDigits": 0, + "symbol": "string" +} +``` + +### Recupera uma moeda específica + +Esse endpoint também não foi solicitado no desafio mas ele é super importante nos testes automatizado garantido que as moedas criadas na aplicação foram criadas corretamente. + +`[ GET ] /currencies/{code}` + +```json +// param +{ + "code": "string", +} +``` + +```json +// response schema +{ + "id": "string", + "name": "string", + "code": "string", + "symbol": "string", + "decimalDigits": 0, + "rate": 0.1 +} +``` + +### Exclui uma moeda do repositório + +`[ DELETE ] /currencies/{code}` + +Todas as configurações dessa aplicação (veja mais [aqui](#ancora1)) oferecem a possibilidade de criar e remover moedas, mas no caso das configurações que utilizam o gateway externo, apenas as novas moedas podem ser removidas. + +```json +// param +{ + "code": "string", +} +``` -Build an API, which responds to JSON, for currency conversion. It must have a backing currency (USD) and make conversions between different currencies with **real and live values**. +```json +// response schema +{ + "message": "string", +} +``` -The API must convert between the following currencies: -- USD -- BRL -- EUR -- BTC -- ETH +## Como Executar -Other coins could be added as usage. +### Pré-requisitos -Ex: USD to BRL, USD to BTC, ETH to BRL, etc... +- Docker & Docker Compose (caso queira rodar com o banco de dados postgres) +- Node +- Yarn (opcional) -The request must receive as parameters: The source currency, the amount to be converted and the final currency. +### Preparação do repositório -Ex: `?from=BTC&to=EUR&amount=123.45` +1. Clone o repositório: -Also build an endpoint to add and remove API supported currencies using HTTP verbs. +```shell +$ git clone https://github.com/hurbcom/challenge-bravo.git +``` -The API must support conversion between FIAT, crypto and fictitious. Example: BRL->HURB, HURB->ETH +2. Navegue até o diretório do projeto: -"Currency is the means by which monetary transactions are effected." (Wikipedia, 2021). +```shell +$ cd challenge-bravo +``` -Therefore, it is possible to imagine that new coins come into existence or cease to exist, it is also possible to imagine fictitious coins such as Dungeons & Dragons coins being used in these transactions, such as how much is a Gold Piece (Dungeons & Dragons) in Real or how much is the GTA$1 in Real. +3. Acesse a branch que criei com a solução do desafio: -Let's consider the PSN quote where GTA$1,250,000.00 cost R$83.50 we clearly have a relationship between the currencies, so it is possible to create a quote. (Playstation Store, 2021). +```shell +$ git checkout 'leandro/challenge-implementation' +``` -Ref: -Wikipedia [Institutional Website]. Available at: . Accessed on: 28 April 2021. -Playstation Store [Virtual Store]. Available at: . Accessed on: 28 April 2021. +### Passos para rodar a aplicação no Docker -You can use any programming language for the challenge. Below is the list of languages ​​that we here at Hurb have more affinity: +1. Construa e inicie os containers Docker: -- JavaScript (NodeJS) -- Python -- Go -- Ruby -- C++ -- PHP +```shell +$ docker-compose build +... +$ docker-compose up +``` -## Requirements +* _Para parar a aplicação execute ctrl+D no terminal_ +* _Para parar o container execute `docker-compose down`_ -- Fork this challenge and create your project (or workspace) using your version of that repository, as soon as you finish the challenge, submit a _pull request_. - - If you have any reason not to submit a _pull request_, create a private repository on Github, do every challenge on the **main** branch and don't forget to fill in the `pull-request.txt` file. As soon as you finish your development, add the user `automator-hurb` to your repository as a contributor and make it available for at least 30 days. **Do not add the `automator-hurb` until development is complete.** - - If you have any problem creating the private repository, at the end of the challenge fill in the file called `pull-request.txt`, compress the project folder - including the `.git` folder - and send it to us by email. -- The code needs to run on macOS or Ubuntu (preferably as a Docker container) -- To run your code, all you need to do is run the following commands: - - git clone \$your-fork - - cd \$your-fork - - command to install dependencies - - command to run the application -- The API can be written with or without the help of _frameworks_ - - If you choose to use a _framework_ that results in _boilerplate code_, mark in the README which piece of code was written by you. The more code you make, the more content we will have to rate. -- The API needs to support a volume of 1000 requests per second in a stress test. -- The API needs to include real and current quotes through integration with public currency quote APIs +### Passos para rodar a aplicação localmente -## Evaluation criteria +1. Instale as dependências -- **Organization of code**: Separation of modules, view and model, back-end and front-end -- **Clarity**: Does the README explain briefly what the problem is and how can I run the application? -- **Assertiveness**: Is the application doing what is expected? If something is missing, does the README explain why? -- **Code readability** (including comments) -- **Security**: Are there any clear vulnerabilities? -- **Test coverage** (We don't expect full coverage) -- **History of commits** (structure and quality) -- **UX**: Is the interface user-friendly and self-explanatory? Is the API intuitive? -- **Technical choices**: Is the choice of libraries, database, architecture, etc. the best choice for the application? +```sh +$ yarn install +``` -## Doubts +2. Inicie o banco de dados via docker-compose -Any questions you may have, check the [_issues_](https://github.com/HurbCom/challenge-bravo/issues) to see if someone hasn't already and if you can't find your answer, open one yourself. new issue! +```sh +$ docker-compose up db +``` -Godspeed! ;) +1. Inicie a aplicação -

- Challange accepted -

+```sh +$ yarn start +``` + +* _Para parar a aplicação execute ctrl+D no terminal_ + + + +> Há ainda outros scripts de inicialização que podem ser utilizados. Cada um sobe o servidor com uma configuração diferente: +> - `start` ou `dev`: Inicia o servidor express com swagger UI e repositório postgres que roda no docker; +> - `dev:express+fake`: Iniciar o servidor express com swagger UI e Repositório em memória; +> - `dev:hapi+fake`: Inicia o servidor hapi com repositório em memória; +> - `dev:express+gw-on`: Inicia o servidor express com swagger UI e o repositório utiliza o gateway currencyapi.com para ter a contação do dia de forma online. +> - `dev:express+gw-off`: Inicia o servidor express com swagger UI e simula a requisição para o gatewayapi.com (para fins de testes sem fazer requisições reais pois são liberadas apenas 300 requisições/mês) + +### Executar testes + +```sh +$ yarn test +``` +- Também pode ser utilizado o `yarn test:watch` que roda os testes com a flag `--watch`. \ No newline at end of file diff --git a/challenge-README.md b/challenge-README.md new file mode 100644 index 000000000..22af01577 --- /dev/null +++ b/challenge-README.md @@ -0,0 +1,82 @@ +# Hurb Bravo Challenge + +[[English](README.md) | [Portuguese](README.pt.md)] + +Build an API, which responds to JSON, for currency conversion. It must have a backing currency (USD) and make conversions between different currencies with **real and live values**. + +The API must convert between the following currencies: + +- USD +- BRL +- EUR +- BTC +- ETH + +Other coins could be added as usage. + +Ex: USD to BRL, USD to BTC, ETH to BRL, etc... + +The request must receive as parameters: The source currency, the amount to be converted and the final currency. + +Ex: `?from=BTC&to=EUR&amount=123.45` + +Also build an endpoint to add and remove API supported currencies using HTTP verbs. + +The API must support conversion between FIAT, crypto and fictitious. Example: BRL->HURB, HURB->ETH + +"Currency is the means by which monetary transactions are effected." (Wikipedia, 2021). + +Therefore, it is possible to imagine that new coins come into existence or cease to exist, it is also possible to imagine fictitious coins such as Dungeons & Dragons coins being used in these transactions, such as how much is a Gold Piece (Dungeons & Dragons) in Real or how much is the GTA$1 in Real. + +Let's consider the PSN quote where GTA$1,250,000.00 cost R$83.50 we clearly have a relationship between the currencies, so it is possible to create a quote. (Playstation Store, 2021). + +Ref: +Wikipedia [Institutional Website]. Available at: . Accessed on: 28 April 2021. +Playstation Store [Virtual Store]. Available at: . Accessed on: 28 April 2021. + +You can use any programming language for the challenge. Below is the list of languages ​​that we here at Hurb have more affinity: + +- JavaScript (NodeJS) +- Python +- Go +- Ruby +- C++ +- PHP + +## Requirements + +- Fork this challenge and create your project (or workspace) using your version of that repository, as soon as you finish the challenge, submit a _pull request_. + - If you have any reason not to submit a _pull request_, create a private repository on Github, do every challenge on the **main** branch and don't forget to fill in the `pull-request.txt` file. As soon as you finish your development, add the user `automator-hurb` to your repository as a contributor and make it available for at least 30 days. **Do not add the `automator-hurb` until development is complete.** + - If you have any problem creating the private repository, at the end of the challenge fill in the file called `pull-request.txt`, compress the project folder - including the `.git` folder - and send it to us by email. +- The code needs to run on macOS or Ubuntu (preferably as a Docker container) +- To run your code, all you need to do is run the following commands: + - git clone \$your-fork + - cd \$your-fork + - command to install dependencies + - command to run the application +- The API can be written with or without the help of _frameworks_ + - If you choose to use a _framework_ that results in _boilerplate code_, mark in the README which piece of code was written by you. The more code you make, the more content we will have to rate. +- The API needs to support a volume of 1000 requests per second in a stress test. +- The API needs to include real and current quotes through integration with public currency quote APIs + +## Evaluation criteria + +- **Organization of code**: Separation of modules, view and model, back-end and front-end +- **Clarity**: Does the README explain briefly what the problem is and how can I run the application? +- **Assertiveness**: Is the application doing what is expected? If something is missing, does the README explain why? +- **Code readability** (including comments) +- **Security**: Are there any clear vulnerabilities? +- **Test coverage** (We don't expect full coverage) +- **History of commits** (structure and quality) +- **UX**: Is the interface user-friendly and self-explanatory? Is the API intuitive? +- **Technical choices**: Is the choice of libraries, database, architecture, etc. the best choice for the application? + +## Doubts + +Any questions you may have, check the [_issues_](https://github.com/HurbCom/challenge-bravo/issues) to see if someone hasn't already and if you can't find your answer, open one yourself. new issue! + +Godspeed! ;) + +

+ Challange accepted +

diff --git a/README.pt.md b/challenge-README.pt.md similarity index 100% rename from README.pt.md rename to challenge-README.pt.md diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 000000000..a1d80f216 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,28 @@ +version: '3.9' + +services: + app: + build: . + ports: + - '3000:3000' + environment: + NODE_ENV: development + HTTP_SERVER_PORT: 3000 + DATABASE_URL: postgres://postgres:123456@db:5432 + CURRENCYAPI_API_KEY: cur_live_cuO1rc3J9p5XJE9QYRgyadj3ERuP57GKFUdt9yOh + volumes: + - .:/usr/src/app + - /usr/src/app/node_modules + command: yarn dev + depends_on: + - db + + db: + image: postgres + ports: + - '5432:5432' + environment: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: 123456 + volumes: + - ./initdb:/docker-entrypoint-initdb.d diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 000000000..cc55f42f4 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,14 @@ +import pluginJs from '@eslint/js'; +import eslintConfigPrettier from 'eslint-config-prettier'; +import tseslint from 'typescript-eslint'; + +export default [ + pluginJs.configs.recommended, + ...tseslint.configs.recommended, + eslintConfigPrettier, + { + rules: { + '@typescript-eslint/no-explicit-any': 'off', + }, + }, +]; diff --git a/initdb/init.sql b/initdb/init.sql new file mode 100644 index 000000000..f75150455 --- /dev/null +++ b/initdb/init.sql @@ -0,0 +1,402 @@ +-- Drop the rate table if it exists to apply new configuration +-- DROP TABLE IF EXISTS currency; +-- DROP TABLE IF EXISTS rate; + +-- Create the currency table if it does not exist +CREATE TABLE IF NOT EXISTS currency ( + id UUID DEFAULT gen_random_uuid() PRIMARY KEY, + code VARCHAR(10) NOT NULL UNIQUE, + name VARCHAR(50) NOT NULL, + symbol VARCHAR(10) NOT NULL, + decimal_digits INTEGER NOT NULL +); + +-- Create the rate table if it does not exist +CREATE TABLE IF NOT EXISTS rate ( + id UUID DEFAULT gen_random_uuid() PRIMARY KEY, + currency_id UUID NOT NULL REFERENCES currency(id) ON DELETE CASCADE, + rate NUMERIC(18, 10) NOT NULL, + updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), + UNIQUE(currency_id, updated_at) +); + +-- Insert currencies into the currency table +-- These inserts will not execute if the currency code already exists + +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('AED', 'United Arab Emirates Dirham', 'AED', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('AFN', 'Afghan Afghani', 'Af', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('ALL', 'Albanian Lek', 'ALL', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('AMD', 'Armenian Dram', 'AMD', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('ANG', 'NL Antillean Guilder', 'ƒ', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('AOA', 'Angolan Kwanza', 'Kz', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('ARS', 'Argentine Peso', 'AR$', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('AUD', 'Australian Dollar', 'AU$', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('AWG', 'Aruban Florin', 'Afl.', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('AZN', 'Azerbaijani Manat', 'man.', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('BAM', 'Bosnia-Herzegovina Convertible Mark', 'KM', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('BBD', 'Barbadian Dollar', 'Bds$', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('BDT', 'Bangladeshi Taka', 'Tk', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('BGN', 'Bulgarian Lev', 'BGN', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('BHD', 'Bahraini Dinar', 'BD',3) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('BIF', 'Burundian Franc', 'FBu', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('BMD', 'Bermudan Dollar', 'BD$', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('BND', 'Brunei Dollar', 'BN$', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('BOB', 'Bolivian Boliviano', 'Bs', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('BRL', 'Brazilian Real', 'R$', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('BSD', 'Bahamian Dollar', 'B$', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('BTN', 'Bhutanese Ngultrum', 'Nu.', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('BWP', 'Botswanan Pula', 'BWP', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('BYN', 'Belarusian ruble', 'Br', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('BYR', 'Belarusian Ruble', 'BYR', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('BZD', 'Belize Dollar', 'BZ$', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('CAD', 'Canadian Dollar', 'CA$', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('CDF', 'Congolese Franc', 'CDF', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('CHF', 'Swiss Franc', 'CHF', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('CLF', 'Unidad de Fomento', 'UF', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('CLP', 'Chilean Peso', 'CL$', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('CNY', 'Chinese Yuan', 'CN¥', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('COP', 'Coombian Peso', 'CO$', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('CRC', 'Costa Rican Colón', '₡', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('CUC', 'Cuban Convertible Peso', 'CUC$', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('CUP', 'Cuban Peso', '$MN', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('CVE', 'Cape Verdean Escudo', 'CV$', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('CZK', 'Czech Republic Koruna', 'Kč', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('DJF', 'Djiboutian Franc', 'Fdj', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('DKK', 'Danish Krone', 'Dkr', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('DOP', 'Dominican Peso', 'RD$', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('DZD', 'Algerian Dinar', 'DA', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('EGP', 'Egyptian Pound', 'EGP', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('ERN', 'Eritrean Nakfa', 'Nfk', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('ETB', 'Ethiopian Birr', 'Br', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('EUR', 'Euro', '€', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('FJD', 'Fijian Dollar', 'FJ$', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('FKP', 'Falkland Islands Pound', 'FK£', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('GBP', 'British Pound Sterling', '£', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('GEL', 'Georgian Lari', 'GEL', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('GGP', 'Guernsey pound', '£', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('GHS', 'Ghanaian Cedi', 'GH₵', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('GIP', 'Gibraltar Pound', '£', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('GMD', 'Gambian Dalasi', 'D', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('GNF', 'Guinean Franc', 'FG', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('GTQ', 'Guatemalan Quetzal', 'GTQ', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('GYD', 'Guyanaese Dollar', 'G$', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('HKD', 'Hong Kong Dollar', 'HK$', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('HNL', 'Honduran Lempira', 'HNL', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('HRK', 'Croatian Kuna', 'kn', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('HTG', 'Haitian Gourde', 'G', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('HUF', 'Hungarian Forint', 'Ft', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('IDR', 'Indonesian Rupiah', 'Rp', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('ILS', 'Israeli New Sheqel', '₪', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('IMP', 'Manx pound', '£', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('INR', 'Indian Rupee', 'Rs', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('IQD', 'Iraqi Dinar', 'IQD', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('IRR', 'Iranian Rial', 'IRR', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('ISK', 'Icelandic Króna', 'Ikr', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('JEP', 'Jersey pound', '£', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('JMD', 'Jamaican Dollar', 'J$', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('JOD', 'Jordanian Dinar', 'JD',3) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('JPY', 'Japanese Yen', '¥', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('KES', 'Kenyan Shilling', 'Ksh', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('KGS', 'Kyrgystani Som', 'KGS', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('KHR', 'Cambodian Riel', 'KHR', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('KMF', 'Comorian Franc', 'CF', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('KPW', 'North Korean Won', '₩', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('KRW', 'South Korean Won', '₩', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('KWD', 'Kuwaiti Dinar', 'KD',3) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('KYD', 'Cayman Islands Dollar', 'CI$', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('KZT', 'Kazakhstani Tenge', 'KZT', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('LAK', 'Laotian Kip', '₭N', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('LBP', 'Lebanese Pound', 'LB£', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('LKR', 'Sri Lankan Rupee', 'SLRs', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('LRD', 'Liberian Dollar', 'LD$', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('LSL', 'Lesotho Loti', 'L', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('LTL', 'Lithuanian Litas', 'Lt', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('LVL', 'Latvian Lats', 'Ls', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('LYD', 'Libyan Dinar', 'LD',3) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('MAD', 'Moroccan Dirham', 'MAD', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('MDL', 'Moldovan Leu', 'MDL', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('MGA', 'Malagasy Ariary', 'MGA', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('MKD', 'Macedonian Denar', 'MKD', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('MMK', 'Myanma Kyat', 'MMK', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('MNT', 'Mongolian Tugrik', '₮', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('MOP', 'Macanese Pataca', 'MOP$', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('MRO', 'Mauritanian ouguiya', 'UM', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('MUR', 'Mauritian Rupee', 'MURs', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('MVR', 'Maldivian Rufiyaa', 'MRf', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('MWK', 'Malawian Kwacha', 'MK', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('MXN', 'Mexican Peso', 'MX$', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('MYR', 'Malaysian Ringgit', 'RM', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('MZN', 'Mozambican Metical', 'MTn', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('NAD', 'Namibian Dollar', 'N$', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('NGN', 'Nigerian Naira', '₦', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('NIO', 'Nicaraguan Córdoba', 'C$', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('NOK', 'Norwegian Krone', 'Nkr', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('NPR', 'Nepalese Rupee', 'NPRs', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('NZD', 'New Zealand Dollar', 'NZ$', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('OMR', 'Omani Rial', 'OMR',3) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('PAB', 'Panamanian Balboa', 'B/.', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('PEN', 'Peruvian Nuevo Sol', 'S/.', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('PGK', 'Papua New Guinean Kina', 'K', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('PHP', 'Philippine Peso', '₱', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('PKR', 'Pakistani Rupee', 'PKRs', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('PLN', 'Polish Zloty', 'zł', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('PYG', 'Paraguayan Guarani', '₲', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('QAR', 'Qatari Rial', 'QR', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('RON', 'Romanian Leu', 'RON', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('RSD', 'Serbian Dinar', 'din.', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('RUB', 'Russian Ruble', 'RUB', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('RWF', 'Rwandan Franc', 'RWF', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('SAR', 'Saudi Riyal', 'SR', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('SBD', 'Solomon Islands Dollar', 'SI$', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('SCR', 'Seychellois Rupee', 'SRe', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('SDG', 'Sudanese Pound', 'SDG', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('SEK', 'Swedish Krona', 'Skr', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('SGD', 'Singapore Dollar', 'S$', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('SHP', 'Saint Helena Pound', '£', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('SLL', 'Sierra Leonean Leone', 'Le', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('SOS', 'Somali Shilling', 'Ssh', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('SRD', 'Surinamese Dollar', '$', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('STD', 'São Tomé and Príncipe dobra', 'Db', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('SVC', 'Salvadoran Colón', '₡', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('SYP', 'Syrian Pound', 'SY£', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('SZL', 'Swazi Lilangeni', 'L', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('THB', 'Thai Baht', '฿', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('TJS', 'Tajikistani Somoni', 'TJS', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('TMT', 'Turkmenistani Manat', 'T', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('TND', 'Tunisian Dinar', 'DT',3) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('TOP', 'Tongan Paʻanga', 'T$', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('TRY', 'Turkish Lira', 'TL', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('TTD', 'Trinidad and Tobago Dollar', 'TT$', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('TWD', 'New Taiwan Dollar', 'NT$', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('TZS', 'Tanzanian Shilling', 'TSh', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('UAH', 'Ukrainian Hryvnia', '₴', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('UGX', 'Ugandan Shilling', 'USh', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('USD', 'US Dollar', '$', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('UYU', 'Uruguayan Peso', '$U', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('UZS', 'Uzbekistan Som', 'UZS', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('VEF', 'Venezuelan Bolívar', 'Bs.F.', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('VND', 'Vietnamese Dong', '₫', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('VUV', 'Vanuatu Vatu', 'VUV', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('WST', 'Samoan Tala', 'WS$', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('XAF', 'CFA Franc BEAC', 'FCFA', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('XAG', 'Silver Ounce', 'XAG', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('XAU', 'Gold Ounce', 'XAU', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('XCD', 'East Caribbean Dollar', 'EC$', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('XDR', 'Special drawing rights', 'SDR', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('XOF', 'CFA Franc BCEAO', 'CFA', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('XPF', 'CFP Franc', 'CFP', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('YER', 'Yemeni Rial', 'YR', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('ZAR', 'South African Rand', 'R', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('ZMK', 'Zambian Kwacha', 'ZK', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('ZMW', 'Zambian Kwacha', 'ZK', 0) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('ZWL', 'Zimbabwean dollar', 'ZWL', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('XPT', 'Platinum Ounce', 'XPT',6) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('XPD', 'Palladium Ounce', 'XPD',6) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('BTC', 'Bitcoin', '₿',8) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('ETH', 'Ethereum', 'Ξ',18) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('BNB', 'Binance', 'BNB',8) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('XRP', 'Ripple', 'XRP',6) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('SOL', 'Solana', 'SOL',9) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('DOT', 'Polkadot', 'DOT',10) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('AVAX', 'Avalanche', 'AVAX',18) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('MATIC', 'Matic Token', 'MATIC',18) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('LTC', 'Litecoin', 'Ł',8) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('ADA', 'Cardano', 'ADA',6) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('USDT', 'Tether', 'USDT', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('USDC', 'USD Coin', 'USDC', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('DAI', 'Dai', 'DAI', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('ARB', 'Arbitrum', 'ARB',8) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('OP', 'Optimism', 'OP',8) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('VES', 'Venezuelan Bolívar', 'Bs.S.', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('STN', 'São Tomé and Príncipe dobra', 'STN', 2) ON CONFLICT (code) DO NOTHING; +INSERT INTO currency (code, name, symbol, decimal_digits) VALUES ('MRU', 'Mauritanian ouguiya', 'MRU', 2) ON CONFLICT (code) DO NOTHING; + +-- Insert exchange rates into the rate table +-- These inserts will not execute if the rate with the same currency_id already exists +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 2.2679298487, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'ADA' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 3.6718406559, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'AED' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 70.7904573332, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'AFN' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 93.0320944204, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'ALL' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 387.0652417589, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'AMD' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 1.787280302, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'ANG' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 851.5743892967, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'AOA' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 1.0411768981, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'ARB' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 901.9165772212, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'ARS' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 1.5132802995, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'AUD' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 0.0309532227, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'AVAX' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 1.79, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'AWG' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 1.7, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'AZN' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 1.8167003404, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'BAM' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 2, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'BBD' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 117.5903174764, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'BDT' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 1.812830352, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'BGN' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 0.376, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'BHD' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 2874.4080899246, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'BIF' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 1, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'BMD' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 0.0015946085, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'BNB' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 1.3515501742, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'BND' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 6.9369912102, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'BOB' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 5.3570006385, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'BRL' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 1, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'BSD' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 1.43517e-5, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'BTC' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 83.5026750681, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'BTN' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 13.7488325074, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'BWP' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 3.2699770637, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'BYN' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 32699.762594218, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'BYR' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 2, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'BZD' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 1.3758702027, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'CAD' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 2813.442771238, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'CDF' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 0.8965300987, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'CHF' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 0.0242000032, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'CLF' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 921.0413972452, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'CLP' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 7.2501309285, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'CNY' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 3937.3301467823, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'COP' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 530.3078152726, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'CRC' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 1, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'CUC' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 24, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'CUP' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 102.4397237684, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'CVE' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 22.8602433711, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'CZK' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 0.9992989749, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'DAI' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 177.721, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'DJF' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 6.9279413087, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'DKK' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 59.4084267105, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'DOP' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 0.1535316848, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'DOT' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 134.9637578508, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'DZD' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 47.718617933, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'EGP' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 15, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'ERN' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 56.9702884224, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'ETB' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 0.0002724481, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'ETH' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 0.9290801473, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'EUR' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 2.2394803828, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'FJD' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 0.7857969946, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'FKP' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 0.7857400856, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'GBP' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 2.8200704628, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'GEL' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 0.7857970595, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'GGP' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 14.9096017346, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'GHS' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 0.7857973594, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'GIP' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 58.2027859377, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'GMD' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 8587.8742589067, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'GNF' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 7.758281421, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'GTQ' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 209.1970978965, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'GYD' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 7.8103013923, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'HKD' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 24.7146626422, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'HNL' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 6.6516508793, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'HRK' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 134.7838194535, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'HTG' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 364.8563849752, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'HUF' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 16267.59254452, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'IDR' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 3.7498404871, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'ILS' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 0.78579737, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'IMP' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 83.5191700278, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'INR' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 1308.6456434348, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'IQD' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 42019.979875943, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'IRR' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 139.2122370989, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'ISK' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 0.7857974327, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'JEP' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 155.2491448209, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'JMD' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 0.71, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'JOD' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 157.014696987, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'JPY' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 129.3930234152, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'KES' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 86.7532661567, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'KGS' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 4112.3295097742, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'KHR' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 458.5398427806, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'KMF' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 900.002639873, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'KPW' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 1372.7226101559, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'KRW' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 0.3068600384, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'KWD' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 0.83333, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'KYD' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 448.5436886523, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'KZT' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 21719.745960039, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'LAK' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 89589.77614652, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'LBP' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 301.8763925636, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'LKR' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 194.250797033, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'LRD' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 18.740072297, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'LSL' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 0.012540671, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'LTC' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 3.2079216576, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'LTL' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 0.6529558367, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'LVL' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 4.8691905541, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'LYD' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 9.9428813366, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'MAD' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 1.5370217613, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'MATIC' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 17.6269922085, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'MDL' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 4480.2747953954, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'MGA' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 57.3124669066, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'MKD' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 2095.624577851, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'MMK' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 3399.6088715777, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'MNT' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 8.0643411333, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'MOP' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 356.999828, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'MRO' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 39.5001473678, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'MRU' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 46.5937585965, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'MUR' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 15.4579725536, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'MVR' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 1734.397497359, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'MWK' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 18.55754282, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'MXN' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 4.7216406039, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'MYR' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 63.6050485402, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'MZN' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 18.6629134402, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'NAD' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 1465.9738916374, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'NGN' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 36.7972487975, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'NIO' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 10.6432812966, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'NOK' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 133.0858524888, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'NPR' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 1.6312602969, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'NZD' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 0.3842500724, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'OMR' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 0.4569196376, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'OP' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 0.9988701052, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'PAB' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 3.7826704942, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'PEN' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 3.8124903888, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'PGK' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 58.7150182203, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'PHP' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 278.478689251, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'PKR' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 4.0171006006, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'PLN' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 7551.7849655727, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'PYG' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 3.6411907088, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'QAR' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 4.6227706077, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'RON' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 108.3531882033, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'RSD' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 88.8936112341, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'RUB' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 1301.7783053399, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'RWF' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 3.7456707423, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'SAR' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 8.3580865701, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'SBD' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 14.8189315961, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'SCR' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 601.5, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'SDG' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 10.476081969, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'SEK' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 1.3524701839, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'SGD' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 0.7857401163, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'SHP' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 22424.082202439, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'SLL' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 0.0062829578, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'SOL' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 571.0236810379, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'SOS' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 31.4496958362, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'SRD' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 22799.367791132, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'STD' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 22.7993551837, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'STN' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 8.75, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'SVC' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 12994.621714013, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'SYP' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 18.6989824867, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'SZL' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 36.7206552011, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'THB' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 10.7309711957, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'TJS' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 3.5, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'TMT' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 3.1210104046, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'TND' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 2.341250381, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'TOP' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 32.3123541442, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'TRY' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 6.7413709853, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'TTD' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 32.4375140234, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'TWD' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 2593.4598939473, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'TZS' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 40.3861148848, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'UAH' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 3793.8622299526, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'UGX' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 1, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'USD' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 0.9995108127, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'USDC' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 0.9993678097, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'USDT' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 38.8978562435, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'UYU' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 12668.129512123, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'UZS' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 3640407.7001116, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'VEF' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 36.4040600039, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'VES' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 25421.433686036, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'VND' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 119.9011334188, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'VUV' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 2.7389439335, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'WST' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 609.3574609173, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'XAF' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 0.033659259, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'XAG' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 0.0004329255, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'XAU' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 2.7, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'XCD' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 0.7558400986, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'XDR' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 609.3574713759, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'XOF' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 0.0011018596, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'XPD' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 110.7528319197, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'XPF' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 0.001027921, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'XPT' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 2.0094059521, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'XRP' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 249.9532931212, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'YER' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 18.7007830651, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'ZAR' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 9001.2, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'ZMK' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 26.4433644143, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'ZMW' ON CONFLICT (currency_id, updated_at) DO NOTHING; +INSERT INTO rate (currency_id, rate, updated_at) SELECT c.id, 13.541264135, '2024-06-10T23:59:59Z' FROM currency c WHERE c.code = 'ZWL' ON CONFLICT (currency_id, updated_at) DO NOTHING; \ No newline at end of file diff --git a/jest.config.ts b/jest.config.ts new file mode 100644 index 000000000..79d1967cb --- /dev/null +++ b/jest.config.ts @@ -0,0 +1,11 @@ +import type { Config } from 'jest'; + +const config: Config = { + preset: 'ts-jest', + testEnvironment: 'node', + moduleNameMapper: { + '^@/(.*)$': '/src/$1', + }, +}; + +export default config; diff --git a/package.json b/package.json new file mode 100644 index 000000000..af331312a --- /dev/null +++ b/package.json @@ -0,0 +1,44 @@ +{ + "name": "challenge-bravo", + "version": "1.0.0", + "main": "src/index.js", + "repository": "https://github.com/hurbcom/challenge-bravo.git", + "author": "Leandro Reis ", + "license": "MIT", + "scripts": { + "start": "ts-node -r tsconfig-paths/register src/main/main.ts", + "dev": "ts-node-dev -r tsconfig-paths/register src/main/main.ts", + "dev:express+fake": "ts-node-dev -r tsconfig-paths/register src/main/main-express-with-fake.ts", + "dev:express+gw-off": "ts-node-dev -r tsconfig-paths/register src/main/main-express-gateway-offline.ts", + "dev:express+gw-on": "ts-node-dev -r tsconfig-paths/register src/main/main-express-gateway-online.ts", + "dev:hapi+fake": "ts-node-dev -r tsconfig-paths/register src/main/main-hapi-with-fake.ts", + "test": "jest --detectOpenHandles", + "test:watch": "jest --watch --detectOpenHandles" + }, + "dependencies": { + "@hapi/hapi": "^21.3.9", + "axios": "^1.7.2", + "crypto": "^1.0.1", + "currency.js": "^2.0.4", + "dotenv": "^16.4.5", + "express": "^4.19.2", + "pg-promise": "^11.8.0", + "swagger-ui-express": "^5.0.1" + }, + "devDependencies": { + "@eslint/js": "^9.4.0", + "@types/express": "^4.17.21", + "@types/jest": "^29.5.12", + "@types/swagger-ui-express": "^4.1.6", + "eslint": "9.x", + "eslint-config-prettier": "^9.1.0", + "jest": "^29.7.0", + "prettier": "3.3.2", + "ts-jest": "^29.1.4", + "ts-node": "^10.9.2", + "ts-node-dev": "^2.0.0", + "tsconfig-paths": "^4.2.0", + "typescript": "^5.4.5", + "typescript-eslint": "^7.13.0" + } +} diff --git a/pull-request.txt b/pull-request.txt index 4eae37418..e4719f04e 100644 --- a/pull-request.txt +++ b/pull-request.txt @@ -1,3 +1,3 @@ -Your name: ___ -Your Github homepage: ___ -Original challenge URL: http://github.com/hurbcom/challenge-___ +Your name: Leandro Reis +Your Github homepage: https://github.com/leandroepr +Original challenge URL: https://github.com/hurbcom/challenge-bravo diff --git a/src/application/query/get-currency-by-code-query.ts b/src/application/query/get-currency-by-code-query.ts new file mode 100644 index 000000000..375217a59 --- /dev/null +++ b/src/application/query/get-currency-by-code-query.ts @@ -0,0 +1,44 @@ +import { CurrencyNotFoundError } from '@/domain/errors'; +import { DatabaseConnection } from '@/infra/database'; + +export class GetCurrencyByCodeQuery { + constructor(private readonly connection: DatabaseConnection) {} + + async execute({ code }: Input): Promise { + const [row] = await this.connection.query( + ` + SELECT c.id, c.name, c.code, c.symbol, c.decimal_digits, r.rate + FROM currency c + JOIN rate r ON c.id = r.currency_id + WHERE c.code = $1 + ORDER BY r.updated_at DESC + LIMIT 1 + `, + [code] + ); + if (!row) { + throw new CurrencyNotFoundError(code); + } + return { + id: row.currency_id, + name: row.name, + code: row.code, + symbol: row.symbol, + decimalDigits: row.decimal_digits, + rate: Number(row.rate), + }; + } +} + +type Input = { + code: string; +}; + +type Output = { + id: string; + name: string; + code: string; + symbol: string; + decimalDigits: number; + rate: number; +}; diff --git a/src/application/query/index.ts b/src/application/query/index.ts new file mode 100644 index 000000000..b8b508a36 --- /dev/null +++ b/src/application/query/index.ts @@ -0,0 +1,2 @@ +export * from './get-currency-by-code-query'; +export * from './list-currencies-query'; diff --git a/src/application/query/list-currencies-query.ts b/src/application/query/list-currencies-query.ts new file mode 100644 index 000000000..7681ea940 --- /dev/null +++ b/src/application/query/list-currencies-query.ts @@ -0,0 +1,99 @@ +import { DatabaseConnection } from '@/infra/database'; + +export class ListCurrenciesQuery { + constructor(private readonly connection: DatabaseConnection) {} + + async execute({ + currencies, + page, + perPage: pageSize, + sortBy, + sortOrder, + }: Filters): Promise { + const rows = await this.connection.query( + ` + WITH latest_rates AS ( + SELECT + r.id, + r.currency_id, + r.rate, + r.updated_at, + ROW_NUMBER() OVER (PARTITION BY r.currency_id ORDER BY r.updated_at DESC) AS rn + FROM + rate r + ) + SELECT + c.id AS currency_id, + c.code, + c.name, + c.symbol, + c.decimal_digits, + lr.rate, + lr.updated_at, + COUNT(*) OVER() AS total_records + FROM + currency c + JOIN + latest_rates lr ON c.id = lr.currency_id + WHERE + lr.rn = 1 + AND ($1::text[] IS NULL OR c.code = ANY($1::text[])) + ORDER BY + CASE WHEN $2::text = 'name' THEN c.name END, + CASE WHEN $2::text = 'code' THEN c.code END, + CASE WHEN $2::text = 'rate' THEN lr.rate END, + $3::text + LIMIT $4 OFFSET (($5 - 1) * $4); + `, + [ + currencies?.length ? currencies : null, + sortBy, + sortOrder, + pageSize, + page, + ] + ); + const totalRecords = Number(rows[0].total_records); + return { + meta: { + page, + perPage: pageSize, + pageCount: Math.ceil(totalRecords / pageSize), + totalCount: totalRecords, + }, + data: rows.map((row: any) => ({ + id: row.currency_id, + name: row.name, + code: row.code, + symbol: row.symbol, + decimalDigits: row.decimal_digits, + rate: Number(row.rate), + })), + }; + } +} + +type Filters = { + currencies: string[]; // BRL, USD, EUR (default all) + page: number; // 1 (default 1) + perPage: number; // 10 - 100 (default 10) + sortBy: 'name' | 'code' | 'rate'; // name (default name) + sortOrder: 'asc' | 'desc'; // asc (default asc) +}; + +type Output = { + meta: { + page: number; + perPage: number; + pageCount: number; + totalCount: number; + }; + data: Array<{ + id: string; + name: string; + code: string; + symbol: string; + decimalDigits: number; + rate: number; + }>; +}; diff --git a/src/application/repository/currency-rate-repository.ts b/src/application/repository/currency-rate-repository.ts new file mode 100644 index 000000000..7a89466cb --- /dev/null +++ b/src/application/repository/currency-rate-repository.ts @@ -0,0 +1,9 @@ +import { type CurrencyRate } from '@/domain/entity/'; + +export interface CurrencyRateRepository { + findByCode: (code: string) => Promise; + add: (currencyRate: CurrencyRate) => Promise; + delete: (code: string) => Promise; +} + +export default CurrencyRateRepository; diff --git a/src/application/repository/index.ts b/src/application/repository/index.ts new file mode 100644 index 000000000..a7be7add5 --- /dev/null +++ b/src/application/repository/index.ts @@ -0,0 +1 @@ +export * from './currency-rate-repository'; diff --git a/src/application/service/equivalent-rate-calculator.ts b/src/application/service/equivalent-rate-calculator.ts new file mode 100644 index 000000000..0f2a64f29 --- /dev/null +++ b/src/application/service/equivalent-rate-calculator.ts @@ -0,0 +1,19 @@ +import { InvalidParamError } from '@/domain/errors'; + +export class EquivalentRateCalculator { + constructor(readonly equivalentCurrencyRate: number) {} + + calculateRate(baseAmount: number, equivalentCurrencyAmount: number): number { + if (baseAmount <= 0) { + throw new InvalidParamError('Invalid param: baseAmount'); + } + if (equivalentCurrencyAmount <= 0) { + throw new InvalidParamError('Invalid param: equivalentCurrencyAmount'); + } + const rate = + (baseAmount / equivalentCurrencyAmount) * this.equivalentCurrencyRate; + return rate; + } +} + +export default EquivalentRateCalculator; diff --git a/src/application/service/index.ts b/src/application/service/index.ts new file mode 100644 index 000000000..0002d585b --- /dev/null +++ b/src/application/service/index.ts @@ -0,0 +1 @@ +export * from './equivalent-rate-calculator'; diff --git a/src/application/use-case/convert-currency.ts b/src/application/use-case/convert-currency.ts new file mode 100644 index 000000000..e2455303d --- /dev/null +++ b/src/application/use-case/convert-currency.ts @@ -0,0 +1,32 @@ +import { CurrencyRateRepository } from '@/application/repository'; + +export class ConvertCurrency { + constructor(readonly currencyRateRepository: CurrencyRateRepository) {} + + async execute(input: ConvertCurrencyDto): Promise { + const exchangeFrom = await this.currencyRateRepository.findByCode( + input.from + ); + const exchangeTo = await this.currencyRateRepository.findByCode(input.to); + const convertedAmount = exchangeFrom.convertTo(exchangeTo, input.amount); + return { + value: convertedAmount, + symbol: exchangeTo.symbol, + decimalDigits: exchangeTo.decimalDigits, + }; + } +} + +export type ConvertCurrencyDto = { + from: string; + to: string; + amount: number; +}; + +export type ConvertCurrencyResponse = { + value: number; + symbol: string; + decimalDigits: number; +}; + +export default ConvertCurrency; diff --git a/src/application/use-case/create-currency-rate.ts b/src/application/use-case/create-currency-rate.ts new file mode 100644 index 000000000..fef74f4ea --- /dev/null +++ b/src/application/use-case/create-currency-rate.ts @@ -0,0 +1,47 @@ +import { CurrencyRateRepository } from '@/application/repository'; +import { EquivalentRateCalculator } from '@/application/service'; +import { CurrencyRate } from '@/domain/entity/'; + +export class CreateCurrencyRate { + constructor(private currencyRateRepository: CurrencyRateRepository) {} + + async execute( + input: CreateCurrencyRateDto + ): Promise { + const equivalentCurrencyRate = await this.currencyRateRepository.findByCode( + input.equivalentCurrencyCode.toUpperCase() + ); + const equivalentRateCalculator = new EquivalentRateCalculator( + equivalentCurrencyRate.rate + ); + const rate = equivalentRateCalculator.calculateRate( + input.baseAmount, + input.equivalentCurrencyAmount + ); + const currencyRate = CurrencyRate.create( + input.name, + input.code, + input.symbol, + input.decimalDigits, + rate + ); + await this.currencyRateRepository.add(currencyRate); + return { currencyRateId: currencyRate.id }; + } +} + +export type CreateCurrencyRateDto = { + name: string; + symbol: string; + code: string; + decimalDigits: number; + baseAmount: number; + equivalentCurrencyCode: string; + equivalentCurrencyAmount: number; +}; + +export type CreateCurrencyRateOutput = { + currencyRateId: string; +}; + +export default CreateCurrencyRate; diff --git a/src/application/use-case/delete-currency-rate-by-code.ts b/src/application/use-case/delete-currency-rate-by-code.ts new file mode 100644 index 000000000..d3bbf6fc1 --- /dev/null +++ b/src/application/use-case/delete-currency-rate-by-code.ts @@ -0,0 +1,21 @@ +import { CurrencyRateRepository } from '@/application/repository'; +import { CurrencyNotFoundError } from '@/domain/errors'; + +export class DeleteCurrencyRateByCode { + constructor( + private readonly currencyRateRepository: CurrencyRateRepository + ) {} + + async execute(code: string): Promise { + if (code === 'USD') { + throw new Error('Cannot delete USD currency rate'); + } + const currencyRate = await this.currencyRateRepository.findByCode(code); + if (!currencyRate) { + throw new CurrencyNotFoundError(code); + } + await this.currencyRateRepository.delete(currencyRate.code); + } +} + +export default DeleteCurrencyRateByCode; diff --git a/src/application/use-case/get-currency-rate-by-code.ts b/src/application/use-case/get-currency-rate-by-code.ts new file mode 100644 index 000000000..bb98e8ab1 --- /dev/null +++ b/src/application/use-case/get-currency-rate-by-code.ts @@ -0,0 +1,30 @@ +import { CurrencyRateRepository } from '@/application/repository'; + +export class GetCurrencyRateByCode { + constructor(readonly currencyRateRepository: CurrencyRateRepository) {} + + async execute(code: string): Promise { + const currencyRate = await this.currencyRateRepository.findByCode( + code.toUpperCase() + ); + return { + id: currencyRate.id, + name: currencyRate.name, + code: currencyRate.code, + symbol: currencyRate.symbol, + decimalDigits: currencyRate.decimalDigits, + rate: currencyRate.rate, + }; + } +} + +export type GetCurrencyRateByCodeOutput = { + id: string; + name: string; + code: string; + symbol: string; + decimalDigits: number; + rate: number; +}; + +export default GetCurrencyRateByCode; diff --git a/src/application/use-case/index.ts b/src/application/use-case/index.ts new file mode 100644 index 000000000..defdfbe56 --- /dev/null +++ b/src/application/use-case/index.ts @@ -0,0 +1,4 @@ +export * from './convert-currency'; +export * from './create-currency-rate'; +export * from './delete-currency-rate-by-code'; +export * from './get-currency-rate-by-code'; diff --git a/src/domain/entity/currency-rate.ts b/src/domain/entity/currency-rate.ts new file mode 100644 index 000000000..4165aaff4 --- /dev/null +++ b/src/domain/entity/currency-rate.ts @@ -0,0 +1,77 @@ +import currency from 'currency.js'; + +import { InvalidParamError } from '@/domain/errors'; +import { + Code, + DecimalDigits, + Symbol as MySymbol, + Name, + Rate, +} from '@/domain/value-object'; + +export class CurrencyRate { + private _name: Name; + private _code: Code; + private _symbol: MySymbol; + private _decimalPoints: DecimalDigits; + private _rate: Rate; + + constructor( + readonly id: string, + name: string, + code: string, + symbol: string, + decimalDigits: number, + rate: number + ) { + this._name = new Name(name); + this._code = new Code(code); + this._symbol = new MySymbol(symbol); + this._decimalPoints = new DecimalDigits(decimalDigits); + this._rate = new Rate(rate); + } + + static create( + name: string, + code: string, + symbol: string, + decimalDigits: number, + rate: number + ): CurrencyRate { + const id = crypto.randomUUID(); + return new CurrencyRate(id, name, code, symbol, decimalDigits, rate); + } + + get name(): string { + return this._name.value; + } + + get code(): string { + return this._code.value; + } + + get symbol(): string { + return this._symbol.value; + } + + get decimalDigits(): number { + return this._decimalPoints.value; + } + + get rate(): number { + return this._rate.value; + } + + convertTo(currencyRate: CurrencyRate, amount: number): number { + if (amount < 0) { + throw new InvalidParamError('Invalid amount'); + } + const convertedAmount = (amount * currencyRate.rate) / this.rate; + const amountCurrency = currency(convertedAmount, { + precision: currencyRate.decimalDigits, + }); + return amountCurrency.value; + } +} + +export default CurrencyRate; diff --git a/src/domain/entity/index.ts b/src/domain/entity/index.ts new file mode 100644 index 000000000..8d2059e7a --- /dev/null +++ b/src/domain/entity/index.ts @@ -0,0 +1 @@ +export * from './currency-rate'; diff --git a/src/domain/errors/currency-not-found.error.ts b/src/domain/errors/currency-not-found.error.ts new file mode 100644 index 000000000..d6d084ad2 --- /dev/null +++ b/src/domain/errors/currency-not-found.error.ts @@ -0,0 +1,10 @@ +import NotFoundError from './not-found.error'; + +export class CurrencyNotFoundError extends NotFoundError { + constructor(currencyRateIdOrCode: string) { + super(`Currency not found: ${currencyRateIdOrCode}`); + this.name = 'CurrencyNotFoundError'; + } +} + +export default CurrencyNotFoundError; diff --git a/src/domain/errors/index.ts b/src/domain/errors/index.ts new file mode 100644 index 000000000..8bdc60ab1 --- /dev/null +++ b/src/domain/errors/index.ts @@ -0,0 +1,3 @@ +export * from './currency-not-found.error'; +export * from './invalid-param.error'; +export * from './not-found.error'; diff --git a/src/domain/errors/invalid-param.error.ts b/src/domain/errors/invalid-param.error.ts new file mode 100644 index 000000000..7304e0340 --- /dev/null +++ b/src/domain/errors/invalid-param.error.ts @@ -0,0 +1,8 @@ +export class InvalidParamError extends Error { + constructor(message: string) { + super(message); + this.name = 'InvalidParamsError'; + } +} + +export default InvalidParamError; diff --git a/src/domain/errors/not-found.error.ts b/src/domain/errors/not-found.error.ts new file mode 100644 index 000000000..5f01ef096 --- /dev/null +++ b/src/domain/errors/not-found.error.ts @@ -0,0 +1,8 @@ +export class NotFoundError extends Error { + constructor(message: string) { + super(message); + this.name = 'NotFoundError'; + } +} + +export default NotFoundError; diff --git a/src/domain/value-object/code.ts b/src/domain/value-object/code.ts new file mode 100644 index 000000000..4c4d75f5d --- /dev/null +++ b/src/domain/value-object/code.ts @@ -0,0 +1,18 @@ +import { InvalidParamError } from '../errors'; + +export class Code { + private _value: string; + + constructor(value: string) { + if (value.length < 3 || value.length > 4) { + throw new InvalidParamError('Invalid code'); + } + this._value = value.toUpperCase(); + } + + get value() { + return this._value; + } +} + +export default Code; diff --git a/src/domain/value-object/decimal-digits.ts b/src/domain/value-object/decimal-digits.ts new file mode 100644 index 000000000..571dd8304 --- /dev/null +++ b/src/domain/value-object/decimal-digits.ts @@ -0,0 +1,18 @@ +import { InvalidParamError } from '../errors'; + +export class DecimalDigits { + private _value: number; + + constructor(value: number) { + if (value < 0 || value > 10) { + throw new InvalidParamError('Invalid decimal digits'); + } + this._value = value; + } + + get value() { + return this._value; + } +} + +export default DecimalDigits; diff --git a/src/domain/value-object/index.ts b/src/domain/value-object/index.ts new file mode 100644 index 000000000..f24e02caf --- /dev/null +++ b/src/domain/value-object/index.ts @@ -0,0 +1,5 @@ +export * from './code'; +export * from './decimal-digits'; +export * from './name'; +export * from './rate'; +export * from './symbol'; diff --git a/src/domain/value-object/name.ts b/src/domain/value-object/name.ts new file mode 100644 index 000000000..7845f4514 --- /dev/null +++ b/src/domain/value-object/name.ts @@ -0,0 +1,18 @@ +import { InvalidParamError } from '../errors'; + +export class Name { + private _value: string; + + constructor(value: string) { + if (value.length < 3 || value.length > 100) { + throw new InvalidParamError('Invalid name'); + } + this._value = value; + } + + get value() { + return this._value; + } +} + +export default Name; diff --git a/src/domain/value-object/rate.ts b/src/domain/value-object/rate.ts new file mode 100644 index 000000000..b3a756cf3 --- /dev/null +++ b/src/domain/value-object/rate.ts @@ -0,0 +1,18 @@ +import { InvalidParamError } from '../errors'; + +export class Rate { + private _value: number; + + constructor(value: number) { + if (value <= 0) { + throw new InvalidParamError('Invalid rate'); + } + this._value = value; + } + + get value() { + return this._value; + } +} + +export default Rate; diff --git a/src/domain/value-object/symbol.ts b/src/domain/value-object/symbol.ts new file mode 100644 index 000000000..5a61e5a22 --- /dev/null +++ b/src/domain/value-object/symbol.ts @@ -0,0 +1,18 @@ +import { InvalidParamError } from '../errors'; + +export class Symbol { + private _value: string; + + constructor(value: string) { + if (value.length < 1 || value.length > 5) { + throw new InvalidParamError('Invalid symbol'); + } + this._value = value; + } + + get value() { + return this._value; + } +} + +export default Symbol; diff --git a/src/env.ts b/src/env.ts new file mode 100644 index 000000000..01428cc8f --- /dev/null +++ b/src/env.ts @@ -0,0 +1,21 @@ +import dotenv from 'dotenv'; + +dotenv.config(); + +const HTTP_SERVER_PORT = Number(process.env.HTTP_SERVER_PORT || 3000); +const DATABASE_URL = process.env.DATABASE_URL; +if (!DATABASE_URL) { + throw new Error('DATABASE_URL is not set'); +} +const CURRENCYAPI_API_KEY = process.env.CURRENCYAPI_API_KEY; +if (!CURRENCYAPI_API_KEY) { + throw new Error('CURRENCYAPI_API_KEY is not set'); +} + +export const env = { + HTTP_SERVER_PORT, + DATABASE_URL, + CURRENCYAPI_API_KEY, +}; + +export default env; diff --git a/src/infra/database/database-connection.ts b/src/infra/database/database-connection.ts new file mode 100644 index 000000000..afcb2c5df --- /dev/null +++ b/src/infra/database/database-connection.ts @@ -0,0 +1,9 @@ +export interface DatabaseConnection { + query( + statement: string, + params: TParams + ): Promise; + close(): Promise; +} + +export default DatabaseConnection; diff --git a/src/infra/database/index.ts b/src/infra/database/index.ts new file mode 100644 index 000000000..07833bbea --- /dev/null +++ b/src/infra/database/index.ts @@ -0,0 +1,2 @@ +export * from './database-connection'; +export * from './pgpromise-adapter'; diff --git a/src/infra/database/pgpromise-adapter.ts b/src/infra/database/pgpromise-adapter.ts new file mode 100644 index 000000000..37030b29d --- /dev/null +++ b/src/infra/database/pgpromise-adapter.ts @@ -0,0 +1,22 @@ +import env from '@/env'; +import { DatabaseConnection } from '@/infra/database'; + +import pgp from 'pg-promise'; + +export class PgPromiseAdapter implements DatabaseConnection { + connection: any; + + constructor() { + this.connection = pgp()(env.DATABASE_URL); + } + + query(statement: string, params: any): Promise { + return this.connection.query(statement, params); + } + + close(): Promise { + return this.connection.$pool.end(); + } +} + +export default PgPromiseAdapter; diff --git a/src/infra/gateway/api.currencyapi-v3-currencies.json b/src/infra/gateway/api.currencyapi-v3-currencies.json new file mode 100644 index 000000000..d75d5c2ea --- /dev/null +++ b/src/infra/gateway/api.currencyapi-v3-currencies.json @@ -0,0 +1,2162 @@ +{ + "data": { + "AED": { + "symbol": "AED", + "name": "United Arab Emirates Dirham", + "symbol_native": "د.إ", + "decimal_digits": 2, + "rounding": 0, + "code": "AED", + "name_plural": "UAE dirhams", + "type": "fiat", + "countries": ["AE"] + }, + "AFN": { + "symbol": "Af", + "name": "Afghan Afghani", + "symbol_native": "؋", + "decimal_digits": 0, + "rounding": 0, + "code": "AFN", + "name_plural": "Afghan Afghanis", + "type": "fiat", + "countries": ["AF"] + }, + "ALL": { + "symbol": "ALL", + "name": "Albanian Lek", + "symbol_native": "Lek", + "decimal_digits": 0, + "rounding": 0, + "code": "ALL", + "name_plural": "Albanian lekë", + "type": "fiat", + "countries": ["AL"] + }, + "AMD": { + "symbol": "AMD", + "name": "Armenian Dram", + "symbol_native": "դր.", + "decimal_digits": 0, + "rounding": 0, + "code": "AMD", + "name_plural": "Armenian drams", + "type": "fiat", + "countries": ["AM"] + }, + "ANG": { + "symbol": "ƒ", + "name": "NL Antillean Guilder", + "symbol_native": "NAƒ", + "decimal_digits": 2, + "rounding": 0, + "code": "ANG", + "icon_name": "ang", + "name_plural": "NL Antillean Guilders", + "type": "fiat", + "countries": ["CW", "SX"] + }, + "AOA": { + "symbol": "Kz", + "name": "Angolan Kwanza", + "symbol_native": "Kz", + "decimal_digits": 2, + "rounding": 0, + "code": "AOA", + "icon_name": "aoa", + "name_plural": "Angolan Kwanza", + "type": "fiat", + "countries": ["AO"] + }, + "ARS": { + "symbol": "AR$", + "name": "Argentine Peso", + "symbol_native": "$", + "decimal_digits": 2, + "rounding": 0, + "code": "ARS", + "name_plural": "Argentine pesos", + "type": "fiat", + "countries": ["AR"] + }, + "AUD": { + "symbol": "AU$", + "name": "Australian Dollar", + "symbol_native": "$", + "decimal_digits": 2, + "rounding": 0, + "code": "AUD", + "name_plural": "Australian dollars", + "type": "fiat", + "countries": ["AU", "CC", "CX", "HM", "KI", "NF", "NR", "TV"] + }, + "AWG": { + "symbol": "Afl.", + "name": "Aruban Florin", + "symbol_native": "Afl.", + "decimal_digits": 2, + "rounding": 0, + "code": "AWG", + "icon_name": "awg", + "name_plural": "Aruban Florin", + "type": "fiat", + "countries": ["AW"] + }, + "AZN": { + "symbol": "man.", + "name": "Azerbaijani Manat", + "symbol_native": "ман.", + "decimal_digits": 2, + "rounding": 0, + "code": "AZN", + "name_plural": "Azerbaijani manats", + "type": "fiat", + "countries": ["AZ"] + }, + "BAM": { + "symbol": "KM", + "name": "Bosnia-Herzegovina Convertible Mark", + "symbol_native": "KM", + "decimal_digits": 2, + "rounding": 0, + "code": "BAM", + "name_plural": "Bosnia-Herzegovina convertible marks", + "type": "fiat", + "countries": ["BA"] + }, + "BBD": { + "symbol": "Bds$", + "name": "Barbadian Dollar", + "symbol_native": "$", + "decimal_digits": 2, + "rounding": 0, + "code": "BBD", + "icon_name": "bbd", + "name_plural": "Barbadian Dollars", + "type": "fiat", + "countries": ["BB"] + }, + "BDT": { + "symbol": "Tk", + "name": "Bangladeshi Taka", + "symbol_native": "৳", + "decimal_digits": 2, + "rounding": 0, + "code": "BDT", + "name_plural": "Bangladeshi takas", + "type": "fiat", + "countries": ["BD"] + }, + "BGN": { + "symbol": "BGN", + "name": "Bulgarian Lev", + "symbol_native": "лв.", + "decimal_digits": 2, + "rounding": 0, + "code": "BGN", + "name_plural": "Bulgarian leva", + "type": "fiat", + "countries": ["BG"] + }, + "BHD": { + "symbol": "BD", + "name": "Bahraini Dinar", + "symbol_native": "د.ب.‏", + "decimal_digits": 3, + "rounding": 0, + "code": "BHD", + "name_plural": "Bahraini dinars", + "type": "fiat", + "countries": ["BH"] + }, + "BIF": { + "symbol": "FBu", + "name": "Burundian Franc", + "symbol_native": "FBu", + "decimal_digits": 0, + "rounding": 0, + "code": "BIF", + "name_plural": "Burundian francs", + "type": "fiat", + "countries": ["BI"] + }, + "BMD": { + "symbol": "BD$", + "name": "Bermudan Dollar", + "symbol_native": "$", + "decimal_digits": 2, + "rounding": 0, + "code": "BMD", + "icon_name": "bmd", + "name_plural": "Bermudan Dollars", + "type": "fiat", + "countries": ["BM"] + }, + "BND": { + "symbol": "BN$", + "name": "Brunei Dollar", + "symbol_native": "$", + "decimal_digits": 2, + "rounding": 0, + "code": "BND", + "name_plural": "Brunei dollars", + "type": "fiat", + "countries": ["BN"] + }, + "BOB": { + "symbol": "Bs", + "name": "Bolivian Boliviano", + "symbol_native": "Bs", + "decimal_digits": 2, + "rounding": 0, + "code": "BOB", + "name_plural": "Bolivian bolivianos", + "type": "fiat", + "countries": ["BO"] + }, + "BRL": { + "symbol": "R$", + "name": "Brazilian Real", + "symbol_native": "R$", + "decimal_digits": 2, + "rounding": 0, + "code": "BRL", + "name_plural": "Brazilian reals", + "type": "fiat", + "countries": ["BR"] + }, + "BSD": { + "symbol": "B$", + "name": "Bahamian Dollar", + "symbol_native": "$", + "decimal_digits": 2, + "rounding": 0, + "code": "BSD", + "icon_name": "bsd", + "name_plural": "Bahamian Dollars", + "type": "fiat", + "countries": ["BS"] + }, + "BTN": { + "symbol": "Nu.", + "name": "Bhutanese Ngultrum", + "symbol_native": "Nu.", + "decimal_digits": 2, + "rounding": 0, + "code": "BTN", + "icon_name": "btn", + "name_plural": "Bhutanese Ngultrum", + "type": "fiat", + "countries": ["BT"] + }, + "BWP": { + "symbol": "BWP", + "name": "Botswanan Pula", + "symbol_native": "P", + "decimal_digits": 2, + "rounding": 0, + "code": "BWP", + "name_plural": "Botswanan pulas", + "type": "fiat", + "countries": ["BW", "ZW"] + }, + "BYN": { + "symbol": "Br", + "name": "Belarusian ruble", + "symbol_native": "Br", + "decimal_digits": 2, + "rounding": 0, + "code": "BYN", + "name_plural": "Belarusian rubles", + "type": "fiat", + "countries": [] + }, + "BYR": { + "symbol": "BYR", + "name": "Belarusian Ruble", + "symbol_native": "BYR", + "decimal_digits": 0, + "rounding": 0, + "code": "BYR", + "name_plural": "Belarusian rubles", + "type": "fiat", + "countries": ["BY"] + }, + "BZD": { + "symbol": "BZ$", + "name": "Belize Dollar", + "symbol_native": "$", + "decimal_digits": 2, + "rounding": 0, + "code": "BZD", + "name_plural": "Belize dollars", + "type": "fiat", + "countries": ["BZ"] + }, + "CAD": { + "symbol": "CA$", + "name": "Canadian Dollar", + "symbol_native": "$", + "decimal_digits": 2, + "rounding": 0, + "code": "CAD", + "name_plural": "Canadian dollars", + "type": "fiat", + "countries": ["CA"] + }, + "CDF": { + "symbol": "CDF", + "name": "Congolese Franc", + "symbol_native": "FrCD", + "decimal_digits": 2, + "rounding": 0, + "code": "CDF", + "name_plural": "Congolese francs", + "type": "fiat", + "countries": ["CD"] + }, + "CHF": { + "symbol": "CHF", + "name": "Swiss Franc", + "symbol_native": "CHF", + "decimal_digits": 2, + "rounding": 0, + "code": "CHF", + "name_plural": "Swiss francs", + "type": "fiat", + "countries": ["CH", "LI"] + }, + "CLF": { + "symbol": "UF", + "name": "Unidad de Fomento", + "symbol_native": "UF", + "decimal_digits": 2, + "rounding": 0, + "code": "CLF", + "name_plural": "Unidad de Fomentos", + "type": "fiat", + "countries": ["CL"] + }, + "CLP": { + "symbol": "CL$", + "name": "Chilean Peso", + "symbol_native": "$", + "decimal_digits": 0, + "rounding": 0, + "code": "CLP", + "name_plural": "Chilean pesos", + "type": "fiat", + "countries": ["CL"] + }, + "CNY": { + "symbol": "CN¥", + "name": "Chinese Yuan", + "symbol_native": "CN¥", + "decimal_digits": 2, + "rounding": 0, + "code": "CNY", + "name_plural": "Chinese yuan", + "type": "fiat", + "countries": ["CN"] + }, + "COP": { + "symbol": "CO$", + "name": "Coombian Peso", + "symbol_native": "$", + "decimal_digits": 0, + "rounding": 0, + "code": "COP", + "name_plural": "Colombian pesos", + "type": "fiat", + "countries": ["CO"] + }, + "CRC": { + "symbol": "₡", + "name": "Costa Rican Colón", + "symbol_native": "₡", + "decimal_digits": 0, + "rounding": 0, + "code": "CRC", + "name_plural": "Costa Rican colóns", + "type": "fiat", + "countries": ["CR"] + }, + "CUC": { + "symbol": "CUC$", + "name": "Cuban Convertible Peso", + "symbol_native": "$", + "decimal_digits": 2, + "rounding": 0, + "code": "CUC", + "icon_name": "cuc", + "name_plural": "Cuban Convertible Peso", + "type": "fiat", + "countries": ["CU"] + }, + "CUP": { + "symbol": "$MN", + "name": "Cuban Peso", + "symbol_native": "$", + "decimal_digits": 2, + "rounding": 0, + "code": "CUP", + "icon_name": "cup", + "name_plural": "Cuban Peso", + "type": "fiat", + "countries": ["CU"] + }, + "CVE": { + "symbol": "CV$", + "name": "Cape Verdean Escudo", + "symbol_native": "CV$", + "decimal_digits": 2, + "rounding": 0, + "code": "CVE", + "name_plural": "Cape Verdean escudos", + "type": "fiat", + "countries": ["CV"] + }, + "CZK": { + "symbol": "Kč", + "name": "Czech Republic Koruna", + "symbol_native": "Kč", + "decimal_digits": 2, + "rounding": 0, + "code": "CZK", + "name_plural": "Czech Republic korunas", + "type": "fiat", + "countries": ["CZ"] + }, + "DJF": { + "symbol": "Fdj", + "name": "Djiboutian Franc", + "symbol_native": "Fdj", + "decimal_digits": 0, + "rounding": 0, + "code": "DJF", + "name_plural": "Djiboutian francs", + "type": "fiat", + "countries": ["DJ"] + }, + "DKK": { + "symbol": "Dkr", + "name": "Danish Krone", + "symbol_native": "kr", + "decimal_digits": 2, + "rounding": 0, + "code": "DKK", + "name_plural": "Danish kroner", + "type": "fiat", + "countries": ["DK", "FO", "GL"] + }, + "DOP": { + "symbol": "RD$", + "name": "Dominican Peso", + "symbol_native": "RD$", + "decimal_digits": 2, + "rounding": 0, + "code": "DOP", + "name_plural": "Dominican pesos", + "type": "fiat", + "countries": ["DO"] + }, + "DZD": { + "symbol": "DA", + "name": "Algerian Dinar", + "symbol_native": "د.ج.‏", + "decimal_digits": 2, + "rounding": 0, + "code": "DZD", + "name_plural": "Algerian dinars", + "type": "fiat", + "countries": ["DZ"] + }, + "EGP": { + "symbol": "EGP", + "name": "Egyptian Pound", + "symbol_native": "ج.م.‏", + "decimal_digits": 2, + "rounding": 0, + "code": "EGP", + "name_plural": "Egyptian pounds", + "type": "fiat", + "countries": ["EG", "PS"] + }, + "ERN": { + "symbol": "Nfk", + "name": "Eritrean Nakfa", + "symbol_native": "Nfk", + "decimal_digits": 2, + "rounding": 0, + "code": "ERN", + "name_plural": "Eritrean nakfas", + "type": "fiat", + "countries": ["ER"] + }, + "ETB": { + "symbol": "Br", + "name": "Ethiopian Birr", + "symbol_native": "Br", + "decimal_digits": 2, + "rounding": 0, + "code": "ETB", + "name_plural": "Ethiopian birrs", + "type": "fiat", + "countries": ["ET"] + }, + "EUR": { + "symbol": "€", + "name": "Euro", + "symbol_native": "€", + "decimal_digits": 2, + "rounding": 0, + "code": "EUR", + "name_plural": "Euros", + "type": "fiat", + "countries": [ + "AD", + "AT", + "AX", + "BE", + "BL", + "CP", + "CY", + "DE", + "EA", + "EE", + "ES", + "EU", + "FI", + "FR", + "FX", + "GF", + "GP", + "GR", + "IC", + "IE", + "IT", + "LT", + "LU", + "LV", + "MC", + "ME", + "MF", + "MQ", + "MT", + "NL", + "PM", + "PT", + "RE", + "SI", + "SK", + "SM", + "TF", + "VA", + "XK", + "YT", + "ZW" + ] + }, + "FJD": { + "symbol": "FJ$", + "name": "Fijian Dollar", + "symbol_native": "$", + "decimal_digits": 2, + "rounding": 0, + "code": "FJD", + "icon_name": "fjd", + "name_plural": "Fijian Dollar", + "type": "fiat", + "countries": ["FJ"] + }, + "FKP": { + "symbol": "FK£", + "name": "Falkland Islands Pound", + "symbol_native": "£", + "decimal_digits": 2, + "rounding": 0, + "code": "FKP", + "icon_name": "fkp", + "name_plural": "Falkland Islands Pound", + "type": "fiat", + "countries": ["FK"] + }, + "GBP": { + "symbol": "£", + "name": "British Pound Sterling", + "symbol_native": "£", + "decimal_digits": 2, + "rounding": 0, + "code": "GBP", + "name_plural": "British pounds sterling", + "type": "fiat", + "countries": ["GB", "GG", "GS", "IM", "JE", "TA", "UK", "ZW"] + }, + "GEL": { + "symbol": "GEL", + "name": "Georgian Lari", + "symbol_native": "GEL", + "decimal_digits": 2, + "rounding": 0, + "code": "GEL", + "name_plural": "Georgian laris", + "type": "fiat", + "countries": ["GE"] + }, + "GGP": { + "symbol": "£", + "name": "Guernsey pound", + "symbol_native": "£", + "decimal_digits": 2, + "rounding": 0, + "code": "GGP", + "name_plural": "Guernsey pounds", + "type": "fiat", + "countries": [] + }, + "GHS": { + "symbol": "GH₵", + "name": "Ghanaian Cedi", + "symbol_native": "GH₵", + "decimal_digits": 2, + "rounding": 0, + "code": "GHS", + "name_plural": "Ghanaian cedis", + "type": "fiat", + "countries": ["GH"] + }, + "GIP": { + "symbol": "£", + "name": "Gibraltar Pound", + "symbol_native": "£", + "decimal_digits": 2, + "rounding": 0, + "code": "GIP", + "icon_name": "gip", + "name_plural": "Gibraltar Pounds", + "type": "fiat", + "countries": ["GI"] + }, + "GMD": { + "symbol": "D", + "name": "Gambian Dalasi", + "symbol_native": "D", + "decimal_digits": 2, + "rounding": 0, + "code": "GMD", + "icon_name": "gmd", + "name_plural": "Gambian Dalasi", + "type": "fiat", + "countries": ["GM"] + }, + "GNF": { + "symbol": "FG", + "name": "Guinean Franc", + "symbol_native": "FG", + "decimal_digits": 0, + "rounding": 0, + "code": "GNF", + "name_plural": "Guinean francs", + "type": "fiat", + "countries": ["GN"] + }, + "GTQ": { + "symbol": "GTQ", + "name": "Guatemalan Quetzal", + "symbol_native": "Q", + "decimal_digits": 2, + "rounding": 0, + "code": "GTQ", + "name_plural": "Guatemalan quetzals", + "type": "fiat", + "countries": ["GT"] + }, + "GYD": { + "symbol": "G$", + "name": "Guyanaese Dollar", + "symbol_native": "$", + "decimal_digits": 2, + "rounding": 0, + "code": "GYD", + "icon_name": "gyd", + "name_plural": "Guyanaese Dollar", + "type": "fiat", + "countries": ["GY"] + }, + "HKD": { + "symbol": "HK$", + "name": "Hong Kong Dollar", + "symbol_native": "$", + "decimal_digits": 2, + "rounding": 0, + "code": "HKD", + "name_plural": "Hong Kong dollars", + "type": "fiat", + "countries": ["HK"] + }, + "HNL": { + "symbol": "HNL", + "name": "Honduran Lempira", + "symbol_native": "L", + "decimal_digits": 2, + "rounding": 0, + "code": "HNL", + "name_plural": "Honduran lempiras", + "type": "fiat", + "countries": ["HN"] + }, + "HRK": { + "symbol": "kn", + "name": "Croatian Kuna", + "symbol_native": "kn", + "decimal_digits": 2, + "rounding": 0, + "code": "HRK", + "name_plural": "Croatian kunas", + "type": "fiat", + "countries": ["HR"] + }, + "HTG": { + "symbol": "G", + "name": "Haitian Gourde", + "symbol_native": "G", + "decimal_digits": 2, + "rounding": 0, + "code": "HTG", + "icon_name": "htg", + "name_plural": "Haitian Gourde", + "type": "fiat", + "countries": ["HT"] + }, + "HUF": { + "symbol": "Ft", + "name": "Hungarian Forint", + "symbol_native": "Ft", + "decimal_digits": 0, + "rounding": 0, + "code": "HUF", + "name_plural": "Hungarian forints", + "type": "fiat", + "countries": ["HU"] + }, + "IDR": { + "symbol": "Rp", + "name": "Indonesian Rupiah", + "symbol_native": "Rp", + "decimal_digits": 0, + "rounding": 0, + "code": "IDR", + "name_plural": "Indonesian rupiahs", + "type": "fiat", + "countries": ["ID"] + }, + "ILS": { + "symbol": "₪", + "name": "Israeli New Sheqel", + "symbol_native": "₪", + "decimal_digits": 2, + "rounding": 0, + "code": "ILS", + "name_plural": "Israeli new sheqels", + "type": "fiat", + "countries": ["IL", "PS"] + }, + "IMP": { + "symbol": "£", + "name": "Manx pound", + "symbol_native": "£", + "decimal_digits": 2, + "rounding": 0, + "code": "IMP", + "name_plural": "Manx pounds", + "type": "fiat", + "countries": [] + }, + "INR": { + "symbol": "Rs", + "name": "Indian Rupee", + "symbol_native": "টকা", + "decimal_digits": 2, + "rounding": 0, + "code": "INR", + "name_plural": "Indian rupees", + "type": "fiat", + "countries": ["BT", "IN"] + }, + "IQD": { + "symbol": "IQD", + "name": "Iraqi Dinar", + "symbol_native": "د.ع.‏", + "decimal_digits": 0, + "rounding": 0, + "code": "IQD", + "name_plural": "Iraqi dinars", + "type": "fiat", + "countries": ["IQ"] + }, + "IRR": { + "symbol": "IRR", + "name": "Iranian Rial", + "symbol_native": "﷼", + "decimal_digits": 0, + "rounding": 0, + "code": "IRR", + "name_plural": "Iranian rials", + "type": "fiat", + "countries": ["IR"] + }, + "ISK": { + "symbol": "Ikr", + "name": "Icelandic Króna", + "symbol_native": "kr", + "decimal_digits": 0, + "rounding": 0, + "code": "ISK", + "name_plural": "Icelandic krónur", + "type": "fiat", + "countries": ["IS"] + }, + "JEP": { + "symbol": "£", + "name": "Jersey pound", + "symbol_native": "£", + "decimal_digits": 2, + "rounding": 0, + "code": "JEP", + "name_plural": "Jersey pound", + "type": "fiat", + "countries": [] + }, + "JMD": { + "symbol": "J$", + "name": "Jamaican Dollar", + "symbol_native": "$", + "decimal_digits": 2, + "rounding": 0, + "code": "JMD", + "name_plural": "Jamaican dollars", + "type": "fiat", + "countries": ["JM"] + }, + "JOD": { + "symbol": "JD", + "name": "Jordanian Dinar", + "symbol_native": "د.أ.‏", + "decimal_digits": 3, + "rounding": 0, + "code": "JOD", + "name_plural": "Jordanian dinars", + "type": "fiat", + "countries": ["JO", "PS"] + }, + "JPY": { + "symbol": "¥", + "name": "Japanese Yen", + "symbol_native": "¥", + "decimal_digits": 0, + "rounding": 0, + "code": "JPY", + "name_plural": "Japanese yen", + "type": "fiat", + "countries": ["JP"] + }, + "KES": { + "symbol": "Ksh", + "name": "Kenyan Shilling", + "symbol_native": "Ksh", + "decimal_digits": 2, + "rounding": 0, + "code": "KES", + "name_plural": "Kenyan shillings", + "type": "fiat", + "countries": ["KE"] + }, + "KGS": { + "symbol": "KGS", + "name": "Kyrgystani Som", + "symbol_native": "KGS", + "decimal_digits": 2, + "rounding": 0, + "code": "KGS", + "icon_name": "kgs", + "name_plural": "Kyrgystani Som", + "type": "fiat", + "countries": ["KG"] + }, + "KHR": { + "symbol": "KHR", + "name": "Cambodian Riel", + "symbol_native": "៛", + "decimal_digits": 2, + "rounding": 0, + "code": "KHR", + "name_plural": "Cambodian riels", + "type": "fiat", + "countries": ["KH"] + }, + "KMF": { + "symbol": "CF", + "name": "Comorian Franc", + "symbol_native": "FC", + "decimal_digits": 0, + "rounding": 0, + "code": "KMF", + "name_plural": "Comorian francs", + "type": "fiat", + "countries": ["KM"] + }, + "KPW": { + "symbol": "₩", + "name": "North Korean Won", + "symbol_native": "₩", + "decimal_digits": 2, + "rounding": 0, + "code": "KPW", + "icon_name": "kpw", + "name_plural": "North Korean Won", + "type": "fiat", + "countries": ["KP"] + }, + "KRW": { + "symbol": "₩", + "name": "South Korean Won", + "symbol_native": "₩", + "decimal_digits": 0, + "rounding": 0, + "code": "KRW", + "name_plural": "South Korean won", + "type": "fiat", + "countries": ["KR"] + }, + "KWD": { + "symbol": "KD", + "name": "Kuwaiti Dinar", + "symbol_native": "د.ك.‏", + "decimal_digits": 3, + "rounding": 0, + "code": "KWD", + "name_plural": "Kuwaiti dinars", + "type": "fiat", + "countries": ["KW"] + }, + "KYD": { + "symbol": "CI$", + "name": "Cayman Islands Dollar", + "symbol_native": "$‏", + "decimal_digits": 2, + "rounding": 0, + "code": "KYD", + "icon_name": "kyd", + "name_plural": "Cayman Islands Dollar", + "type": "fiat", + "countries": ["KY"] + }, + "KZT": { + "symbol": "KZT", + "name": "Kazakhstani Tenge", + "symbol_native": "тңг.", + "decimal_digits": 2, + "rounding": 0, + "code": "KZT", + "name_plural": "Kazakhstani tenges", + "type": "fiat", + "countries": ["KZ"] + }, + "LAK": { + "symbol": "₭N", + "name": "Laotian Kip", + "symbol_native": "₭‏‏", + "decimal_digits": 0, + "rounding": 0, + "code": "LAK", + "name_plural": "Laotian Kip", + "type": "fiat", + "countries": ["LA"] + }, + "LBP": { + "symbol": "LB£", + "name": "Lebanese Pound", + "symbol_native": "ل.ل.‏", + "decimal_digits": 0, + "rounding": 0, + "code": "LBP", + "name_plural": "Lebanese pounds", + "type": "fiat", + "countries": ["LB"] + }, + "LKR": { + "symbol": "SLRs", + "name": "Sri Lankan Rupee", + "symbol_native": "SL Re", + "decimal_digits": 2, + "rounding": 0, + "code": "LKR", + "name_plural": "Sri Lankan rupees", + "type": "fiat", + "countries": ["LK"] + }, + "LRD": { + "symbol": "LD$", + "name": "Liberian Dollar", + "symbol_native": "L$", + "decimal_digits": 2, + "rounding": 0, + "code": "LRD", + "icon_name": "lrd", + "name_plural": "Liberian Dollar", + "type": "fiat", + "countries": ["LR"] + }, + "LSL": { + "symbol": "L", + "name": "Lesotho Loti", + "symbol_native": "M", + "decimal_digits": 2, + "rounding": 0, + "code": "LSL", + "icon_name": "lsl", + "name_plural": "Lesotho Loti", + "type": "fiat", + "countries": ["LS"] + }, + "LTL": { + "symbol": "Lt", + "name": "Lithuanian Litas", + "symbol_native": "Lt", + "decimal_digits": 2, + "rounding": 0, + "code": "LTL", + "name_plural": "Lithuanian litai", + "type": "fiat", + "countries": [] + }, + "LVL": { + "symbol": "Ls", + "name": "Latvian Lats", + "symbol_native": "Ls", + "decimal_digits": 2, + "rounding": 0, + "code": "LVL", + "name_plural": "Latvian lati", + "type": "fiat", + "countries": [] + }, + "LYD": { + "symbol": "LD", + "name": "Libyan Dinar", + "symbol_native": "د.ل.‏", + "decimal_digits": 3, + "rounding": 0, + "code": "LYD", + "name_plural": "Libyan dinars", + "type": "fiat", + "countries": ["LY"] + }, + "MAD": { + "symbol": "MAD", + "name": "Moroccan Dirham", + "symbol_native": "د.م.‏", + "decimal_digits": 2, + "rounding": 0, + "code": "MAD", + "name_plural": "Moroccan dirhams", + "type": "fiat", + "countries": ["EH", "MA"] + }, + "MDL": { + "symbol": "MDL", + "name": "Moldovan Leu", + "symbol_native": "MDL", + "decimal_digits": 2, + "rounding": 0, + "code": "MDL", + "name_plural": "Moldovan lei", + "type": "fiat", + "countries": ["MD"] + }, + "MGA": { + "symbol": "MGA", + "name": "Malagasy Ariary", + "symbol_native": "MGA", + "decimal_digits": 0, + "rounding": 0, + "code": "MGA", + "name_plural": "Malagasy Ariaries", + "type": "fiat", + "countries": ["MG"] + }, + "MKD": { + "symbol": "MKD", + "name": "Macedonian Denar", + "symbol_native": "MKD", + "decimal_digits": 2, + "rounding": 0, + "code": "MKD", + "name_plural": "Macedonian denari", + "type": "fiat", + "countries": ["MK"] + }, + "MMK": { + "symbol": "MMK", + "name": "Myanma Kyat", + "symbol_native": "K", + "decimal_digits": 0, + "rounding": 0, + "code": "MMK", + "name_plural": "Myanma kyats", + "type": "fiat", + "countries": ["MM"] + }, + "MNT": { + "symbol": "₮", + "name": "Mongolian Tugrik", + "symbol_native": "₮", + "decimal_digits": 2, + "rounding": 0, + "code": "MNT", + "icon_name": "mnt", + "name_plural": "Mongolian Tugrik", + "type": "fiat", + "countries": ["MN"] + }, + "MOP": { + "symbol": "MOP$", + "name": "Macanese Pataca", + "symbol_native": "MOP$", + "decimal_digits": 2, + "rounding": 0, + "code": "MOP", + "name_plural": "Macanese patacas", + "type": "fiat", + "countries": ["MO"] + }, + "MRO": { + "symbol": "UM", + "name": "Mauritanian ouguiya", + "symbol_native": "UM", + "decimal_digits": 2, + "rounding": 0, + "code": "MRO", + "name_plural": "Mauritanian ouguiyas", + "type": "fiat", + "countries": ["MR"] + }, + "MUR": { + "symbol": "MURs", + "name": "Mauritian Rupee", + "symbol_native": "MURs", + "decimal_digits": 0, + "rounding": 0, + "code": "MUR", + "name_plural": "Mauritian rupees", + "type": "fiat", + "countries": ["MU"] + }, + "MVR": { + "symbol": "MRf", + "name": "Maldivian Rufiyaa", + "symbol_native": "Rf", + "decimal_digits": 2, + "rounding": 0, + "code": "MVR", + "name_plural": "Maldivian Rufiyaa", + "type": "fiat", + "countries": ["MV"] + }, + "MWK": { + "symbol": "MK", + "name": "Malawian Kwacha", + "symbol_native": "MK", + "decimal_digits": 2, + "rounding": 0, + "code": "MWK", + "icon_name": "mwk", + "name_plural": "Malawian Kwacha", + "type": "fiat", + "countries": ["MW"] + }, + "MXN": { + "symbol": "MX$", + "name": "Mexican Peso", + "symbol_native": "$", + "decimal_digits": 2, + "rounding": 0, + "code": "MXN", + "name_plural": "Mexican pesos", + "type": "fiat", + "countries": ["MX"] + }, + "MYR": { + "symbol": "RM", + "name": "Malaysian Ringgit", + "symbol_native": "RM", + "decimal_digits": 2, + "rounding": 0, + "code": "MYR", + "name_plural": "Malaysian ringgits", + "type": "fiat", + "countries": ["MY"] + }, + "MZN": { + "symbol": "MTn", + "name": "Mozambican Metical", + "symbol_native": "MTn", + "decimal_digits": 2, + "rounding": 0, + "code": "MZN", + "name_plural": "Mozambican meticals", + "type": "fiat", + "countries": ["MZ"] + }, + "NAD": { + "symbol": "N$", + "name": "Namibian Dollar", + "symbol_native": "N$", + "decimal_digits": 2, + "rounding": 0, + "code": "NAD", + "name_plural": "Namibian dollars", + "type": "fiat", + "countries": ["NA"] + }, + "NGN": { + "symbol": "₦", + "name": "Nigerian Naira", + "symbol_native": "₦", + "decimal_digits": 2, + "rounding": 0, + "code": "NGN", + "name_plural": "Nigerian nairas", + "type": "fiat", + "countries": ["NG"] + }, + "NIO": { + "symbol": "C$", + "name": "Nicaraguan Córdoba", + "symbol_native": "C$", + "decimal_digits": 2, + "rounding": 0, + "code": "NIO", + "name_plural": "Nicaraguan córdobas", + "type": "fiat", + "countries": ["NI"] + }, + "NOK": { + "symbol": "Nkr", + "name": "Norwegian Krone", + "symbol_native": "kr", + "decimal_digits": 2, + "rounding": 0, + "code": "NOK", + "name_plural": "Norwegian kroner", + "type": "fiat", + "countries": ["BV", "NO", "SJ"] + }, + "NPR": { + "symbol": "NPRs", + "name": "Nepalese Rupee", + "symbol_native": "नेरू", + "decimal_digits": 2, + "rounding": 0, + "code": "NPR", + "name_plural": "Nepalese rupees", + "type": "fiat", + "countries": ["NP"] + }, + "NZD": { + "symbol": "NZ$", + "name": "New Zealand Dollar", + "symbol_native": "$", + "decimal_digits": 2, + "rounding": 0, + "code": "NZD", + "name_plural": "New Zealand dollars", + "type": "fiat", + "countries": ["CK", "NU", "NZ", "PN", "TK"] + }, + "OMR": { + "symbol": "OMR", + "name": "Omani Rial", + "symbol_native": "ر.ع.‏", + "decimal_digits": 3, + "rounding": 0, + "code": "OMR", + "name_plural": "Omani rials", + "type": "fiat", + "countries": ["OM"] + }, + "PAB": { + "symbol": "B/.", + "name": "Panamanian Balboa", + "symbol_native": "B/.", + "decimal_digits": 2, + "rounding": 0, + "code": "PAB", + "name_plural": "Panamanian balboas", + "type": "fiat", + "countries": ["PA"] + }, + "PEN": { + "symbol": "S/.", + "name": "Peruvian Nuevo Sol", + "symbol_native": "S/.", + "decimal_digits": 2, + "rounding": 0, + "code": "PEN", + "name_plural": "Peruvian nuevos soles", + "type": "fiat", + "countries": ["PE"] + }, + "PGK": { + "symbol": "K", + "name": "Papua New Guinean Kina", + "symbol_native": "K", + "decimal_digits": 2, + "rounding": 0, + "code": "PGK", + "icon_name": "pgk", + "name_plural": "Papua New Guinean Kina", + "type": "fiat", + "countries": ["PG"] + }, + "PHP": { + "symbol": "₱", + "name": "Philippine Peso", + "symbol_native": "₱", + "decimal_digits": 2, + "rounding": 0, + "code": "PHP", + "name_plural": "Philippine pesos", + "type": "fiat", + "countries": ["PH"] + }, + "PKR": { + "symbol": "PKRs", + "name": "Pakistani Rupee", + "symbol_native": "₨", + "decimal_digits": 0, + "rounding": 0, + "code": "PKR", + "name_plural": "Pakistani rupees", + "type": "fiat", + "countries": ["PK"] + }, + "PLN": { + "symbol": "zł", + "name": "Polish Zloty", + "symbol_native": "zł", + "decimal_digits": 2, + "rounding": 0, + "code": "PLN", + "name_plural": "Polish zlotys", + "type": "fiat", + "countries": ["PL"] + }, + "PYG": { + "symbol": "₲", + "name": "Paraguayan Guarani", + "symbol_native": "₲", + "decimal_digits": 0, + "rounding": 0, + "code": "PYG", + "name_plural": "Paraguayan guaranis", + "type": "fiat", + "countries": ["PY"] + }, + "QAR": { + "symbol": "QR", + "name": "Qatari Rial", + "symbol_native": "ر.ق.‏", + "decimal_digits": 2, + "rounding": 0, + "code": "QAR", + "name_plural": "Qatari rials", + "type": "fiat", + "countries": ["QA"] + }, + "RON": { + "symbol": "RON", + "name": "Romanian Leu", + "symbol_native": "RON", + "decimal_digits": 2, + "rounding": 0, + "code": "RON", + "name_plural": "Romanian lei", + "type": "fiat", + "countries": ["RO"] + }, + "RSD": { + "symbol": "din.", + "name": "Serbian Dinar", + "symbol_native": "дин.", + "decimal_digits": 0, + "rounding": 0, + "code": "RSD", + "name_plural": "Serbian dinars", + "type": "fiat", + "countries": ["RS"] + }, + "RUB": { + "symbol": "RUB", + "name": "Russian Ruble", + "symbol_native": "руб.", + "decimal_digits": 2, + "rounding": 0, + "code": "RUB", + "name_plural": "Russian rubles", + "type": "fiat", + "countries": ["RU", "SU"] + }, + "RWF": { + "symbol": "RWF", + "name": "Rwandan Franc", + "symbol_native": "FR", + "decimal_digits": 0, + "rounding": 0, + "code": "RWF", + "name_plural": "Rwandan francs", + "type": "fiat", + "countries": ["RW"] + }, + "SAR": { + "symbol": "SR", + "name": "Saudi Riyal", + "symbol_native": "ر.س.‏", + "decimal_digits": 2, + "rounding": 0, + "code": "SAR", + "name_plural": "Saudi riyals", + "type": "fiat", + "countries": ["SA"] + }, + "SBD": { + "symbol": "SI$", + "name": "Solomon Islands Dollar", + "symbol_native": "$", + "decimal_digits": 2, + "rounding": 0, + "code": "SBD", + "icon_name": "sbd", + "name_plural": "Solomon Islands Dollars", + "type": "fiat", + "countries": ["SB"] + }, + "SCR": { + "symbol": "SRe", + "name": "Seychellois Rupee", + "symbol_native": "SR", + "decimal_digits": 2, + "rounding": 0, + "code": "SCR", + "icon_name": "scr", + "name_plural": "Seychellois Rupees", + "type": "fiat", + "countries": ["SC"] + }, + "SDG": { + "symbol": "SDG", + "name": "Sudanese Pound", + "symbol_native": "SDG", + "decimal_digits": 2, + "rounding": 0, + "code": "SDG", + "name_plural": "Sudanese pounds", + "type": "fiat", + "countries": ["SD"] + }, + "SEK": { + "symbol": "Skr", + "name": "Swedish Krona", + "symbol_native": "kr", + "decimal_digits": 2, + "rounding": 0, + "code": "SEK", + "name_plural": "Swedish kronor", + "type": "fiat", + "countries": ["SE"] + }, + "SGD": { + "symbol": "S$", + "name": "Singapore Dollar", + "symbol_native": "$", + "decimal_digits": 2, + "rounding": 0, + "code": "SGD", + "name_plural": "Singapore dollars", + "type": "fiat", + "countries": ["SG"] + }, + "SHP": { + "symbol": "£", + "name": "Saint Helena Pound", + "symbol_native": "£", + "decimal_digits": 2, + "rounding": 0, + "code": "SHP", + "icon_name": "shp", + "name_plural": "Saint Helena Pounds", + "type": "fiat", + "countries": ["SH"] + }, + "SLL": { + "symbol": "Le", + "name": "Sierra Leonean Leone", + "symbol_native": "Le", + "decimal_digits": 2, + "rounding": 0, + "code": "SLL", + "icon_name": "sll", + "name_plural": "Sierra Leonean Leone", + "type": "fiat", + "countries": ["SL"] + }, + "SOS": { + "symbol": "Ssh", + "name": "Somali Shilling", + "symbol_native": "Ssh", + "decimal_digits": 0, + "rounding": 0, + "code": "SOS", + "name_plural": "Somali shillings", + "type": "fiat", + "countries": ["SO"] + }, + "SRD": { + "symbol": "$", + "name": "Surinamese Dollar", + "symbol_native": "$", + "decimal_digits": 2, + "rounding": 0, + "code": "SRD", + "icon_name": "srd", + "name_plural": "Surinamese Dollar", + "type": "fiat", + "countries": ["SR"] + }, + "STD": { + "symbol": "Db", + "name": "São Tomé and Príncipe dobra", + "symbol_native": "Db", + "decimal_digits": 2, + "rounding": 0, + "code": "STD", + "name_plural": "São Tomé and Príncipe dobras", + "type": "fiat", + "countries": ["ST"] + }, + "SVC": { + "symbol": "₡", + "name": "Salvadoran Colón", + "symbol_native": "₡", + "decimal_digits": 2, + "rounding": 0, + "code": "SVC", + "icon_name": "svc", + "name_plural": "Salvadoran Colón", + "type": "fiat", + "countries": [] + }, + "SYP": { + "symbol": "SY£", + "name": "Syrian Pound", + "symbol_native": "ل.س.‏", + "decimal_digits": 0, + "rounding": 0, + "code": "SYP", + "name_plural": "Syrian pounds", + "type": "fiat", + "countries": ["SY"] + }, + "SZL": { + "symbol": "L", + "name": "Swazi Lilangeni", + "symbol_native": "E‏", + "decimal_digits": 2, + "rounding": 0, + "code": "SZL", + "icon_name": "szl", + "name_plural": "Swazi Lilangeni", + "type": "fiat", + "countries": ["SZ"] + }, + "THB": { + "symbol": "฿", + "name": "Thai Baht", + "symbol_native": "฿", + "decimal_digits": 2, + "rounding": 0, + "code": "THB", + "name_plural": "Thai baht", + "type": "fiat", + "countries": ["TH"] + }, + "TJS": { + "symbol": "TJS", + "name": "Tajikistani Somoni", + "symbol_native": "TJS", + "decimal_digits": 2, + "rounding": 0, + "code": "TJS", + "icon_name": "tjs", + "name_plural": "Tajikistani Somoni", + "type": "fiat", + "countries": ["TJ"] + }, + "TMT": { + "symbol": "T", + "name": "Turkmenistani Manat", + "symbol_native": "T‏", + "decimal_digits": 2, + "rounding": 0, + "code": "TMT", + "icon_name": "tmt", + "name_plural": "Turkmenistani Manat", + "type": "fiat", + "countries": ["TM"] + }, + "TND": { + "symbol": "DT", + "name": "Tunisian Dinar", + "symbol_native": "د.ت.‏", + "decimal_digits": 3, + "rounding": 0, + "code": "TND", + "name_plural": "Tunisian dinars", + "type": "fiat", + "countries": ["TN"] + }, + "TOP": { + "symbol": "T$", + "name": "Tongan Paʻanga", + "symbol_native": "T$", + "decimal_digits": 2, + "rounding": 0, + "code": "TOP", + "name_plural": "Tongan paʻanga", + "type": "fiat", + "countries": ["TO"] + }, + "TRY": { + "symbol": "TL", + "name": "Turkish Lira", + "symbol_native": "TL", + "decimal_digits": 2, + "rounding": 0, + "code": "TRY", + "name_plural": "Turkish Lira", + "type": "fiat", + "countries": ["TR"] + }, + "TTD": { + "symbol": "TT$", + "name": "Trinidad and Tobago Dollar", + "symbol_native": "$", + "decimal_digits": 2, + "rounding": 0, + "code": "TTD", + "name_plural": "Trinidad and Tobago dollars", + "type": "fiat", + "countries": ["TT"] + }, + "TWD": { + "symbol": "NT$", + "name": "New Taiwan Dollar", + "symbol_native": "NT$", + "decimal_digits": 2, + "rounding": 0, + "code": "TWD", + "name_plural": "New Taiwan dollars", + "type": "fiat", + "countries": ["TW"] + }, + "TZS": { + "symbol": "TSh", + "name": "Tanzanian Shilling", + "symbol_native": "TSh", + "decimal_digits": 0, + "rounding": 0, + "code": "TZS", + "name_plural": "Tanzanian shillings", + "type": "fiat", + "countries": ["TZ"] + }, + "UAH": { + "symbol": "₴", + "name": "Ukrainian Hryvnia", + "symbol_native": "₴", + "decimal_digits": 2, + "rounding": 0, + "code": "UAH", + "name_plural": "Ukrainian hryvnias", + "type": "fiat", + "countries": ["UA"] + }, + "UGX": { + "symbol": "USh", + "name": "Ugandan Shilling", + "symbol_native": "USh", + "decimal_digits": 0, + "rounding": 0, + "code": "UGX", + "name_plural": "Ugandan shillings", + "type": "fiat", + "countries": ["UG"] + }, + "USD": { + "symbol": "$", + "name": "US Dollar", + "symbol_native": "$", + "decimal_digits": 2, + "rounding": 0, + "code": "USD", + "name_plural": "US dollars", + "type": "fiat", + "countries": [ + "AC", + "AS", + "BQ", + "DG", + "EC", + "FM", + "GU", + "HT", + "IO", + "MH", + "MP", + "PA", + "PR", + "PW", + "SV", + "TC", + "TL", + "UM", + "US", + "VG", + "VI", + "ZW" + ] + }, + "UYU": { + "symbol": "$U", + "name": "Uruguayan Peso", + "symbol_native": "$", + "decimal_digits": 2, + "rounding": 0, + "code": "UYU", + "name_plural": "Uruguayan pesos", + "type": "fiat", + "countries": ["UY"] + }, + "UZS": { + "symbol": "UZS", + "name": "Uzbekistan Som", + "symbol_native": "UZS", + "decimal_digits": 0, + "rounding": 0, + "code": "UZS", + "name_plural": "Uzbekistan som", + "type": "fiat", + "countries": ["UZ"] + }, + "VEF": { + "symbol": "Bs.F.", + "name": "Venezuelan Bolívar", + "symbol_native": "Bs.F.", + "decimal_digits": 2, + "rounding": 0, + "code": "VEF", + "name_plural": "Venezuelan bolívars", + "type": "fiat", + "countries": ["VE"] + }, + "VND": { + "symbol": "₫", + "name": "Vietnamese Dong", + "symbol_native": "₫", + "decimal_digits": 0, + "rounding": 0, + "code": "VND", + "name_plural": "Vietnamese dong", + "type": "fiat", + "countries": ["VN"] + }, + "VUV": { + "symbol": "VUV", + "name": "Vanuatu Vatu", + "symbol_native": "VT", + "decimal_digits": 0, + "rounding": 0, + "code": "VUV", + "icon_name": "vuv", + "name_plural": "Vanuatu Vatu", + "type": "fiat", + "countries": ["VU"] + }, + "WST": { + "symbol": "WS$", + "name": "Samoan Tala", + "symbol_native": "T", + "decimal_digits": 2, + "rounding": 0, + "code": "WST", + "icon_name": "wst", + "name_plural": "Samoan Tala", + "type": "fiat", + "countries": ["WS"] + }, + "XAF": { + "symbol": "FCFA", + "name": "CFA Franc BEAC", + "symbol_native": "FCFA", + "decimal_digits": 0, + "rounding": 0, + "code": "XAF", + "name_plural": "CFA francs BEAC", + "type": "fiat", + "countries": ["CF", "CG", "CM", "GA", "GQ", "TD"] + }, + "XAG": { + "symbol": "XAG", + "name": "Silver Ounce", + "symbol_native": "XAG", + "decimal_digits": 2, + "rounding": 0, + "code": "XAG", + "name_plural": "Silver Ounces", + "type": "metal", + "countries": [] + }, + "XAU": { + "symbol": "XAU", + "name": "Gold Ounce", + "symbol_native": "XAU", + "decimal_digits": 2, + "rounding": 0, + "code": "XAU", + "name_plural": "Gold Ounces", + "type": "metal", + "countries": [] + }, + "XCD": { + "symbol": "EC$", + "name": "East Caribbean Dollar", + "symbol_native": "$", + "decimal_digits": 2, + "rounding": 0, + "code": "XCD", + "icon_name": "xcd", + "name_plural": "East Caribbean Dollars", + "type": "fiat", + "countries": ["AG", "AI", "DM", "GD", "KN", "LC", "MS", "VC"] + }, + "XDR": { + "symbol": "SDR", + "name": "Special drawing rights", + "symbol_native": "SDR", + "decimal_digits": 2, + "rounding": 0, + "code": "XDR", + "name_plural": "Special drawing rights", + "type": "fiat", + "countries": [] + }, + "XOF": { + "symbol": "CFA", + "name": "CFA Franc BCEAO", + "symbol_native": "CFA", + "decimal_digits": 0, + "rounding": 0, + "code": "XOF", + "name_plural": "CFA francs BCEAO", + "type": "fiat", + "countries": ["BF", "BJ", "CI", "GW", "ML", "NE", "SN", "TG"] + }, + "XPF": { + "symbol": "CFP", + "name": "CFP Franc", + "symbol_native": "CFP", + "decimal_digits": 0, + "rounding": 0, + "code": "XPF", + "icon_name": "xpf", + "name_plural": "CFP francs", + "type": "fiat", + "countries": ["NC", "PF", "WF"] + }, + "YER": { + "symbol": "YR", + "name": "Yemeni Rial", + "symbol_native": "ر.ي.‏", + "decimal_digits": 0, + "rounding": 0, + "code": "YER", + "name_plural": "Yemeni rials", + "type": "fiat", + "countries": ["YE"] + }, + "ZAR": { + "symbol": "R", + "name": "South African Rand", + "symbol_native": "R", + "decimal_digits": 2, + "rounding": 0, + "code": "ZAR", + "name_plural": "South African rand", + "type": "fiat", + "countries": ["LS", "NA", "ZA", "ZW"] + }, + "ZMK": { + "symbol": "ZK", + "name": "Zambian Kwacha", + "symbol_native": "ZK", + "decimal_digits": 0, + "rounding": 0, + "code": "ZMK", + "name_plural": "Zambian kwachas", + "type": "fiat", + "countries": [] + }, + "ZMW": { + "symbol": "ZK", + "name": "Zambian Kwacha", + "symbol_native": "ZK", + "decimal_digits": 0, + "rounding": 0, + "code": "ZMW", + "name_plural": "Zambian kwachas", + "type": "fiat", + "countries": ["ZM"] + }, + "ZWL": { + "symbol": "ZWL", + "name": "Zimbabwean dollar", + "symbol_native": "$", + "decimal_digits": 2, + "rounding": 0, + "code": "ZWL", + "name_plural": "Zimbabwean dollars", + "type": "fiat", + "countries": [] + }, + "XPT": { + "symbol": "XPT", + "name": "Platinum Ounce", + "symbol_native": "XPT", + "decimal_digits": 6, + "rounding": 0, + "code": "XPT", + "name_plural": "Platinum Ounces", + "type": "metal", + "countries": [] + }, + "XPD": { + "symbol": "XPD", + "name": "Palladium Ounce", + "symbol_native": "XPD", + "decimal_digits": 6, + "rounding": 0, + "code": "XPD", + "name_plural": "Palladium Ounces", + "type": "metal", + "countries": [] + }, + "BTC": { + "symbol": "₿", + "name": "Bitcoin", + "symbol_native": "₿", + "decimal_digits": 8, + "rounding": 0, + "code": "BTC", + "name_plural": "Bitcoins", + "type": "crypto", + "countries": [] + }, + "ETH": { + "symbol": "Ξ", + "name": "Ethereum", + "symbol_native": "Ξ", + "decimal_digits": 18, + "rounding": 0, + "code": "ETH", + "name_plural": "Ethereum", + "type": "crypto", + "countries": [] + }, + "BNB": { + "symbol": "BNB", + "name": "Binance", + "symbol_native": "BNB", + "decimal_digits": 8, + "rounding": 0, + "code": "BNB", + "name_plural": "Binance", + "type": "crypto", + "countries": [] + }, + "XRP": { + "symbol": "XRP", + "name": "Ripple", + "symbol_native": "XRP", + "decimal_digits": 6, + "rounding": 0, + "code": "XRP", + "name_plural": "Ripple", + "type": "crypto", + "countries": [] + }, + "SOL": { + "symbol": "SOL", + "name": "Solana", + "symbol_native": "SOL", + "decimal_digits": 9, + "rounding": 0, + "code": "SOL", + "name_plural": "Solana", + "type": "crypto", + "countries": [] + }, + "DOT": { + "symbol": "DOT", + "name": "Polkadot", + "symbol_native": "DOT", + "decimal_digits": 10, + "rounding": 0, + "code": "DOT", + "name_plural": "Polkadot", + "type": "crypto", + "countries": [] + }, + "AVAX": { + "symbol": "AVAX", + "name": "Avalanche", + "symbol_native": "AVAX", + "decimal_digits": 18, + "rounding": 0, + "code": "AVAX", + "name_plural": "Avalanche", + "type": "crypto", + "countries": [] + }, + "MATIC": { + "symbol": "MATIC", + "name": "Matic Token", + "symbol_native": "MATIC", + "decimal_digits": 18, + "rounding": 0, + "code": "MATIC", + "name_plural": "Matic Tokens", + "type": "crypto", + "countries": [] + }, + "LTC": { + "symbol": "Ł", + "name": "Litecoin", + "symbol_native": "Ł", + "decimal_digits": 8, + "rounding": 0, + "code": "LTC", + "name_plural": "Litecoins", + "type": "crypto", + "countries": [] + }, + "ADA": { + "symbol": "ADA", + "name": "Cardano", + "symbol_native": "ADA", + "decimal_digits": 6, + "rounding": 0, + "code": "ADA", + "name_plural": "Cardanos", + "type": "crypto", + "countries": [] + }, + "USDT": { + "symbol": "USDT", + "name": "Tether", + "symbol_native": "USDT", + "decimal_digits": 2, + "rounding": 0, + "code": "USDT", + "name_plural": "Tethers", + "type": "crypto", + "countries": [] + }, + "USDC": { + "symbol": "USDC", + "name": "USD Coin", + "symbol_native": "USDC", + "decimal_digits": 2, + "rounding": 0, + "code": "USDC", + "name_plural": "USD Coins", + "type": "crypto", + "countries": [] + }, + "DAI": { + "symbol": "DAI", + "name": "Dai", + "symbol_native": "DAI", + "decimal_digits": 2, + "rounding": 0, + "code": "DAI", + "name_plural": "Dais", + "type": "crypto", + "countries": [] + }, + "ARB": { + "symbol": "ARB", + "name": "Arbitrum", + "symbol_native": "ARB", + "decimal_digits": 8, + "rounding": 0, + "code": "ARB", + "name_plural": "Arbitrums", + "type": "crypto", + "countries": [] + }, + "OP": { + "symbol": "OP", + "name": "Optimism", + "symbol_native": "OP", + "decimal_digits": 8, + "rounding": 0, + "code": "OP", + "name_plural": "Optimism", + "type": "crypto", + "countries": [] + }, + "VES": { + "symbol": "Bs.S.", + "name": "Venezuelan Bolívar", + "symbol_native": "Bs.S.", + "decimal_digits": 2, + "rounding": 0, + "code": "VES", + "name_plural": "Venezuelan bolívars", + "type": "fiat", + "countries": [] + }, + "STN": { + "symbol": "STN", + "name": "São Tomé and Príncipe dobra", + "symbol_native": "STN", + "decimal_digits": 2, + "rounding": 0, + "code": "STN", + "name_plural": "dobra", + "type": "fiat", + "countries": [] + }, + "MRU": { + "symbol": "MRU", + "name": "Mauritanian ouguiya", + "symbol_native": "MRU", + "decimal_digits": 2, + "rounding": 0, + "code": "MRU", + "name_plural": "ouguiya", + "type": "fiat", + "countries": [] + } + } +} diff --git a/src/infra/gateway/api.currencyapi-v3-latest.json b/src/infra/gateway/api.currencyapi-v3-latest.json new file mode 100644 index 000000000..e3279e17a --- /dev/null +++ b/src/infra/gateway/api.currencyapi-v3-latest.json @@ -0,0 +1,192 @@ +{ + "meta": { "last_updated_at": "2024-06-10T23:59:59Z" }, + "data": { + "ADA": { "code": "ADA", "value": 2.2679298487 }, + "AED": { "code": "AED", "value": 3.6718406559 }, + "AFN": { "code": "AFN", "value": 70.7904573332 }, + "ALL": { "code": "ALL", "value": 93.0320944204 }, + "AMD": { "code": "AMD", "value": 387.0652417589 }, + "ANG": { "code": "ANG", "value": 1.787280302 }, + "AOA": { "code": "AOA", "value": 851.5743892967 }, + "ARB": { "code": "ARB", "value": 1.0411768981 }, + "ARS": { "code": "ARS", "value": 901.9165772212 }, + "AUD": { "code": "AUD", "value": 1.5132802995 }, + "AVAX": { "code": "AVAX", "value": 0.0309532227 }, + "AWG": { "code": "AWG", "value": 1.79 }, + "AZN": { "code": "AZN", "value": 1.7 }, + "BAM": { "code": "BAM", "value": 1.8167003404 }, + "BBD": { "code": "BBD", "value": 2 }, + "BDT": { "code": "BDT", "value": 117.5903174764 }, + "BGN": { "code": "BGN", "value": 1.812830352 }, + "BHD": { "code": "BHD", "value": 0.376 }, + "BIF": { "code": "BIF", "value": 2874.4080899246 }, + "BMD": { "code": "BMD", "value": 1 }, + "BNB": { "code": "BNB", "value": 0.0015946085 }, + "BND": { "code": "BND", "value": 1.3515501742 }, + "BOB": { "code": "BOB", "value": 6.9369912102 }, + "BRL": { "code": "BRL", "value": 5.3570006385 }, + "BSD": { "code": "BSD", "value": 1 }, + "BTC": { "code": "BTC", "value": 1.43517e-5 }, + "BTN": { "code": "BTN", "value": 83.5026750681 }, + "BWP": { "code": "BWP", "value": 13.7488325074 }, + "BYN": { "code": "BYN", "value": 3.2699770637 }, + "BYR": { "code": "BYR", "value": 32699.762594218 }, + "BZD": { "code": "BZD", "value": 2 }, + "CAD": { "code": "CAD", "value": 1.3758702027 }, + "CDF": { "code": "CDF", "value": 2813.442771238 }, + "CHF": { "code": "CHF", "value": 0.8965300987 }, + "CLF": { "code": "CLF", "value": 0.0242000032 }, + "CLP": { "code": "CLP", "value": 921.0413972452 }, + "CNY": { "code": "CNY", "value": 7.2501309285 }, + "COP": { "code": "COP", "value": 3937.3301467823 }, + "CRC": { "code": "CRC", "value": 530.3078152726 }, + "CUC": { "code": "CUC", "value": 1 }, + "CUP": { "code": "CUP", "value": 24 }, + "CVE": { "code": "CVE", "value": 102.4397237684 }, + "CZK": { "code": "CZK", "value": 22.8602433711 }, + "DAI": { "code": "DAI", "value": 0.9992989749 }, + "DJF": { "code": "DJF", "value": 177.721 }, + "DKK": { "code": "DKK", "value": 6.9279413087 }, + "DOP": { "code": "DOP", "value": 59.4084267105 }, + "DOT": { "code": "DOT", "value": 0.1535316848 }, + "DZD": { "code": "DZD", "value": 134.9637578508 }, + "EGP": { "code": "EGP", "value": 47.718617933 }, + "ERN": { "code": "ERN", "value": 15 }, + "ETB": { "code": "ETB", "value": 56.9702884224 }, + "ETH": { "code": "ETH", "value": 0.0002724481 }, + "EUR": { "code": "EUR", "value": 0.9290801473 }, + "FJD": { "code": "FJD", "value": 2.2394803828 }, + "FKP": { "code": "FKP", "value": 0.7857969946 }, + "GBP": { "code": "GBP", "value": 0.7857400856 }, + "GEL": { "code": "GEL", "value": 2.8200704628 }, + "GGP": { "code": "GGP", "value": 0.7857970595 }, + "GHS": { "code": "GHS", "value": 14.9096017346 }, + "GIP": { "code": "GIP", "value": 0.7857973594 }, + "GMD": { "code": "GMD", "value": 58.2027859377 }, + "GNF": { "code": "GNF", "value": 8587.8742589067 }, + "GTQ": { "code": "GTQ", "value": 7.758281421 }, + "GYD": { "code": "GYD", "value": 209.1970978965 }, + "HKD": { "code": "HKD", "value": 7.8103013923 }, + "HNL": { "code": "HNL", "value": 24.7146626422 }, + "HRK": { "code": "HRK", "value": 6.6516508793 }, + "HTG": { "code": "HTG", "value": 134.7838194535 }, + "HUF": { "code": "HUF", "value": 364.8563849752 }, + "IDR": { "code": "IDR", "value": 16267.59254452 }, + "ILS": { "code": "ILS", "value": 3.7498404871 }, + "IMP": { "code": "IMP", "value": 0.78579737 }, + "INR": { "code": "INR", "value": 83.5191700278 }, + "IQD": { "code": "IQD", "value": 1308.6456434348 }, + "IRR": { "code": "IRR", "value": 42019.979875943 }, + "ISK": { "code": "ISK", "value": 139.2122370989 }, + "JEP": { "code": "JEP", "value": 0.7857974327 }, + "JMD": { "code": "JMD", "value": 155.2491448209 }, + "JOD": { "code": "JOD", "value": 0.71 }, + "JPY": { "code": "JPY", "value": 157.014696987 }, + "KES": { "code": "KES", "value": 129.3930234152 }, + "KGS": { "code": "KGS", "value": 86.7532661567 }, + "KHR": { "code": "KHR", "value": 4112.3295097742 }, + "KMF": { "code": "KMF", "value": 458.5398427806 }, + "KPW": { "code": "KPW", "value": 900.002639873 }, + "KRW": { "code": "KRW", "value": 1372.7226101559 }, + "KWD": { "code": "KWD", "value": 0.3068600384 }, + "KYD": { "code": "KYD", "value": 0.83333 }, + "KZT": { "code": "KZT", "value": 448.5436886523 }, + "LAK": { "code": "LAK", "value": 21719.745960039 }, + "LBP": { "code": "LBP", "value": 89589.77614652 }, + "LKR": { "code": "LKR", "value": 301.8763925636 }, + "LRD": { "code": "LRD", "value": 194.250797033 }, + "LSL": { "code": "LSL", "value": 18.740072297 }, + "LTC": { "code": "LTC", "value": 0.012540671 }, + "LTL": { "code": "LTL", "value": 3.2079216576 }, + "LVL": { "code": "LVL", "value": 0.6529558367 }, + "LYD": { "code": "LYD", "value": 4.8691905541 }, + "MAD": { "code": "MAD", "value": 9.9428813366 }, + "MATIC": { "code": "MATIC", "value": 1.5370217613 }, + "MDL": { "code": "MDL", "value": 17.6269922085 }, + "MGA": { "code": "MGA", "value": 4480.2747953954 }, + "MKD": { "code": "MKD", "value": 57.3124669066 }, + "MMK": { "code": "MMK", "value": 2095.624577851 }, + "MNT": { "code": "MNT", "value": 3399.6088715777 }, + "MOP": { "code": "MOP", "value": 8.0643411333 }, + "MRO": { "code": "MRO", "value": 356.999828 }, + "MRU": { "code": "MRU", "value": 39.5001473678 }, + "MUR": { "code": "MUR", "value": 46.5937585965 }, + "MVR": { "code": "MVR", "value": 15.4579725536 }, + "MWK": { "code": "MWK", "value": 1734.397497359 }, + "MXN": { "code": "MXN", "value": 18.55754282 }, + "MYR": { "code": "MYR", "value": 4.7216406039 }, + "MZN": { "code": "MZN", "value": 63.6050485402 }, + "NAD": { "code": "NAD", "value": 18.6629134402 }, + "NGN": { "code": "NGN", "value": 1465.9738916374 }, + "NIO": { "code": "NIO", "value": 36.7972487975 }, + "NOK": { "code": "NOK", "value": 10.6432812966 }, + "NPR": { "code": "NPR", "value": 133.0858524888 }, + "NZD": { "code": "NZD", "value": 1.6312602969 }, + "OMR": { "code": "OMR", "value": 0.3842500724 }, + "OP": { "code": "OP", "value": 0.4569196376 }, + "PAB": { "code": "PAB", "value": 0.9988701052 }, + "PEN": { "code": "PEN", "value": 3.7826704942 }, + "PGK": { "code": "PGK", "value": 3.8124903888 }, + "PHP": { "code": "PHP", "value": 58.7150182203 }, + "PKR": { "code": "PKR", "value": 278.478689251 }, + "PLN": { "code": "PLN", "value": 4.0171006006 }, + "PYG": { "code": "PYG", "value": 7551.7849655727 }, + "QAR": { "code": "QAR", "value": 3.6411907088 }, + "RON": { "code": "RON", "value": 4.6227706077 }, + "RSD": { "code": "RSD", "value": 108.3531882033 }, + "RUB": { "code": "RUB", "value": 88.8936112341 }, + "RWF": { "code": "RWF", "value": 1301.7783053399 }, + "SAR": { "code": "SAR", "value": 3.7456707423 }, + "SBD": { "code": "SBD", "value": 8.3580865701 }, + "SCR": { "code": "SCR", "value": 14.8189315961 }, + "SDG": { "code": "SDG", "value": 601.5 }, + "SEK": { "code": "SEK", "value": 10.476081969 }, + "SGD": { "code": "SGD", "value": 1.3524701839 }, + "SHP": { "code": "SHP", "value": 0.7857401163 }, + "SLL": { "code": "SLL", "value": 22424.082202439 }, + "SOL": { "code": "SOL", "value": 0.0062829578 }, + "SOS": { "code": "SOS", "value": 571.0236810379 }, + "SRD": { "code": "SRD", "value": 31.4496958362 }, + "STD": { "code": "STD", "value": 22799.367791132 }, + "STN": { "code": "STN", "value": 22.7993551837 }, + "SVC": { "code": "SVC", "value": 8.75 }, + "SYP": { "code": "SYP", "value": 12994.621714013 }, + "SZL": { "code": "SZL", "value": 18.6989824867 }, + "THB": { "code": "THB", "value": 36.7206552011 }, + "TJS": { "code": "TJS", "value": 10.7309711957 }, + "TMT": { "code": "TMT", "value": 3.5 }, + "TND": { "code": "TND", "value": 3.1210104046 }, + "TOP": { "code": "TOP", "value": 2.341250381 }, + "TRY": { "code": "TRY", "value": 32.3123541442 }, + "TTD": { "code": "TTD", "value": 6.7413709853 }, + "TWD": { "code": "TWD", "value": 32.4375140234 }, + "TZS": { "code": "TZS", "value": 2593.4598939473 }, + "UAH": { "code": "UAH", "value": 40.3861148848 }, + "UGX": { "code": "UGX", "value": 3793.8622299526 }, + "USD": { "code": "USD", "value": 1 }, + "USDC": { "code": "USDC", "value": 0.9995108127 }, + "USDT": { "code": "USDT", "value": 0.9993678097 }, + "UYU": { "code": "UYU", "value": 38.8978562435 }, + "UZS": { "code": "UZS", "value": 12668.129512123 }, + "VEF": { "code": "VEF", "value": 3640407.7001116 }, + "VES": { "code": "VES", "value": 36.4040600039 }, + "VND": { "code": "VND", "value": 25421.433686036 }, + "VUV": { "code": "VUV", "value": 119.9011334188 }, + "WST": { "code": "WST", "value": 2.7389439335 }, + "XAF": { "code": "XAF", "value": 609.3574609173 }, + "XAG": { "code": "XAG", "value": 0.033659259 }, + "XAU": { "code": "XAU", "value": 0.0004329255 }, + "XCD": { "code": "XCD", "value": 2.7 }, + "XDR": { "code": "XDR", "value": 0.7558400986 }, + "XOF": { "code": "XOF", "value": 609.3574713759 }, + "XPD": { "code": "XPD", "value": 0.0011018596 }, + "XPF": { "code": "XPF", "value": 110.7528319197 }, + "XPT": { "code": "XPT", "value": 0.001027921 }, + "XRP": { "code": "XRP", "value": 2.0094059521 }, + "YER": { "code": "YER", "value": 249.9532931212 }, + "ZAR": { "code": "ZAR", "value": 18.7007830651 }, + "ZMK": { "code": "ZMK", "value": 9001.2 }, + "ZMW": { "code": "ZMW", "value": 26.4433644143 }, + "ZWL": { "code": "ZWL", "value": 13.5412641357 } + } +} diff --git a/src/infra/gateway/currency-api-gateway-online.ts b/src/infra/gateway/currency-api-gateway-online.ts new file mode 100644 index 000000000..eacc7ada1 --- /dev/null +++ b/src/infra/gateway/currency-api-gateway-online.ts @@ -0,0 +1,35 @@ +import env from '@/env'; +import { + CurrenciesResponse, + CurrencyApiGateway, + Filters, + RateResponse, +} from '@/infra/gateway/'; +import { HttpClient } from '@/infra/http-client'; + +export class CurrenciesApiGatewayOnline implements CurrencyApiGateway { + constructor(private readonly httpClient: HttpClient) { + httpClient.setSettings({ + baseURL: 'https://api.currencyapi.com/v3/', + headers: { + apiKey: env.CURRENCYAPI_API_KEY, + }, + }); + } + + getCurrencies(filters?: Filters): Promise { + const params: { [key: string]: any } = { + ...(filters?.currencies && { currencies: filters.currencies }), + ...(filters?.type && { type: filters.type }), + }; + return this.httpClient.get('/currencies', { params }); + } + + getRates(filters?: Filters): Promise { + const params: { [key: string]: any } = { + ...(filters?.currencies && { currencies: filters.currencies }), + ...(filters?.type && { type: filters.type }), + }; + return this.httpClient.get('/latest', { params }); + } +} diff --git a/src/infra/gateway/currency-api-gateway-static.ts b/src/infra/gateway/currency-api-gateway-static.ts new file mode 100644 index 000000000..e14abd27e --- /dev/null +++ b/src/infra/gateway/currency-api-gateway-static.ts @@ -0,0 +1,80 @@ +import { + CurrenciesResponse, + CurrencyApiGateway, + Filters, + RateResponse, +} from '@/infra/gateway/'; +import { readFileSync } from 'fs'; +import path from 'path'; + +export class CurrenciesApiGatewayStatic implements CurrencyApiGateway { + private currenciesMap: Map; + private ratesMap: Map; + private lastUpdatedAt!: Date; + + constructor() { + this.currenciesMap = new Map(); + this.ratesMap = new Map(); + this.loadData(); + } + + private async loadData(): Promise { + const currenciesFilePath = path.resolve( + __dirname, + './api.currencyapi-v3-currencies.json' + ); + const ratesFilePath = path.resolve( + __dirname, + './api.currencyapi-v3-latest.json' + ); + const currenciesData = readFileSync(currenciesFilePath, 'utf-8'); + const ratesData = readFileSync(ratesFilePath, 'utf-8'); + const currenciesResponse: CurrenciesResponse = JSON.parse(currenciesData); + const ratesResponse: RateResponse = JSON.parse(ratesData); + this.lastUpdatedAt = ratesResponse.meta.last_updated_at; + for (const [code, currency] of Object.entries(currenciesResponse.data)) { + this.currenciesMap.set(code, currency); + } + for (const [code, rate] of Object.entries(ratesResponse.data)) { + this.ratesMap.set(code, rate); + } + } + + async getCurrencies(filters?: Filters): Promise { + const filteredCurrencies = Array.from(this.currenciesMap.entries()).reduce( + (acc, [code, currency]) => { + if ( + (!filters?.currencies || filters.currencies.includes(code)) && + (!filters?.type || currency.type === filters.type) + ) { + acc[code] = currency; + } + return acc; + }, + {} as { [key: string]: any } + ); + + return { data: filteredCurrencies }; + } + + async getRates(filters?: Filters): Promise { + const filteredRates = Array.from(this.ratesMap.entries()).reduce( + (acc, [code, rate]) => { + if ( + (!filters?.currencies || filters.currencies.includes(code)) && + (!filters?.type || + this.currenciesMap.get(code)?.type === filters.type) + ) { + acc[code] = rate; + } + return acc; + }, + {} as { [key: string]: any } + ); + + return { + meta: { last_updated_at: this.lastUpdatedAt }, + data: filteredRates, + }; + } +} diff --git a/src/infra/gateway/currency-api-gateway.ts b/src/infra/gateway/currency-api-gateway.ts new file mode 100644 index 000000000..9cb0e1c1c --- /dev/null +++ b/src/infra/gateway/currency-api-gateway.ts @@ -0,0 +1,38 @@ +export interface CurrencyApiGateway { + getCurrencies(filters?: Filters): Promise; + getRates(filters?: Filters): Promise; +} + +export type Filters = { currencies?: string[]; type?: CurrencyType }; + +export type CurrencyType = 'fiat' | 'metal' | 'crypto'; + +export type CurrenciesResponse = { + data: { + [key: string]: { + symbol: string; + name: string; + symbol_native: string; + decimal_digits: number; + rounding: number; + code: string; + name_plural: string; + type: CurrencyType; + countries: string[]; + }; + }; +}; + +export type RateResponse = { + meta: { + last_updated_at: Date; + }; + data: { + [key: string]: { + code: string; + value: number; + }; + }; +}; + +export default CurrencyApiGateway; diff --git a/src/infra/gateway/index.ts b/src/infra/gateway/index.ts new file mode 100644 index 000000000..769c4db92 --- /dev/null +++ b/src/infra/gateway/index.ts @@ -0,0 +1,3 @@ +export * from './currency-api-gateway'; +export * from './currency-api-gateway-online'; +export * from './currency-api-gateway-static'; diff --git a/src/infra/http-client/axios-adapter.ts b/src/infra/http-client/axios-adapter.ts new file mode 100644 index 000000000..0b1223dbc --- /dev/null +++ b/src/infra/http-client/axios-adapter.ts @@ -0,0 +1,30 @@ +import HttpClient, { Options, Settings } from '@/infra/http-client/http-client'; +import axios from 'axios'; + +export class AxiosAdapter extends HttpClient { + api: axios.AxiosInstance; + + constructor(settings: Settings = { baseURL: '', headers: {} }) { + super(settings); + this.api = axios.create({ + baseURL: settings.baseURL, + headers: settings.headers, + }); + } + + async get(url: string, options?: Options): Promise { + const response = await this.api.get(url, options); + return response.data; + } + + setSettings(settings: { [k in keyof Settings]?: Settings[k] }): void { + if (settings.baseURL) this.api.defaults.baseURL = settings.baseURL; + if (settings.headers) { + for (const key in settings.headers) { + this.api.defaults.headers[key] = settings.headers[key]; + } + } + } +} + +export default AxiosAdapter; diff --git a/src/infra/http-client/http-client.ts b/src/infra/http-client/http-client.ts new file mode 100644 index 000000000..4b80ff3ab --- /dev/null +++ b/src/infra/http-client/http-client.ts @@ -0,0 +1,19 @@ +export abstract class HttpClient { + constructor(protected readonly settings: Settings) { + this.setSettings(settings); + } + abstract setSettings(settings: { [k in keyof Settings]?: Settings[k] }): void; + abstract get(url: string, options?: Options): Promise; +} + +export type Settings = { + baseURL: string; + headers: { [key: string]: string }; +}; + +export type Options = { + params?: { [key: string]: any }; + headers?: { [key: string]: string }; +}; + +export default HttpClient; diff --git a/src/infra/http-client/index.ts b/src/infra/http-client/index.ts new file mode 100644 index 000000000..51863ebef --- /dev/null +++ b/src/infra/http-client/index.ts @@ -0,0 +1,2 @@ +export * from './axios-adapter'; +export * from './http-client'; diff --git a/src/infra/http-server/controller.ts b/src/infra/http-server/controller.ts new file mode 100644 index 000000000..187331817 --- /dev/null +++ b/src/infra/http-server/controller.ts @@ -0,0 +1,17 @@ +export interface Controller< + TResponse extends Response = Response, + TRequest extends Request = Request, +> { + handle: (request: TRequest) => Promise; +} + +export type Request = { + query: { [key: string]: any }; + body: any; + params: { [key: string]: string }; +}; + +export type Response = { + statusCode: number; + data: T; +}; diff --git a/src/infra/http-server/convert-currency.controller.ts b/src/infra/http-server/convert-currency.controller.ts new file mode 100644 index 000000000..6cdd06b73 --- /dev/null +++ b/src/infra/http-server/convert-currency.controller.ts @@ -0,0 +1,46 @@ +import { ConvertCurrency } from '@/application/use-case'; +import { InvalidParamError, NotFoundError } from '@/domain/errors'; +import { Controller, Request, Response } from '@/infra/http-server/controller'; + +export class ConvertCurrencyController implements Controller { + constructor(private readonly convertCurrency: ConvertCurrency) {} + + async handle({ query }: Request): Promise { + try { + const input = { + from: query.from.toUpperCase(), + to: query.to.toUpperCase(), + amount: Number(query.amount), + }; + const output = await this.convertCurrency.execute(input); + return { + statusCode: 200, + data: { + from: input.from, + to: input.to, + givenAmount: input.amount, + convertedAmount: output.value, + decimalDigits: output.decimalDigits, + symbol: output.symbol, + convertedAmountFormatted: `${output.symbol} ${output.value.toFixed(output.decimalDigits)}`, + }, + }; + } catch (error: any) { + if (error instanceof NotFoundError) { + return { + statusCode: 404, + data: { message: error.message }, + }; + } + if (error instanceof InvalidParamError) { + return { + statusCode: 400, + data: { message: error.message }, + }; + } + throw error; + } + } +} + +export default ConvertCurrencyController; diff --git a/src/infra/http-server/create-currency.controller.ts b/src/infra/http-server/create-currency.controller.ts new file mode 100644 index 000000000..a47ad0193 --- /dev/null +++ b/src/infra/http-server/create-currency.controller.ts @@ -0,0 +1,36 @@ +import { CreateCurrencyRate } from '@/application/use-case'; +import { InvalidParamError } from '@/domain/errors'; +import { Controller, Request, Response } from '@/infra/http-server/controller'; + +export class CreateCurrencyController implements Controller { + constructor(private readonly createCurrencyRate: CreateCurrencyRate) {} + + async handle({ body }: Request): Promise { + try { + const input = { + name: body.name, + code: body.code, + symbol: body.symbol, + decimalDigits: body.decimalDigits, + baseAmount: body.baseAmount, + equivalentCurrencyAmount: body.equivalentCurrencyAmount, + equivalentCurrencyCode: body.equivalentCurrencyCode, + }; + const output = await this.createCurrencyRate.execute(input); + return { + statusCode: 200, + data: output, + }; + } catch (error: any) { + if (error instanceof InvalidParamError) { + return { + statusCode: 400, + data: { message: error.message }, + }; + } + throw error; + } + } +} + +export default CreateCurrencyController; diff --git a/src/infra/http-server/currencies.routes.ts b/src/infra/http-server/currencies.routes.ts new file mode 100644 index 000000000..c834ff4ab --- /dev/null +++ b/src/infra/http-server/currencies.routes.ts @@ -0,0 +1,56 @@ +import { Controller } from './controller'; +import { HttpServer } from './http-server'; + +export class CurrenciesRoutes { + private readonly listCurrenciesController?: Controller; + private readonly createCurrencyController: Controller; + private readonly convertCurrencyController: Controller; + private readonly getCurrencyByCodeController: Controller; + private readonly deleteCurrencyController: Controller; + + constructor(dependencies: Controllers) { + this.listCurrenciesController = dependencies.listCurrenciesController; + this.createCurrencyController = dependencies.createCurrencyController; + this.convertCurrencyController = dependencies.convertCurrencyController; + this.getCurrencyByCodeController = dependencies.getCurrencyByCodeController; + this.deleteCurrencyController = dependencies.deleteCurrencyController; + } + + registerRoutes(httpServer: HttpServer) { + if (this.listCurrenciesController) { + httpServer.register( + 'get', + '/api/v1/currencies', + this.listCurrenciesController + ); + } + httpServer.register( + 'post', + '/api/v1/currencies', + this.createCurrencyController + ); + httpServer.register( + 'get', + '/api/v1/currencies/convert', + this.convertCurrencyController + ); + httpServer.register( + 'get', + '/api/v1/currencies/{code}', + this.getCurrencyByCodeController + ); + httpServer.register( + 'delete', + '/api/v1/currencies/{code}', + this.deleteCurrencyController + ); + } +} + +type Controllers = { + listCurrenciesController?: Controller; + createCurrencyController: Controller; + convertCurrencyController: Controller; + getCurrencyByCodeController: Controller; + deleteCurrencyController: Controller; +}; diff --git a/src/infra/http-server/delete-currency.controller.ts b/src/infra/http-server/delete-currency.controller.ts new file mode 100644 index 000000000..5bbbd38bf --- /dev/null +++ b/src/infra/http-server/delete-currency.controller.ts @@ -0,0 +1,32 @@ +import { DeleteCurrencyRateByCode } from '@/application/use-case'; +import { CurrencyNotFoundError } from '@/domain/errors'; +import { Controller, Request, Response } from '@/infra/http-server/controller'; + +export class DeleteCurrencyController implements Controller { + constructor( + private readonly deleteCurrencyRateByCode: DeleteCurrencyRateByCode + ) {} + + async handle({ params }: Request): Promise { + try { + const code = params?.code.toUpperCase(); + await this.deleteCurrencyRateByCode.execute(code); + return { + statusCode: 200, + data: { + message: 'Currency deleted', + }, + }; + } catch (error: any) { + if (error instanceof CurrencyNotFoundError) { + return { + statusCode: 404, + data: { message: error.message }, + }; + } + throw error; + } + } +} + +export default DeleteCurrencyController; diff --git a/src/infra/http-server/express-adapter.ts b/src/infra/http-server/express-adapter.ts new file mode 100644 index 000000000..15deeeae5 --- /dev/null +++ b/src/infra/http-server/express-adapter.ts @@ -0,0 +1,47 @@ +import { HttpServer, Method } from '@/infra/http-server'; +import { Controller, Request } from '@/infra/http-server/controller'; +import swaggerDocument from '@/infra/http-server/swagger.json'; +import SwaggerUi from 'swagger-ui-express'; + +import express, { Express } from 'express'; + +export class ExpressAdapter implements HttpServer { + private app: Express; + + constructor() { + this.app = express(); + this.app.use(express.json()); + this.app.use( + '/api-docs', + SwaggerUi.serve, + SwaggerUi.setup(swaggerDocument) + ); + } + + register(method: Method, route: string, controller: Controller): void { + this.app[method]( + route.replace('}', '').replace('{', ':'), + async (req, res) => { + try { + const request: Request = { + query: req.query, + params: req.params, + body: req.body, + }; + const response = await controller.handle(request); + res.status(response.statusCode).json(response.data); + } catch (error: any) { + res + .status(500) + .json({ message: error.message || 'An unexpected error occurred' }); + } + } + ); + } + + listen(port: number): void { + this.app.listen(port, () => { + console.log(`Server running on port ${port}`); + }); + } +} diff --git a/src/infra/http-server/get-currency-by-code-query.controller.ts b/src/infra/http-server/get-currency-by-code-query.controller.ts new file mode 100644 index 000000000..26197b523 --- /dev/null +++ b/src/infra/http-server/get-currency-by-code-query.controller.ts @@ -0,0 +1,24 @@ +import { GetCurrencyByCodeQuery } from '@/application/query/'; +import { Controller, Request, Response } from '@/infra/http-server/controller'; + +export class GetCurrencyByCodeQueryController implements Controller { + constructor(private readonly getCurrencyByCode: GetCurrencyByCodeQuery) {} + + async handle({ params }: Request): Promise { + try { + const input = { + code: params.code?.toUpperCase(), + }; + const output = await this.getCurrencyByCode.execute(input); + return { + statusCode: 200, + data: output, + }; + } catch (error: any) { + console.error(error.message); + throw error; + } + } +} + +export default GetCurrencyByCodeQueryController; diff --git a/src/infra/http-server/get-currency-by-code.controller.ts b/src/infra/http-server/get-currency-by-code.controller.ts new file mode 100644 index 000000000..19cde9e52 --- /dev/null +++ b/src/infra/http-server/get-currency-by-code.controller.ts @@ -0,0 +1,22 @@ +import { GetCurrencyRateByCode } from '@/application/use-case'; +import { Controller, Request, Response } from '@/infra/http-server/controller'; + +export class GetCurrencyByCodeController implements Controller { + constructor(readonly getCurrencyByCode: GetCurrencyRateByCode) {} + + async handle({ params }: Request): Promise { + try { + const input = params.code?.toUpperCase(); + const output = await this.getCurrencyByCode.execute(input); + return { + statusCode: 200, + data: output, + }; + } catch (error: any) { + console.error(error.message); + throw error; + } + } +} + +export default GetCurrencyByCodeController; diff --git a/src/infra/http-server/hapi-adapter.ts b/src/infra/http-server/hapi-adapter.ts new file mode 100644 index 000000000..eae369b0e --- /dev/null +++ b/src/infra/http-server/hapi-adapter.ts @@ -0,0 +1,41 @@ +import { HttpServer, Method } from '@/infra/http-server'; +import { Controller, Request } from '@/infra/http-server/controller'; + +import Hapi from '@hapi/hapi'; + +export class HapiAdapter implements HttpServer { + private server: Hapi.Server; + + constructor() { + this.server = Hapi.server({}); + } + + register(method: Method, route: string, controller: Controller): void { + this.server.route({ + method, + path: route, + handler: async (req, res) => { + try { + const request: Request = { + query: req.query, + params: req.params, + body: req.payload, + }; + const result = await controller.handle(request); + return res.response(result.data).code(result.statusCode); + } catch (error: any) { + return res + .response({ + message: error.message || 'An unexpected error occurred', + }) + .code(500); + } + }, + }); + } + + listen(port: number): void { + this.server.settings.port = port; + this.server.start(); + } +} diff --git a/src/infra/http-server/http-server.ts b/src/infra/http-server/http-server.ts new file mode 100644 index 000000000..6a9ef0a26 --- /dev/null +++ b/src/infra/http-server/http-server.ts @@ -0,0 +1,8 @@ +import { Controller } from './controller'; + +export interface HttpServer { + register(method: Method, route: string, handler: Controller): void; + listen(port: number): void; +} + +export type Method = 'get' | 'post' | 'put' | 'delete'; diff --git a/src/infra/http-server/index.ts b/src/infra/http-server/index.ts new file mode 100644 index 000000000..f5d68fd78 --- /dev/null +++ b/src/infra/http-server/index.ts @@ -0,0 +1,10 @@ +export * from './convert-currency.controller'; +export * from './create-currency.controller'; +export * from './currencies.routes'; +export * from './delete-currency.controller'; +export * from './express-adapter'; +export * from './get-currency-by-code-query.controller'; +export * from './get-currency-by-code.controller'; +export * from './hapi-adapter'; +export * from './http-server'; +export * from './list-currencies.controller'; diff --git a/src/infra/http-server/list-currencies.controller.ts b/src/infra/http-server/list-currencies.controller.ts new file mode 100644 index 000000000..584d8299a --- /dev/null +++ b/src/infra/http-server/list-currencies.controller.ts @@ -0,0 +1,30 @@ +import { ListCurrenciesQuery } from '@/application/query/list-currencies-query'; +import { Controller, Request, Response } from '@/infra/http-server/controller'; + +export class ListCurrenciesController implements Controller { + constructor(private readonly listCurrencies: ListCurrenciesQuery) {} + + async handle({ query }: Request): Promise { + try { + const input = { + currencies: + query.currencies?.map((currency: string) => currency.toUpperCase()) || + [], + page: Number(query.page) || 1, + perPage: Number(query.perPage) || 10, + sortBy: query.sortBy || 'name', + sortOrder: query.sortOrder?.toUpperCase() || 'ASC', + }; + const output = await this.listCurrencies.execute(input); + return { + statusCode: 200, + data: output, + }; + } catch (error: any) { + console.error(error.message); + throw error; + } + } +} + +export default ListCurrenciesController; diff --git a/src/infra/http-server/swagger.json b/src/infra/http-server/swagger.json new file mode 100644 index 000000000..f84d839fb --- /dev/null +++ b/src/infra/http-server/swagger.json @@ -0,0 +1,343 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "API de Conversão Monetária", + "description": "API de Conversão Monetária para o desafio Bravo da empresa hurbcom", + "contact": { + "email": "leandro.e.reis@gmail.com", + "url": "https://www.linkedin.com/in/leandroepr/" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + }, + "version": "1.0.0" + }, + "servers": [ + { + "url": "http://localhost:3000/api/v1", + "description": "Servidor Local" + } + ], + "tags": [ + { + "name": "Currencies", + "description": "Operações com moedas" + } + ], + "basePath": "/api/v1", + "paths": { + "/currencies": { + "get": { + "tags": ["Currencies"], + "summary": "Lista de moedas", + "description": "Retorna a lista de moedas cadastradas", + "parameters": [ + { + "name": "currencies", + "in": "query", + "description": "Lista de moedas", + "required": false, + "schema": { + "type": "array", + "items": { "type": "string" } + } + }, + { + "name": "sortBy", + "in": "query", + "description": "Ordenação", + "required": false, + "schema": { + "type": "string", + "enum": ["name", "code", "rate"], + "default": "name" + } + }, + { + "name": "sortOrder", + "in": "query", + "description": "Ordem de ordenação", + "required": false, + "schema": { + "type": "string", + "enum": ["asc", "desc"], + "default": "asc" + } + }, + { + "name": "page", + "in": "query", + "description": "Página", + "required": false, + "schema": { "type": "number", "minimum": 1, "default": 1 } + }, + { + "name": "perPage", + "in": "query", + "description": "Número máximo de registros por página", + "required": false, + "schema": { + "type": "number", + "minimum": 10, + "maximum": 100, + "default": 10 + } + } + ], + "responses": { + "200": { + "description": "Lista paginada de moedas", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "meta": { + "type": "object", + "properties": { + "page": { "type": "number" }, + "perPage": { "type": "number" }, + "pageCount": { "type": "number" }, + "totalCount": { "type": "number" } + } + }, + "data": { + "type": "array", + "items": { "$ref": "#/components/schemas/Currency" } + } + } + } + } + } + } + } + }, + "post": { + "tags": ["Currencies"], + "summary": "Adiciona uma nova moeda", + "description": "Adiciona uma nova moeda ao sistema", + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "code": { "type": "string" }, + "symbol": { "type": "string" }, + "baseAmount": { "type": "number" }, + "equivalentCurrencyAmount": { "type": "number" }, + "equivalentCurrencyCode": { "type": "string" } + } + } + } + } + }, + "responses": { + "200": { + "description": "Moeda adicionada com sucesso", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "currencyId": { "type": "string" } + } + } + } + } + }, + "400": { + "description": "Erro na requisição", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { "type": "string" } + } + } + } + } + }, + "404": { + "description": "Moeda equivalente não encontrada", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { "type": "string" } + } + } + } + } + } + } + } + }, + "/currencies/convert": { + "get": { + "tags": ["Currencies"], + "summary": "Conversor de moedas", + "description": "Converte uma moeda para outra", + "parameters": [ + { + "name": "from", + "in": "query", + "description": "Moeda de origem", + "required": true, + "schema": { "type": "string" } + }, + { + "name": "to", + "in": "query", + "description": "Moeda de destino", + "required": true, + "schema": { "type": "string" } + }, + { + "name": "amount", + "in": "query", + "description": "Valor a ser convertido", + "required": true, + "schema": { "type": "number" } + } + ], + "responses": { + "200": { + "description": "Conversão realizada com sucesso", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "from": { "type": "string" }, + "to": { "type": "string" }, + "givenAmount": { "type": "number" }, + "convertedAmount": { "type": "number" }, + "convertedAmountFormatted": { "type": "string" }, + "decimalDigits": { "type": "number" }, + "symbol": { "type": "string" } + } + } + } + } + }, + "400": { + "description": "Erro na requisição", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { "type": "string" } + } + } + } + } + } + } + } + }, + "/currencies/{code}": { + "get": { + "tags": ["Currencies"], + "summary": "Busca uma moeda", + "description": "Busca uma moeda pelo código", + "parameters": [ + { + "name": "code", + "in": "path", + "description": "Código da moeda", + "required": true, + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "Moeda encontrada", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Currency" + } + } + } + }, + "404": { + "description": "Moeda não encontrada", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { "type": "string" } + } + } + } + } + } + } + }, + "delete": { + "tags": ["Currencies"], + "summary": "Remove uma moeda", + "description": "Remove uma moeda pelo código", + "parameters": [ + { + "name": "code", + "in": "path", + "description": "Código da moeda", + "required": true, + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "Moeda removida com sucesso", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { "type": "string" } + } + } + } + } + }, + "404": { + "description": "Moeda não encontrada", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { "type": "string" } + } + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "Currency": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "name": { "type": "string" }, + "code": { "type": "string" }, + "symbol": { "type": "string" }, + "decimalDigits": { "type": "number", "format": "integer" }, + "rate": { "type": "number", "format": "double" } + } + } + } + } +} diff --git a/src/infra/repository/currency-rate-repository-api.ts b/src/infra/repository/currency-rate-repository-api.ts new file mode 100644 index 000000000..102336b34 --- /dev/null +++ b/src/infra/repository/currency-rate-repository-api.ts @@ -0,0 +1,61 @@ +import { CurrencyRateRepository } from '@/application/repository/'; +import { CurrencyRate } from '@/domain/entity/'; +import { CurrencyNotFoundError } from '@/domain/errors/'; +import { CurrencyApiGateway } from '@/infra/gateway'; + +export class CurrencyRateRepositoryApi implements CurrencyRateRepository { + currencyMap: Map; + + constructor(private readonly currencyGateway: CurrencyApiGateway) { + this.currencyMap = new Map(); + } + + async findByCode(code: string): Promise { + if (this.currencyMap.has(code)) { + return this.currencyMap.get(code)!; + } + try { + const currencyResponse = await this.currencyGateway.getCurrencies({ + currencies: [code], + }); + const currencyData = currencyResponse.data[code]; + if (!currencyResponse.data[code] || !currencyResponse.data[code]) { + throw new CurrencyNotFoundError(code); + } + const rateResponse = await this.currencyGateway.getRates({ + currencies: [code], + }); + const rateData = rateResponse.data[code]; + const currency = new CurrencyRate( + currencyData.code, + currencyData.name, + currencyData.code, + currencyData.symbol, + currencyData.decimal_digits, + rateData.value + ); + return currency; + } catch (error: any) { + if (error?.message === 'Request failed with status code 422') { + throw new CurrencyNotFoundError(code); + } + throw error; + } + } + + async add(currencyRate: CurrencyRate): Promise { + if (this.currencyMap.has(currencyRate.code)) { + throw new Error('Currency already exists'); + } + this.currencyMap.set(currencyRate.code, currencyRate); + } + + async delete(code: string): Promise { + if (!this.currencyMap.has(code)) { + throw new Error('Currency not found'); + } + this.currencyMap.delete(code); + } +} + +export default CurrencyRateRepositoryApi; diff --git a/src/infra/repository/currency-rate-repository-database.ts b/src/infra/repository/currency-rate-repository-database.ts new file mode 100644 index 000000000..0630edc5c --- /dev/null +++ b/src/infra/repository/currency-rate-repository-database.ts @@ -0,0 +1,68 @@ +import { CurrencyRateRepository } from '@/application/repository'; +import { CurrencyRate } from '@/domain/entity/'; +import { CurrencyNotFoundError } from '@/domain/errors'; +import { DatabaseConnection } from '@/infra/database'; + +export class CurrencyRateRepositoryDatabase implements CurrencyRateRepository { + constructor(private readonly _connection: DatabaseConnection) {} + + async findByCode(code: string): Promise { + const [row] = await this._connection.query( + ` + SELECT c.id, c.name, c.code, c.symbol, c.decimal_digits, r.rate + FROM currency c + JOIN rate r ON c.id = r.currency_id + WHERE c.code = $1 + ORDER BY r.updated_at DESC + LIMIT 1 + `, + [code] + ); + if (!row) { + throw new CurrencyNotFoundError(code); + } + const currencyRate = new CurrencyRate( + row.id, + row.name, + row.code, + row.symbol, + row.decimal_digits, + Number(row.rate) + ); + return currencyRate; + } + + async add(currencyRate: CurrencyRate): Promise { + await this._connection.query( + ` + INSERT INTO currency (id, name, code, symbol, decimal_digits) + VALUES ($1, $2, $3, $4, $5)`, + [ + currencyRate.id, + currencyRate.name, + currencyRate.code, + currencyRate.symbol, + currencyRate.decimalDigits, + ] + ); + + await this._connection.query( + ` + INSERT INTO rate (currency_id, rate) + VALUES ($1, $2)`, + [currencyRate.id, currencyRate.rate] + ); + } + + async delete(code: string): Promise { + await this._connection.query( + ` + DELETE FROM currency + WHERE code = $1 + `, + [code] + ); + } +} + +export default CurrencyRateRepositoryDatabase; diff --git a/src/infra/repository/currency-rate-repository-fake.ts b/src/infra/repository/currency-rate-repository-fake.ts new file mode 100644 index 000000000..7889ff99e --- /dev/null +++ b/src/infra/repository/currency-rate-repository-fake.ts @@ -0,0 +1,52 @@ +import { CurrencyRateRepository } from '@/application/repository/'; +import { CurrencyRate } from '@/domain/entity/'; +import { CurrencyNotFoundError } from '@/domain/errors/'; + +export class CurrencyRateRepositoryFake implements CurrencyRateRepository { + currencyRates: CurrencyRate[]; + + constructor() { + this.currencyRates = [ + new CurrencyRate('1', 'US Dollar', 'USD', '$', 2, 1), + new CurrencyRate('2', 'Brazilian Real', 'BRL', 'R$', 2, 5.2), + new CurrencyRate('3', 'Euro', 'EUR', '€', 2, 0.92), + ]; + } + + async findByCode(code: string) { + const currencyRate = this.currencyRates.find( + (currencyRate) => currencyRate.code === code + ); + if (!currencyRate) { + throw new CurrencyNotFoundError(code); + } + return currencyRate; + } + + async add(currencyRate: CurrencyRate) { + const exists = await this.exists(currencyRate.code); + if (exists) { + throw new Error( + 'Currency rate with code ' + currencyRate.code + ' already exists' + ); + } + this.currencyRates.push(currencyRate); + } + + async delete(code: string) { + const index = this.currencyRates.findIndex( + (currencyRate) => currencyRate.code === code + ); + if (index !== -1) { + this.currencyRates.splice(index, 1); + } + } + + async exists(code: string) { + return this.currencyRates.some( + (currencyRate) => currencyRate.code === code + ); + } +} + +export default CurrencyRateRepositoryFake; diff --git a/src/infra/repository/index.ts b/src/infra/repository/index.ts new file mode 100644 index 000000000..033153c91 --- /dev/null +++ b/src/infra/repository/index.ts @@ -0,0 +1,3 @@ +export * from './currency-rate-repository-api'; +export * from './currency-rate-repository-database'; +export * from './currency-rate-repository-fake'; diff --git a/src/main/main-express-gateway-offline.ts b/src/main/main-express-gateway-offline.ts new file mode 100644 index 000000000..f7225430c --- /dev/null +++ b/src/main/main-express-gateway-offline.ts @@ -0,0 +1,47 @@ +import { + ConvertCurrency, + CreateCurrencyRate, + DeleteCurrencyRateByCode, + GetCurrencyRateByCode, +} from '@/application/use-case/'; +import env from '@/env'; +import { CurrenciesApiGatewayStatic } from '@/infra/gateway'; +import { + ConvertCurrencyController, + CreateCurrencyController, + CurrenciesRoutes, + DeleteCurrencyController, + ExpressAdapter, + GetCurrencyByCodeController, +} from '@/infra/http-server/'; +import { CurrencyRateRepositoryApi } from '@/infra/repository/'; + +const httpServer = new ExpressAdapter(); +const currencyGateway = new CurrenciesApiGatewayStatic(); +const currencyRateRepository = new CurrencyRateRepositoryApi(currencyGateway); +const createCurrencyRate = new CreateCurrencyRate(currencyRateRepository); +const convertCurrency = new ConvertCurrency(currencyRateRepository); +const getCurrencyByCode = new GetCurrencyRateByCode(currencyRateRepository); +const deleteCurrencyRateByCode = new DeleteCurrencyRateByCode( + currencyRateRepository +); +const createCurrencyController = new CreateCurrencyController( + createCurrencyRate +); +const convertCurrencyController = new ConvertCurrencyController( + convertCurrency +); +const getCurrencyByCodeController = new GetCurrencyByCodeController( + getCurrencyByCode +); +const deleteCurrencyController = new DeleteCurrencyController( + deleteCurrencyRateByCode +); +const currencyRoutes = new CurrenciesRoutes({ + createCurrencyController, + convertCurrencyController, + getCurrencyByCodeController, + deleteCurrencyController, +}); +currencyRoutes.registerRoutes(httpServer); +httpServer.listen(env.HTTP_SERVER_PORT); diff --git a/src/main/main-express-gateway-online.ts b/src/main/main-express-gateway-online.ts new file mode 100644 index 000000000..0d15ac2c4 --- /dev/null +++ b/src/main/main-express-gateway-online.ts @@ -0,0 +1,49 @@ +import { + ConvertCurrency, + CreateCurrencyRate, + DeleteCurrencyRateByCode, + GetCurrencyRateByCode, +} from '@/application/use-case/'; +import env from '@/env'; +import { CurrenciesApiGatewayOnline } from '@/infra/gateway'; +import { AxiosAdapter } from '@/infra/http-client'; +import { + ConvertCurrencyController, + CreateCurrencyController, + CurrenciesRoutes, + DeleteCurrencyController, + ExpressAdapter, + GetCurrencyByCodeController, +} from '@/infra/http-server/'; +import { CurrencyRateRepositoryApi } from '@/infra/repository/'; + +const httpServer = new ExpressAdapter(); +const httpClient = new AxiosAdapter(); +const currencyGateway = new CurrenciesApiGatewayOnline(httpClient); +const currencyRateRepository = new CurrencyRateRepositoryApi(currencyGateway); +const createCurrencyRate = new CreateCurrencyRate(currencyRateRepository); +const convertCurrency = new ConvertCurrency(currencyRateRepository); +const getCurrencyByCode = new GetCurrencyRateByCode(currencyRateRepository); +const deleteCurrencyRateByCode = new DeleteCurrencyRateByCode( + currencyRateRepository +); +const createCurrencyController = new CreateCurrencyController( + createCurrencyRate +); +const convertCurrencyController = new ConvertCurrencyController( + convertCurrency +); +const getCurrencyByCodeController = new GetCurrencyByCodeController( + getCurrencyByCode +); +const deleteCurrencyController = new DeleteCurrencyController( + deleteCurrencyRateByCode +); +const currencyRoutes = new CurrenciesRoutes({ + createCurrencyController, + convertCurrencyController, + getCurrencyByCodeController, + deleteCurrencyController, +}); +currencyRoutes.registerRoutes(httpServer); +httpServer.listen(env.HTTP_SERVER_PORT); diff --git a/src/main/main-express-with-fake.ts b/src/main/main-express-with-fake.ts new file mode 100644 index 000000000..644f842e5 --- /dev/null +++ b/src/main/main-express-with-fake.ts @@ -0,0 +1,45 @@ +import { + ConvertCurrency, + CreateCurrencyRate, + DeleteCurrencyRateByCode, + GetCurrencyRateByCode, +} from '@/application/use-case/'; +import env from '@/env'; +import { + ConvertCurrencyController, + CreateCurrencyController, + CurrenciesRoutes, + DeleteCurrencyController, + ExpressAdapter, + GetCurrencyByCodeController, +} from '@/infra/http-server/'; +import { CurrencyRateRepositoryFake } from '@/infra/repository/'; + +const httpServer = new ExpressAdapter(); +const currencyRateRepository = new CurrencyRateRepositoryFake(); +const createCurrencyRate = new CreateCurrencyRate(currencyRateRepository); +const convertCurrency = new ConvertCurrency(currencyRateRepository); +const getCurrencyByCode = new GetCurrencyRateByCode(currencyRateRepository); +const deleteCurrencyRateByCode = new DeleteCurrencyRateByCode( + currencyRateRepository +); +const createCurrencyController = new CreateCurrencyController( + createCurrencyRate +); +const convertCurrencyController = new ConvertCurrencyController( + convertCurrency +); +const getCurrencyByCodeController = new GetCurrencyByCodeController( + getCurrencyByCode +); +const deleteCurrencyController = new DeleteCurrencyController( + deleteCurrencyRateByCode +); +const currencyRoutes = new CurrenciesRoutes({ + createCurrencyController, + convertCurrencyController, + getCurrencyByCodeController, + deleteCurrencyController, +}); +currencyRoutes.registerRoutes(httpServer); +httpServer.listen(env.HTTP_SERVER_PORT); diff --git a/src/main/main-hapi-with-fake.ts b/src/main/main-hapi-with-fake.ts new file mode 100644 index 000000000..138185207 --- /dev/null +++ b/src/main/main-hapi-with-fake.ts @@ -0,0 +1,45 @@ +import { + ConvertCurrency, + CreateCurrencyRate, + DeleteCurrencyRateByCode, + GetCurrencyRateByCode, +} from '@/application/use-case/'; +import env from '@/env'; +import { + ConvertCurrencyController, + CreateCurrencyController, + CurrenciesRoutes, + DeleteCurrencyController, + GetCurrencyByCodeController, + HapiAdapter, +} from '@/infra/http-server/'; +import { CurrencyRateRepositoryFake } from '@/infra/repository/'; + +const httpServer = new HapiAdapter(); +const currencyRateRepository = new CurrencyRateRepositoryFake(); +const createCurrencyRate = new CreateCurrencyRate(currencyRateRepository); +const convertCurrency = new ConvertCurrency(currencyRateRepository); +const getCurrencyByCode = new GetCurrencyRateByCode(currencyRateRepository); +const deleteCurrencyRateByCode = new DeleteCurrencyRateByCode( + currencyRateRepository +); +const createCurrencyController = new CreateCurrencyController( + createCurrencyRate +); +const convertCurrencyController = new ConvertCurrencyController( + convertCurrency +); +const getCurrencyByCodeController = new GetCurrencyByCodeController( + getCurrencyByCode +); +const deleteCurrencyController = new DeleteCurrencyController( + deleteCurrencyRateByCode +); +const currencyRoutes = new CurrenciesRoutes({ + createCurrencyController, + convertCurrencyController, + getCurrencyByCodeController, + deleteCurrencyController, +}); +currencyRoutes.registerRoutes(httpServer); +httpServer.listen(env.HTTP_SERVER_PORT); diff --git a/src/main/main.ts b/src/main/main.ts new file mode 100644 index 000000000..f0bafaddb --- /dev/null +++ b/src/main/main.ts @@ -0,0 +1,52 @@ +import { GetCurrencyByCodeQuery } from '@/application/query'; +import { ListCurrenciesQuery } from '@/application/query/'; +import { + ConvertCurrency, + CreateCurrencyRate, + DeleteCurrencyRateByCode, +} from '@/application/use-case/'; +import env from '@/env'; +import { PgPromiseAdapter } from '@/infra/database/'; +import { + ConvertCurrencyController, + CreateCurrencyController, + CurrenciesRoutes, + DeleteCurrencyController, + ExpressAdapter, + GetCurrencyByCodeQueryController, + ListCurrenciesController, +} from '@/infra/http-server/'; +import { CurrencyRateRepositoryDatabase } from '@/infra/repository/'; + +const httpServer = new ExpressAdapter(); +const connection = new PgPromiseAdapter(); +const listCurrencies = new ListCurrenciesQuery(connection); +const currencyRateRepository = new CurrencyRateRepositoryDatabase(connection); +const createCurrencyRate = new CreateCurrencyRate(currencyRateRepository); +const convertCurrency = new ConvertCurrency(currencyRateRepository); +const getCurrencyByCodeQuery = new GetCurrencyByCodeQuery(connection); +const deleteCurrencyRateByCode = new DeleteCurrencyRateByCode( + currencyRateRepository +); +const listCurrenciesController = new ListCurrenciesController(listCurrencies); +const createCurrencyController = new CreateCurrencyController( + createCurrencyRate +); +const convertCurrencyController = new ConvertCurrencyController( + convertCurrency +); +const getCurrencyByCodeController = new GetCurrencyByCodeQueryController( + getCurrencyByCodeQuery +); +const deleteCurrencyController = new DeleteCurrencyController( + deleteCurrencyRateByCode +); +const currencyRoutes = new CurrenciesRoutes({ + listCurrenciesController, + createCurrencyController, + convertCurrencyController, + getCurrencyByCodeController, + deleteCurrencyController, +}); +currencyRoutes.registerRoutes(httpServer); +httpServer.listen(env.HTTP_SERVER_PORT); diff --git a/test/integration/api.test.ts b/test/integration/api.test.ts new file mode 100644 index 000000000..cfc18a1b6 --- /dev/null +++ b/test/integration/api.test.ts @@ -0,0 +1,93 @@ +import axios from 'axios'; + +describe('Main API', () => { + it('should create, get, convert and delete a currency rate', async () => { + const payload = { + name: 'Grand Theft Auto Dollar', + symbol: 'GTA$', + code: 'gta', + decimalDigits: 2, + baseAmount: 1250000.0, + equivalentCurrencyCode: 'brl', + equivalentCurrencyAmount: 83.5, + }; + await axios.post('http://localhost:3000/api/v1/currencies', payload); + const getResponse = await axios.get( + `http://localhost:3000/api/v1/currencies/${payload.code}` + ); + const getOutput = getResponse.data; + expect(getOutput.name).toEqual(payload.name); + expect(getOutput.code).toEqual(payload.code.toUpperCase()); + expect(getOutput.symbol).toEqual(payload.symbol); + expect(getOutput.decimalDigits).toEqual(payload.decimalDigits); + expect(getOutput.rate).toBeDefined(); + const convertParams = { from: 'brl', to: 'gta', amount: 83.5 }; + const convertResponse = await axios.get( + 'http://localhost:3000/api/v1/currencies/convert', + { params: convertParams } + ); + const convertOutput = convertResponse.data; + expect(convertOutput.from).toBe('BRL'); + expect(convertOutput.to).toBe('GTA'); + expect(convertOutput.givenAmount).toBe(83.5); + expect(convertOutput.convertedAmount).toBe(1250000); + expect(convertOutput.convertedAmountFormatted).toContain('GTA$ 1250000.00'); + const deleteResponse = await axios.delete( + `http://localhost:3000/api/v1/currencies/${getOutput.code}` + ); + const deleteOutput = deleteResponse.data; + expect(deleteOutput).toEqual({ message: 'Currency deleted' }); + expect(deleteResponse.status).toBe(200); + }); + + it('should throw an error when trying to create a currency with invalid name', async () => { + const payload = { + name: '', + code: 'ANY', + symbol: '$', + decimalDigits: 2, + baseAmount: 2, + equivalentCurrencyAmount: 1, + equivalentCurrencyCode: 'USD', + }; + try { + await axios.post('http://localhost:3000/api/v1/currencies', payload); + } catch (error: any) { + expect(error.response.data.message).toBe('Invalid name'); + expect(error.response.status).toBe(400); + } + }); + + it('should throw an error when trying to convert with invalid currency', async () => { + const params = { from: 'INVALID', to: 'BRL', amount: 10 }; + try { + await axios.get('http://localhost:3000/api/v1/currencies/convert', { + params, + }); + } catch (error: any) { + expect(error.response.data.message).toBe('Currency not found: INVALID'); + expect(error.response.status).toBe(404); + } + }); + + it('should throw an error when trying to convert with invalid amount', async () => { + const params = { from: 'USD', to: 'BRL', amount: -10 }; + try { + await axios.get('http://localhost:3000/api/v1/currencies/convert', { + params, + }); + } catch (error: any) { + expect(error.response.data.message).toEqual('Invalid amount'); + expect(error.response.status).toBe(400); + } + }); + + it('should throw an error when trying to delete an invalid currency', async () => { + try { + await axios.delete('http://localhost:3000/api/v1/currencies/INVALID'); + } catch (error: any) { + expect(error.response.data.message).toBe('Currency not found: INVALID'); + expect(error.response.status).toBe(404); + } + }); +}); diff --git a/test/unity/convert-currency.test.ts b/test/unity/convert-currency.test.ts new file mode 100644 index 000000000..e2af27c97 --- /dev/null +++ b/test/unity/convert-currency.test.ts @@ -0,0 +1,74 @@ +import { ConvertCurrency } from '@/application/use-case'; +import { CurrencyRateRepositoryFake } from '@/infra/repository/'; + +describe('Currency Converter', () => { + let currencyRateRepository: CurrencyRateRepositoryFake; + let convertCurrency: ConvertCurrency; + + beforeEach(() => { + currencyRateRepository = new CurrencyRateRepositoryFake(); + convertCurrency = new ConvertCurrency(currencyRateRepository); + }); + + it('should convert USD to BRL', async () => { + const input = { + from: 'USD', + to: 'BRL', + amount: 1, + }; + const result = await convertCurrency.execute(input); + expect(result.value).toBe(5.2); + }); + + it('should convert BRL to USD', async () => { + const input = { + from: 'BRL', + to: 'USD', + amount: 5.2, + }; + const result = await convertCurrency.execute(input); + expect(result.value).toBe(1.0); + }); + + it('should convert USD to EUR', async () => { + const input = { + from: 'USD', + to: 'EUR', + amount: 1, + }; + const result = await convertCurrency.execute(input); + expect(result.value).toBe(0.92); + }); + + it('should convert EUR to BRL', async () => { + const input = { + from: 'EUR', + to: 'BRL', + amount: 1, + }; + const result = await convertCurrency.execute(input); + expect(result.value).toBe(5.65); + }); + + it('should throw an error when the currency is not found', async () => { + const input = { + from: 'INVALID', + to: 'BRL', + amount: 1, + }; + await expect(convertCurrency.execute(input)).rejects.toThrow( + 'Currency not found' + ); + }); + + it('should throw an error when the amount is invalid', async () => { + const input = { + from: 'USD', + to: 'BRL', + amount: -1, + }; + await expect(convertCurrency.execute(input)).rejects.toThrow( + 'Invalid amount' + ); + }); +}); diff --git a/test/unity/create-currency-rate.test.ts b/test/unity/create-currency-rate.test.ts new file mode 100644 index 000000000..66faebe0a --- /dev/null +++ b/test/unity/create-currency-rate.test.ts @@ -0,0 +1,53 @@ +import { + CreateCurrencyRate, + GetCurrencyRateByCode, +} from '@/application/use-case/'; +import { CurrencyRateRepositoryFake } from '@/infra/repository/'; + +describe('create-currency-rate', () => { + it('should create a currency', async () => { + const currencyRateRepository = new CurrencyRateRepositoryFake(); + const createCurrency = new CreateCurrencyRate(currencyRateRepository); + const createCurrencyInput = { + name: 'Grand Theft Auto Dollar', + symbol: 'GTA$', + code: 'GTA', + decimalDigits: 2, + baseAmount: 1250000.0, + equivalentCurrencyCode: 'BRL', + equivalentCurrencyAmount: 83.5, + }; + await createCurrency.execute(createCurrencyInput); + const getCurrencyRateByCode = new GetCurrencyRateByCode( + currencyRateRepository + ); + const getCurrencyOutput = await getCurrencyRateByCode.execute( + createCurrencyInput.code + ); + expect(getCurrencyOutput.name).toBe(createCurrencyInput.name); + expect(getCurrencyOutput.symbol).toBe(createCurrencyInput.symbol); + expect(getCurrencyOutput.code).toBe(createCurrencyInput.code); + expect(getCurrencyOutput.decimalDigits).toBe( + createCurrencyInput.decimalDigits + ); + expect(getCurrencyOutput.rate).toBe(77844.31137724551); + }); + + it('should not create a currency with duplicated code', async () => { + const currencyRateRepository = new CurrencyRateRepositoryFake(); + const createCurrency = new CreateCurrencyRate(currencyRateRepository); + const createCurrencyInput = { + name: 'Any Currency', + code: 'ANY', + symbol: 'A$', + decimalDigits: 2, + baseAmount: 1.0, + equivalentCurrencyCode: 'USD', + equivalentCurrencyAmount: 1.0, + }; + await createCurrency.execute(createCurrencyInput); + await expect(createCurrency.execute(createCurrencyInput)).rejects.toThrow( + 'Currency rate with code ANY already exists' + ); + }); +}); diff --git a/test/unity/currenty-rate.test.ts b/test/unity/currenty-rate.test.ts new file mode 100644 index 000000000..adc8e07d4 --- /dev/null +++ b/test/unity/currenty-rate.test.ts @@ -0,0 +1,98 @@ +import { CurrencyRate } from '@/domain/entity/'; +import { InvalidParamError } from '@/domain/errors'; + +describe('Currency Rate', () => { + it('should create a currency rate', () => { + const currencyRate = CurrencyRate.create('US Dollar', 'USD', '$', 2, 1); + expect(currencyRate).toBeDefined(); + }); + + it('should convert an amount to another currency', () => { + const usdCurrencyRate = CurrencyRate.create('US Dollar', 'USD', '$', 2, 1); + const brlCurrencyRate = CurrencyRate.create( + 'Brazilian Real', + 'BRL', + 'R$', + 2, + 5.2 + ); + expect(usdCurrencyRate.convertTo(brlCurrencyRate, 1)).toBe(5.2); + expect(usdCurrencyRate.convertTo(brlCurrencyRate, 2)).toBe(10.4); + expect(brlCurrencyRate.convertTo(usdCurrencyRate, 5.2)).toBe(1); + expect(brlCurrencyRate.convertTo(usdCurrencyRate, 10.4)).toBe(2); + }); + + it('should throw an error when the rate is invalid', () => { + try { + CurrencyRate.create('US Dollar', 'USD', '$', 2, 0); + fail('Expected to throw an error'); + } catch (error: any) { + expect(error).toBeInstanceOf(InvalidParamError); + expect(error.message).toBe('Invalid rate'); + } + try { + CurrencyRate.create('US Dollar', 'USD', '$', 2, -1); + fail('Expected to throw an error'); + } catch (error: any) { + expect(error).toBeInstanceOf(InvalidParamError); + expect(error.message).toBe('Invalid rate'); + } + }); + + it('should throw an error when the name is invalid', () => { + try { + CurrencyRate.create('', 'USD', '$', 2, 1); + fail('Expected to throw an error'); + } catch (error: any) { + expect(error).toBeInstanceOf(InvalidParamError); + expect(error.message).toBe('Invalid name'); + } + }); + + it('should throw an error when the code is invalid', () => { + try { + CurrencyRate.create('US Dollar', '', '$', 2, 1); + fail('Expected to throw an error'); + } catch (error: any) { + expect(error).toBeInstanceOf(InvalidParamError); + expect(error.message).toBe('Invalid code'); + } + }); + + it('should throw an error when the symbol is invalid', () => { + try { + CurrencyRate.create('US Dollar', 'USD', '', 2, 1); + fail('Expected to throw an error'); + } catch (error: any) { + expect(error).toBeInstanceOf(InvalidParamError); + expect(error.message).toBe('Invalid symbol'); + } + }); + + it('should throw an error when the decimal digits is invalid', () => { + try { + CurrencyRate.create('US Dollar', 'USD', '$', -1, 1); + fail('Expected to throw an error'); + } catch (error: any) { + expect(error).toBeInstanceOf(InvalidParamError); + expect(error.message).toBe('Invalid decimal digits'); + } + }); + + it('should throw an error when the rate is invalid', () => { + try { + CurrencyRate.create('US Dollar', 'USD', '$', 2, 0); + fail('Expected to throw an error'); + } catch (error: any) { + expect(error).toBeInstanceOf(InvalidParamError); + expect(error.message).toBe('Invalid rate'); + } + try { + CurrencyRate.create('US Dollar', 'USD', '$', 2, -1); + fail('Expected to throw an error'); + } catch (error: any) { + expect(error).toBeInstanceOf(InvalidParamError); + expect(error.message).toBe('Invalid rate'); + } + }); +}); diff --git a/test/unity/delete-currency-rate.test.ts b/test/unity/delete-currency-rate.test.ts new file mode 100644 index 000000000..3199b1e19 --- /dev/null +++ b/test/unity/delete-currency-rate.test.ts @@ -0,0 +1,53 @@ +import { + CreateCurrencyRate, + DeleteCurrencyRateByCode, + GetCurrencyRateByCode, +} from '@/application/use-case/'; +import { CurrencyRateRepositoryFake } from '@/infra/repository/'; + +describe('delete-currency-rate', () => { + it('should delete a currency rate by code', async () => { + const currencyRateRepository = new CurrencyRateRepositoryFake(); + const createCurrency = new CreateCurrencyRate(currencyRateRepository); + const createCurrencyInput = { + name: 'Any Currency', + symbol: 'AC$', + code: 'AYC', + decimalDigits: 2, + baseAmount: 1.0, + equivalentCurrencyCode: 'USD', + equivalentCurrencyAmount: 1.0, + }; + await createCurrency.execute(createCurrencyInput); + const deleteCurrencyRate = new DeleteCurrencyRateByCode( + currencyRateRepository + ); + await deleteCurrencyRate.execute(createCurrencyInput.code); + const getCurrencyRateByCode = new GetCurrencyRateByCode( + currencyRateRepository + ); + await expect( + getCurrencyRateByCode.execute(createCurrencyInput.code) + ).rejects.toThrow('Currency not found'); + }); + + it('should throw an error when trying to delete a currency rate that does not exist', async () => { + const currencyRateRepository = new CurrencyRateRepositoryFake(); + const deleteCurrencyRate = new DeleteCurrencyRateByCode( + currencyRateRepository + ); + await expect(deleteCurrencyRate.execute('ABC')).rejects.toThrow( + 'Currency not found' + ); + }); + + it('should throw an error when trying to delete USD currency rate', async () => { + const currencyRateRepository = new CurrencyRateRepositoryFake(); + const deleteCurrencyRate = new DeleteCurrencyRateByCode( + currencyRateRepository + ); + await expect(deleteCurrencyRate.execute('USD')).rejects.toThrow( + 'Cannot delete USD currency rate' + ); + }); +}); diff --git a/test/unity/equivalent-rate-calculator.test.ts b/test/unity/equivalent-rate-calculator.test.ts new file mode 100644 index 000000000..c1b0ee4c8 --- /dev/null +++ b/test/unity/equivalent-rate-calculator.test.ts @@ -0,0 +1,32 @@ +import { EquivalentRateCalculator } from '@/application/service/'; + +describe('equivalent-rate-calculator', () => { + it('should calculate the equivalent rate of BRL in USD', async () => { + const equivalentRateCalculator = new EquivalentRateCalculator(1); + expect(equivalentRateCalculator.calculateRate(5.2, 1.0)).toBe(5.2); + expect(equivalentRateCalculator.calculateRate(10.4, 2.0)).toBe(5.2); + }); + + it('should calculate the equivalent rate of GTA$ in BRL', async () => { + const equivalentRateCalculator = new EquivalentRateCalculator(5.2); + const equivalentRate = equivalentRateCalculator.calculateRate( + 1250000.0, + 83.5 + ); + expect(equivalentRate).toBe(77844.31137724551); + }); + + it('should throw an error when the base amount is invalid', async () => { + const equivalentRateCalculator = new EquivalentRateCalculator(1); + expect(() => equivalentRateCalculator.calculateRate(-1, 1)).toThrow( + 'Invalid param: baseAmount' + ); + }); + + it('should throw an error when the equivalent currency amount is invalid', async () => { + const equivalentRateCalculator = new EquivalentRateCalculator(1); + expect(() => equivalentRateCalculator.calculateRate(1, -1)).toThrow( + 'Invalid param: equivalentCurrencyAmount' + ); + }); +}); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 000000000..57f2f84ec --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,113 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "ES2022", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "lib": ["ES2023"], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "node16", /* Specify what module code is generated. */ + // "rootDir": "./", /* Specify the root folder within your source files. */ + // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ + "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + "paths": { + "@/*": ["src/*"], + }, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ + // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ + // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ + // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ + "resolveJsonModule": true, /* Enable importing .json files. */ + // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + "outDir": "./dist", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + }, + "include": ["src/**/*", "test/**/*"], + "exclude": ["node_modules", "dist", "coverage"], +} diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 000000000..5af83d17a --- /dev/null +++ b/yarn.lock @@ -0,0 +1,3948 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ampproject/remapping@^2.2.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" + integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.24.6": + version "7.24.6" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.6.tgz#ab88da19344445c3d8889af2216606d3329f3ef2" + integrity sha512-ZJhac6FkEd1yhG2AHOmfcXG4ceoLltoCVJjN5XsWN9BifBQr+cHJbWi0h68HZuSORq+3WtJ2z0hwF2NG1b5kcA== + dependencies: + "@babel/highlight" "^7.24.6" + picocolors "^1.0.0" + +"@babel/compat-data@^7.24.6": + version "7.24.6" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.24.6.tgz#b3600217688cabb26e25f8e467019e66d71b7ae2" + integrity sha512-aC2DGhBq5eEdyXWqrDInSqQjO0k8xtPRf5YylULqx8MCd6jBtzqfta/3ETMRpuKIc5hyswfO80ObyA1MvkCcUQ== + +"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9": + version "7.24.6" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.24.6.tgz#8650e0e4b03589ebe886c4e4a60398db0a7ec787" + integrity sha512-qAHSfAdVyFmIvl0VHELib8xar7ONuSHrE2hLnsaWkYNTI68dmi1x8GYDhJjMI/e7XWal9QBlZkwbOnkcw7Z8gQ== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.24.6" + "@babel/generator" "^7.24.6" + "@babel/helper-compilation-targets" "^7.24.6" + "@babel/helper-module-transforms" "^7.24.6" + "@babel/helpers" "^7.24.6" + "@babel/parser" "^7.24.6" + "@babel/template" "^7.24.6" + "@babel/traverse" "^7.24.6" + "@babel/types" "^7.24.6" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/generator@^7.24.6", "@babel/generator@^7.7.2": + version "7.24.6" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.6.tgz#dfac82a228582a9d30c959fe50ad28951d4737a7" + integrity sha512-S7m4eNa6YAPJRHmKsLHIDJhNAGNKoWNiWefz1MBbpnt8g9lvMDl1hir4P9bo/57bQEmuwEhnRU/AMWsD0G/Fbg== + dependencies: + "@babel/types" "^7.24.6" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" + jsesc "^2.5.1" + +"@babel/helper-compilation-targets@^7.24.6": + version "7.24.6" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.6.tgz#4a51d681f7680043d38e212715e2a7b1ad29cb51" + integrity sha512-VZQ57UsDGlX/5fFA7GkVPplZhHsVc+vuErWgdOiysI9Ksnw0Pbbd6pnPiR/mmJyKHgyIW0c7KT32gmhiF+cirg== + dependencies: + "@babel/compat-data" "^7.24.6" + "@babel/helper-validator-option" "^7.24.6" + browserslist "^4.22.2" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-environment-visitor@^7.24.6": + version "7.24.6" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.6.tgz#ac7ad5517821641550f6698dd5468f8cef78620d" + integrity sha512-Y50Cg3k0LKLMjxdPjIl40SdJgMB85iXn27Vk/qbHZCFx/o5XO3PSnpi675h1KEmmDb6OFArfd5SCQEQ5Q4H88g== + +"@babel/helper-function-name@^7.24.6": + version "7.24.6" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.24.6.tgz#cebdd063386fdb95d511d84b117e51fc68fec0c8" + integrity sha512-xpeLqeeRkbxhnYimfr2PC+iA0Q7ljX/d1eZ9/inYbmfG2jpl8Lu3DyXvpOAnrS5kxkfOWJjioIMQsaMBXFI05w== + dependencies: + "@babel/template" "^7.24.6" + "@babel/types" "^7.24.6" + +"@babel/helper-hoist-variables@^7.24.6": + version "7.24.6" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.6.tgz#8a7ece8c26756826b6ffcdd0e3cf65de275af7f9" + integrity sha512-SF/EMrC3OD7dSta1bLJIlrsVxwtd0UpjRJqLno6125epQMJ/kyFmpTT4pbvPbdQHzCHg+biQ7Syo8lnDtbR+uA== + dependencies: + "@babel/types" "^7.24.6" + +"@babel/helper-module-imports@^7.24.6": + version "7.24.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.6.tgz#65e54ffceed6a268dc4ce11f0433b82cfff57852" + integrity sha512-a26dmxFJBF62rRO9mmpgrfTLsAuyHk4e1hKTUkD/fcMfynt8gvEKwQPQDVxWhca8dHoDck+55DFt42zV0QMw5g== + dependencies: + "@babel/types" "^7.24.6" + +"@babel/helper-module-transforms@^7.24.6": + version "7.24.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.24.6.tgz#22346ed9df44ce84dee850d7433c5b73fab1fe4e" + integrity sha512-Y/YMPm83mV2HJTbX1Qh2sjgjqcacvOlhbzdCCsSlblOKjSYmQqEbO6rUniWQyRo9ncyfjT8hnUjlG06RXDEmcA== + dependencies: + "@babel/helper-environment-visitor" "^7.24.6" + "@babel/helper-module-imports" "^7.24.6" + "@babel/helper-simple-access" "^7.24.6" + "@babel/helper-split-export-declaration" "^7.24.6" + "@babel/helper-validator-identifier" "^7.24.6" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.24.6", "@babel/helper-plugin-utils@^7.8.0": + version "7.24.6" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.6.tgz#fa02a32410a15a6e8f8185bcbf608f10528d2a24" + integrity sha512-MZG/JcWfxybKwsA9N9PmtF2lOSFSEMVCpIRrbxccZFLJPrJciJdG/UhSh5W96GEteJI2ARqm5UAHxISwRDLSNg== + +"@babel/helper-simple-access@^7.24.6": + version "7.24.6" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.24.6.tgz#1d6e04d468bba4fc963b4906f6dac6286cfedff1" + integrity sha512-nZzcMMD4ZhmB35MOOzQuiGO5RzL6tJbsT37Zx8M5L/i9KSrukGXWTjLe1knIbb/RmxoJE9GON9soq0c0VEMM5g== + dependencies: + "@babel/types" "^7.24.6" + +"@babel/helper-split-export-declaration@^7.24.6": + version "7.24.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.6.tgz#e830068f7ba8861c53b7421c284da30ae656d7a3" + integrity sha512-CvLSkwXGWnYlF9+J3iZUvwgAxKiYzK3BWuo+mLzD/MDGOZDj7Gq8+hqaOkMxmJwmlv0iu86uH5fdADd9Hxkymw== + dependencies: + "@babel/types" "^7.24.6" + +"@babel/helper-string-parser@^7.24.6": + version "7.24.6" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.6.tgz#28583c28b15f2a3339cfafafeaad42f9a0e828df" + integrity sha512-WdJjwMEkmBicq5T9fm/cHND3+UlFa2Yj8ALLgmoSQAJZysYbBjw+azChSGPN4DSPLXOcooGRvDwZWMcF/mLO2Q== + +"@babel/helper-validator-identifier@^7.24.6": + version "7.24.6" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.6.tgz#08bb6612b11bdec78f3feed3db196da682454a5e" + integrity sha512-4yA7s865JHaqUdRbnaxarZREuPTHrjpDT+pXoAZ1yhyo6uFnIEpS8VMu16siFOHDpZNKYv5BObhsB//ycbICyw== + +"@babel/helper-validator-option@^7.24.6": + version "7.24.6" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.24.6.tgz#59d8e81c40b7d9109ab7e74457393442177f460a" + integrity sha512-Jktc8KkF3zIkePb48QO+IapbXlSapOW9S+ogZZkcO6bABgYAxtZcjZ/O005111YLf+j4M84uEgwYoidDkXbCkQ== + +"@babel/helpers@^7.24.6": + version "7.24.6" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.24.6.tgz#cd124245299e494bd4e00edda0e4ea3545c2c176" + integrity sha512-V2PI+NqnyFu1i0GyTd/O/cTpxzQCYioSkUIRmgo7gFEHKKCg5w46+r/A6WeUR1+P3TeQ49dspGPNd/E3n9AnnA== + dependencies: + "@babel/template" "^7.24.6" + "@babel/types" "^7.24.6" + +"@babel/highlight@^7.24.6": + version "7.24.6" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.6.tgz#6d610c1ebd2c6e061cade0153bf69b0590b7b3df" + integrity sha512-2YnuOp4HAk2BsBrJJvYCbItHx0zWscI1C3zgWkz+wDyD9I7GIVrfnLyrR4Y1VR+7p+chAEcrgRQYZAGIKMV7vQ== + dependencies: + "@babel/helper-validator-identifier" "^7.24.6" + chalk "^2.4.2" + js-tokens "^4.0.0" + picocolors "^1.0.0" + +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.24.6": + version "7.24.6" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.6.tgz#5e030f440c3c6c78d195528c3b688b101a365328" + integrity sha512-eNZXdfU35nJC2h24RznROuOpO94h6x8sg9ju0tT9biNtLZ2vuP8SduLqqV+/8+cebSLV9SJEAN5Z3zQbJG/M+Q== + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.8.3": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-import-meta@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-jsx@^7.7.2": + version "7.24.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.6.tgz#bcca2964150437f88f65e3679e3d68762287b9c8" + integrity sha512-lWfvAIFNWMlCsU0DRUun2GpFwZdGTukLaHJqRh1JRb80NdAP5Sb1HDHB5X9P9OtgZHQl089UzQkpYlBq2VTPRw== + dependencies: + "@babel/helper-plugin-utils" "^7.24.6" + +"@babel/plugin-syntax-logical-assignment-operators@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.7.2": + version "7.24.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.6.tgz#769daf2982d60308bc83d8936eaecb7582463c87" + integrity sha512-TzCtxGgVTEJWWwcYwQhCIQ6WaKlo80/B+Onsk4RRCcYqpYGFcG9etPW94VToGte5AAcxRrhjPUFvUS3Y2qKi4A== + dependencies: + "@babel/helper-plugin-utils" "^7.24.6" + +"@babel/template@^7.24.6", "@babel/template@^7.3.3": + version "7.24.6" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.6.tgz#048c347b2787a6072b24c723664c8d02b67a44f9" + integrity sha512-3vgazJlLwNXi9jhrR1ef8qiB65L1RK90+lEQwv4OxveHnqC3BfmnHdgySwRLzf6akhlOYenT+b7AfWq+a//AHw== + dependencies: + "@babel/code-frame" "^7.24.6" + "@babel/parser" "^7.24.6" + "@babel/types" "^7.24.6" + +"@babel/traverse@^7.24.6": + version "7.24.6" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.6.tgz#0941ec50cdeaeacad0911eb67ae227a4f8424edc" + integrity sha512-OsNjaJwT9Zn8ozxcfoBc+RaHdj3gFmCmYoQLUII1o6ZrUwku0BMg80FoOTPx+Gi6XhcQxAYE4xyjPTo4SxEQqw== + dependencies: + "@babel/code-frame" "^7.24.6" + "@babel/generator" "^7.24.6" + "@babel/helper-environment-visitor" "^7.24.6" + "@babel/helper-function-name" "^7.24.6" + "@babel/helper-hoist-variables" "^7.24.6" + "@babel/helper-split-export-declaration" "^7.24.6" + "@babel/parser" "^7.24.6" + "@babel/types" "^7.24.6" + debug "^4.3.1" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.24.6", "@babel/types@^7.3.3": + version "7.24.6" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.6.tgz#ba4e1f59870c10dc2fa95a274ac4feec23b21912" + integrity sha512-WaMsgi6Q8zMgMth93GvWPXkhAIEobfsIkLTacoVZoK1J0CevIPGYY2Vo5YvJGqyHqXM6P4ppOYGsIRU8MM9pFQ== + dependencies: + "@babel/helper-string-parser" "^7.24.6" + "@babel/helper-validator-identifier" "^7.24.6" + to-fast-properties "^2.0.0" + +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + +"@cspotcode/source-map-support@^0.8.0": + version "0.8.1" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" + integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== + dependencies: + "@jridgewell/trace-mapping" "0.3.9" + +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.6.1": + version "4.10.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.1.tgz#361461e5cb3845d874e61731c11cfedd664d83a0" + integrity sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA== + +"@eslint/config-array@^0.15.1": + version "0.15.1" + resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.15.1.tgz#1fa78b422d98f4e7979f2211a1fde137e26c7d61" + integrity sha512-K4gzNq+yymn/EVsXYmf+SBcBro8MTf+aXJZUphM96CdzUEr+ClGDvAbpmaEK+cGVigVXIgs9gNmvHAlrzzY5JQ== + dependencies: + "@eslint/object-schema" "^2.1.3" + debug "^4.3.1" + minimatch "^3.0.5" + +"@eslint/eslintrc@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.1.0.tgz#dbd3482bfd91efa663cbe7aa1f506839868207b6" + integrity sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^10.0.1" + globals "^14.0.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@eslint/js@9.4.0", "@eslint/js@^9.4.0": + version "9.4.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.4.0.tgz#96a2edd37ec0551ce5f9540705be23951c008a0c" + integrity sha512-fdI7VJjP3Rvc70lC4xkFXHB0fiPeojiL1PxVG6t1ZvXQrarj893PweuBTujxDUFk0Fxj4R7PIIAZ/aiiyZPZcg== + +"@eslint/object-schema@^2.1.3": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.4.tgz#9e69f8bb4031e11df79e03db09f9dbbae1740843" + integrity sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ== + +"@hapi/accept@^6.0.1": + version "6.0.3" + resolved "https://registry.yarnpkg.com/@hapi/accept/-/accept-6.0.3.tgz#eef0800a4f89cd969da8e5d0311dc877c37279ab" + integrity sha512-p72f9k56EuF0n3MwlBNThyVE5PXX40g+aQh+C/xbKrfzahM2Oispv3AXmOIU51t3j77zay1qrX7IIziZXspMlw== + dependencies: + "@hapi/boom" "^10.0.1" + "@hapi/hoek" "^11.0.2" + +"@hapi/ammo@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@hapi/ammo/-/ammo-6.0.1.tgz#1bc9f7102724ff288ca03b721854fc5393ad123a" + integrity sha512-pmL+nPod4g58kXrMcsGLp05O2jF4P2Q3GiL8qYV7nKYEh3cGf+rV4P5Jyi2Uq0agGhVU63GtaSAfBEZOlrJn9w== + dependencies: + "@hapi/hoek" "^11.0.2" + +"@hapi/b64@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@hapi/b64/-/b64-6.0.1.tgz#786b47dc070e14465af49e2428c1025bd06ed3df" + integrity sha512-ZvjX4JQReUmBheeCq+S9YavcnMMHWqx3S0jHNXWIM1kQDxB9cyfSycpVvjfrKcIS8Mh5N3hmu/YKo4Iag9g2Kw== + dependencies: + "@hapi/hoek" "^11.0.2" + +"@hapi/boom@^10.0.0", "@hapi/boom@^10.0.1": + version "10.0.1" + resolved "https://registry.yarnpkg.com/@hapi/boom/-/boom-10.0.1.tgz#ebb14688275ae150aa6af788dbe482e6a6062685" + integrity sha512-ERcCZaEjdH3OgSJlyjVk8pHIFeus91CjKP3v+MpgBNp5IvGzP2l/bRiD78nqYcKPaZdbKkK5vDBVPd2ohHBlsA== + dependencies: + "@hapi/hoek" "^11.0.2" + +"@hapi/bounce@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@hapi/bounce/-/bounce-3.0.1.tgz#25a51bf95733749c557c6bf948048bffa66435e4" + integrity sha512-G+/Pp9c1Ha4FDP+3Sy/Xwg2O4Ahaw3lIZFSX+BL4uWi64CmiETuZPxhKDUD4xBMOUZbBlzvO8HjiK8ePnhBadA== + dependencies: + "@hapi/boom" "^10.0.1" + "@hapi/hoek" "^11.0.2" + +"@hapi/bourne@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@hapi/bourne/-/bourne-3.0.0.tgz#f11fdf7dda62fe8e336fa7c6642d9041f30356d7" + integrity sha512-Waj1cwPXJDucOib4a3bAISsKJVb15MKi9IvmTI/7ssVEm6sywXGjVJDhl6/umt1pK1ZS7PacXU3A1PmFKHEZ2w== + +"@hapi/call@^9.0.1": + version "9.0.1" + resolved "https://registry.yarnpkg.com/@hapi/call/-/call-9.0.1.tgz#569b87d5b67abf0e58fb82a3894a61aaed3ca92e" + integrity sha512-uPojQRqEL1GRZR4xXPqcLMujQGaEpyVPRyBlD8Pp5rqgIwLhtveF9PkixiKru2THXvuN8mUrLeet5fqxKAAMGg== + dependencies: + "@hapi/boom" "^10.0.1" + "@hapi/hoek" "^11.0.2" + +"@hapi/catbox-memory@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@hapi/catbox-memory/-/catbox-memory-6.0.1.tgz#8f6b04c0cf2ce25da470324df360bd4e8d68b6ec" + integrity sha512-sVb+/ZxbZIvaMtJfAbdyY+QJUQg9oKTwamXpEg/5xnfG5WbJLTjvEn4kIGKz9pN3ENNbIL/bIdctmHmqi/AdGA== + dependencies: + "@hapi/boom" "^10.0.1" + "@hapi/hoek" "^11.0.2" + +"@hapi/catbox@^12.1.1": + version "12.1.1" + resolved "https://registry.yarnpkg.com/@hapi/catbox/-/catbox-12.1.1.tgz#9339dca0a5b18b3ca0a825ac5dfc916dbc5bab83" + integrity sha512-hDqYB1J+R0HtZg4iPH3LEnldoaBsar6bYp0EonBmNQ9t5CO+1CqgCul2ZtFveW1ReA5SQuze9GPSU7/aecERhw== + dependencies: + "@hapi/boom" "^10.0.1" + "@hapi/hoek" "^11.0.2" + "@hapi/podium" "^5.0.0" + "@hapi/validate" "^2.0.1" + +"@hapi/content@^6.0.0": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@hapi/content/-/content-6.0.0.tgz#2427af3bac8a2f743512fce2a70cbdc365af29df" + integrity sha512-CEhs7j+H0iQffKfe5Htdak5LBOz/Qc8TRh51cF+BFv0qnuph3Em4pjGVzJMkI2gfTDdlJKWJISGWS1rK34POGA== + dependencies: + "@hapi/boom" "^10.0.0" + +"@hapi/cryptiles@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@hapi/cryptiles/-/cryptiles-6.0.1.tgz#7868a9d4233567ed66f0a9caf85fdcc56e980621" + integrity sha512-9GM9ECEHfR8lk5ASOKG4+4ZsEzFqLfhiryIJ2ISePVB92OHLp/yne4m+zn7z9dgvM98TLpiFebjDFQ0UHcqxXQ== + dependencies: + "@hapi/boom" "^10.0.1" + +"@hapi/file@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@hapi/file/-/file-3.0.0.tgz#f1fd824493ac89a6fceaf89c824afc5ae2121c09" + integrity sha512-w+lKW+yRrLhJu620jT3y+5g2mHqnKfepreykvdOcl9/6up8GrQQn+l3FRTsjHTKbkbfQFkuksHpdv2EcpKcJ4Q== + +"@hapi/hapi@^21.3.9": + version "21.3.9" + resolved "https://registry.yarnpkg.com/@hapi/hapi/-/hapi-21.3.9.tgz#953220abe26d12a7cbd308a57e434dedf0278cb3" + integrity sha512-AT5m+Rb8iSOFG3zWaiEuTJazf4HDYl5UpRpyxMJ3yR+g8tOEmqDv6FmXrLHShdvDOStAAepHGnr1G7egkFSRdw== + dependencies: + "@hapi/accept" "^6.0.1" + "@hapi/ammo" "^6.0.1" + "@hapi/boom" "^10.0.1" + "@hapi/bounce" "^3.0.1" + "@hapi/call" "^9.0.1" + "@hapi/catbox" "^12.1.1" + "@hapi/catbox-memory" "^6.0.1" + "@hapi/heavy" "^8.0.1" + "@hapi/hoek" "^11.0.2" + "@hapi/mimos" "^7.0.1" + "@hapi/podium" "^5.0.1" + "@hapi/shot" "^6.0.1" + "@hapi/somever" "^4.1.1" + "@hapi/statehood" "^8.1.1" + "@hapi/subtext" "^8.1.0" + "@hapi/teamwork" "^6.0.0" + "@hapi/topo" "^6.0.1" + "@hapi/validate" "^2.0.1" + +"@hapi/heavy@^8.0.1": + version "8.0.1" + resolved "https://registry.yarnpkg.com/@hapi/heavy/-/heavy-8.0.1.tgz#e2be4a6a249005b5a587f7604aafa8ed02461fb6" + integrity sha512-gBD/NANosNCOp6RsYTsjo2vhr5eYA3BEuogk6cxY0QdhllkkTaJFYtTXv46xd6qhBVMbMMqcSdtqey+UQU3//w== + dependencies: + "@hapi/boom" "^10.0.1" + "@hapi/hoek" "^11.0.2" + "@hapi/validate" "^2.0.1" + +"@hapi/hoek@^11.0.2": + version "11.0.4" + resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-11.0.4.tgz#42a7f244fd3dd777792bfb74b8c6340ae9182f37" + integrity sha512-PnsP5d4q7289pS2T2EgGz147BFJ2Jpb4yrEdkpz2IhgEUzos1S7HTl7ezWh1yfYzYlj89KzLdCRkqsP6SIryeQ== + +"@hapi/iron@^7.0.1": + version "7.0.1" + resolved "https://registry.yarnpkg.com/@hapi/iron/-/iron-7.0.1.tgz#f74bace8dad9340c7c012c27c078504f070f14b5" + integrity sha512-tEZnrOujKpS6jLKliyWBl3A9PaE+ppuL/+gkbyPPDb/l2KSKQyH4lhMkVb+sBhwN+qaxxlig01JRqB8dk/mPxQ== + dependencies: + "@hapi/b64" "^6.0.1" + "@hapi/boom" "^10.0.1" + "@hapi/bourne" "^3.0.0" + "@hapi/cryptiles" "^6.0.1" + "@hapi/hoek" "^11.0.2" + +"@hapi/mimos@^7.0.1": + version "7.0.1" + resolved "https://registry.yarnpkg.com/@hapi/mimos/-/mimos-7.0.1.tgz#5b65c76bb9da28ba34b0092215891f2c72bc899d" + integrity sha512-b79V+BrG0gJ9zcRx1VGcCI6r6GEzzZUgiGEJVoq5gwzuB2Ig9Cax8dUuBauQCFKvl2YWSWyOc8mZ8HDaJOtkew== + dependencies: + "@hapi/hoek" "^11.0.2" + mime-db "^1.52.0" + +"@hapi/nigel@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@hapi/nigel/-/nigel-5.0.1.tgz#a6dfe357e9d48d944e2ffc552bd95cb701d79ee9" + integrity sha512-uv3dtYuB4IsNaha+tigWmN8mQw/O9Qzl5U26Gm4ZcJVtDdB1AVJOwX3X5wOX+A07qzpEZnOMBAm8jjSqGsU6Nw== + dependencies: + "@hapi/hoek" "^11.0.2" + "@hapi/vise" "^5.0.1" + +"@hapi/pez@^6.1.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@hapi/pez/-/pez-6.1.0.tgz#64d9f95580fc7d8f1d13437ee4a8676709954fda" + integrity sha512-+FE3sFPYuXCpuVeHQ/Qag1b45clR2o54QoonE/gKHv9gukxQ8oJJZPR7o3/ydDTK6racnCJXxOyT1T93FCJMIg== + dependencies: + "@hapi/b64" "^6.0.1" + "@hapi/boom" "^10.0.1" + "@hapi/content" "^6.0.0" + "@hapi/hoek" "^11.0.2" + "@hapi/nigel" "^5.0.1" + +"@hapi/podium@^5.0.0", "@hapi/podium@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@hapi/podium/-/podium-5.0.1.tgz#f292b4c0ca3118747394a102c6c3340bda96662f" + integrity sha512-eznFTw6rdBhAijXFIlBOMJJd+lXTvqbrBIS4Iu80r2KTVIo4g+7fLy4NKp/8+UnSt5Ox6mJtAlKBU/Sf5080TQ== + dependencies: + "@hapi/hoek" "^11.0.2" + "@hapi/teamwork" "^6.0.0" + "@hapi/validate" "^2.0.1" + +"@hapi/shot@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@hapi/shot/-/shot-6.0.1.tgz#ea84d1810b7c8599d5517c23b4ec55a529d7dc16" + integrity sha512-s5ynMKZXYoDd3dqPw5YTvOR/vjHvMTxc388+0qL0jZZP1+uwXuUD32o9DuuuLsmTlyXCWi02BJl1pBpwRuUrNA== + dependencies: + "@hapi/hoek" "^11.0.2" + "@hapi/validate" "^2.0.1" + +"@hapi/somever@^4.1.1": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@hapi/somever/-/somever-4.1.1.tgz#b492c78408303c72cd1a39c5060f35d18a404b27" + integrity sha512-lt3QQiDDOVRatS0ionFDNrDIv4eXz58IibQaZQDOg4DqqdNme8oa0iPWcE0+hkq/KTeBCPtEOjDOBKBKwDumVg== + dependencies: + "@hapi/bounce" "^3.0.1" + "@hapi/hoek" "^11.0.2" + +"@hapi/statehood@^8.1.1": + version "8.1.1" + resolved "https://registry.yarnpkg.com/@hapi/statehood/-/statehood-8.1.1.tgz#db4bd14c90810a1389763cb0b0b8f221aa4179c1" + integrity sha512-YbK7PSVUA59NArAW5Np0tKRoIZ5VNYUicOk7uJmWZF6XyH5gGL+k62w77SIJb0AoAJ0QdGQMCQ/WOGL1S3Ydow== + dependencies: + "@hapi/boom" "^10.0.1" + "@hapi/bounce" "^3.0.1" + "@hapi/bourne" "^3.0.0" + "@hapi/cryptiles" "^6.0.1" + "@hapi/hoek" "^11.0.2" + "@hapi/iron" "^7.0.1" + "@hapi/validate" "^2.0.1" + +"@hapi/subtext@^8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@hapi/subtext/-/subtext-8.1.0.tgz#58733020a6655bc4d978df9e2f75e31696ff3f91" + integrity sha512-PyaN4oSMtqPjjVxLny1k0iYg4+fwGusIhaom9B2StinBclHs7v46mIW706Y+Wo21lcgulGyXbQrmT/w4dus6ww== + dependencies: + "@hapi/boom" "^10.0.1" + "@hapi/bourne" "^3.0.0" + "@hapi/content" "^6.0.0" + "@hapi/file" "^3.0.0" + "@hapi/hoek" "^11.0.2" + "@hapi/pez" "^6.1.0" + "@hapi/wreck" "^18.0.1" + +"@hapi/teamwork@^6.0.0": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@hapi/teamwork/-/teamwork-6.0.0.tgz#b3a173cf811ba59fc6ee22318a1b51f4561f06e0" + integrity sha512-05HumSy3LWfXpmJ9cr6HzwhAavrHkJ1ZRCmNE2qJMihdM5YcWreWPfyN0yKT2ZjCM92au3ZkuodjBxOibxM67A== + +"@hapi/topo@^6.0.1": + version "6.0.2" + resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-6.0.2.tgz#f219c1c60da8430228af4c1f2e40c32a0d84bbb4" + integrity sha512-KR3rD5inZbGMrHmgPxsJ9dbi6zEK+C3ZwUwTa+eMwWLz7oijWUTWD2pMSNNYJAU6Qq+65NkxXjqHr/7LM2Xkqg== + dependencies: + "@hapi/hoek" "^11.0.2" + +"@hapi/validate@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@hapi/validate/-/validate-2.0.1.tgz#45cf228c4c8cfc61ba2da7e0a5ba93ff3b9afff1" + integrity sha512-NZmXRnrSLK8MQ9y/CMqE9WSspgB9xA41/LlYR0k967aSZebWr4yNrpxIbov12ICwKy4APSlWXZga9jN5p6puPA== + dependencies: + "@hapi/hoek" "^11.0.2" + "@hapi/topo" "^6.0.1" + +"@hapi/vise@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@hapi/vise/-/vise-5.0.1.tgz#5c9f16bcf1c039ddd4b6cad5f32d71eeb6bb7dac" + integrity sha512-XZYWzzRtINQLedPYlIkSkUr7m5Ddwlu99V9elh8CSygXstfv3UnWIXT0QD+wmR0VAG34d2Vx3olqcEhRRoTu9A== + dependencies: + "@hapi/hoek" "^11.0.2" + +"@hapi/wreck@^18.0.1": + version "18.1.0" + resolved "https://registry.yarnpkg.com/@hapi/wreck/-/wreck-18.1.0.tgz#68e631fc7568ebefc6252d5b86cb804466c8dbe6" + integrity sha512-0z6ZRCmFEfV/MQqkQomJ7sl/hyxvcZM7LtuVqN3vdAO4vM9eBbowl0kaqQj9EJJQab+3Uuh1GxbGIBFy4NfJ4w== + dependencies: + "@hapi/boom" "^10.0.1" + "@hapi/bourne" "^3.0.0" + "@hapi/hoek" "^11.0.2" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/retry@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.0.tgz#6d86b8cb322660f03d3f0aa94b99bdd8e172d570" + integrity sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew== + +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jest/console@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.7.0.tgz#cd4822dbdb84529265c5a2bdb529a3c9cc950ffc" + integrity sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + slash "^3.0.0" + +"@jest/core@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.7.0.tgz#b6cccc239f30ff36609658c5a5e2291757ce448f" + integrity sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg== + dependencies: + "@jest/console" "^29.7.0" + "@jest/reporters" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + ci-info "^3.2.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-changed-files "^29.7.0" + jest-config "^29.7.0" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-resolve-dependencies "^29.7.0" + jest-runner "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + jest-watcher "^29.7.0" + micromatch "^4.0.4" + pretty-format "^29.7.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/environment@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.7.0.tgz#24d61f54ff1f786f3cd4073b4b94416383baf2a7" + integrity sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw== + dependencies: + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-mock "^29.7.0" + +"@jest/expect-utils@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.7.0.tgz#023efe5d26a8a70f21677d0a1afc0f0a44e3a1c6" + integrity sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA== + dependencies: + jest-get-type "^29.6.3" + +"@jest/expect@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.7.0.tgz#76a3edb0cb753b70dfbfe23283510d3d45432bf2" + integrity sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ== + dependencies: + expect "^29.7.0" + jest-snapshot "^29.7.0" + +"@jest/fake-timers@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.7.0.tgz#fd91bf1fffb16d7d0d24a426ab1a47a49881a565" + integrity sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ== + dependencies: + "@jest/types" "^29.6.3" + "@sinonjs/fake-timers" "^10.0.2" + "@types/node" "*" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-util "^29.7.0" + +"@jest/globals@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.7.0.tgz#8d9290f9ec47ff772607fa864ca1d5a2efae1d4d" + integrity sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/types" "^29.6.3" + jest-mock "^29.7.0" + +"@jest/reporters@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.7.0.tgz#04b262ecb3b8faa83b0b3d321623972393e8f4c7" + integrity sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^6.0.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.1.3" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + jest-worker "^29.7.0" + slash "^3.0.0" + string-length "^4.0.1" + strip-ansi "^6.0.0" + v8-to-istanbul "^9.0.1" + +"@jest/schemas@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" + integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== + dependencies: + "@sinclair/typebox" "^0.27.8" + +"@jest/source-map@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.3.tgz#d90ba772095cf37a34a5eb9413f1b562a08554c4" + integrity sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw== + dependencies: + "@jridgewell/trace-mapping" "^0.3.18" + callsites "^3.0.0" + graceful-fs "^4.2.9" + +"@jest/test-result@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.7.0.tgz#8db9a80aa1a097bb2262572686734baed9b1657c" + integrity sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA== + dependencies: + "@jest/console" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-sequencer@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz#6cef977ce1d39834a3aea887a1726628a6f072ce" + integrity sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw== + dependencies: + "@jest/test-result" "^29.7.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + slash "^3.0.0" + +"@jest/transform@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.7.0.tgz#df2dd9c346c7d7768b8a06639994640c642e284c" + integrity sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw== + dependencies: + "@babel/core" "^7.11.6" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^2.0.0" + fast-json-stable-stringify "^2.1.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + write-file-atomic "^4.0.2" + +"@jest/types@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.3.tgz#1131f8cf634e7e84c5e77bab12f052af585fba59" + integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== + dependencies: + "@jest/schemas" "^29.6.3" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + +"@jridgewell/gen-mapping@^0.3.5": + version "0.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" + integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== + dependencies: + "@jridgewell/set-array" "^1.2.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/set-array@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" + integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": + version "1.4.15" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + +"@jridgewell/trace-mapping@0.3.9": + version "0.3.9" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": + version "0.3.25" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@sinclair/typebox@^0.27.8": + version "0.27.8" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" + integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== + +"@sinonjs/commons@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.1.tgz#1029357e44ca901a615585f6d27738dbc89084cd" + integrity sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^10.0.2": + version "10.3.0" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz#55fdff1ecab9f354019129daf4df0dd4d923ea66" + integrity sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA== + dependencies: + "@sinonjs/commons" "^3.0.0" + +"@tsconfig/node10@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.11.tgz#6ee46400685f130e278128c7b38b7e031ff5b2f2" + integrity sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw== + +"@tsconfig/node12@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" + integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== + +"@tsconfig/node14@^1.0.0": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" + integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== + +"@tsconfig/node16@^1.0.2": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" + integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== + +"@types/babel__core@^7.1.14": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" + integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== + dependencies: + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.8" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.8.tgz#f836c61f48b1346e7d2b0d93c6dacc5b9535d3ab" + integrity sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f" + integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": + version "7.20.6" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.6.tgz#8dc9f0ae0f202c08d8d4dab648912c8d6038e3f7" + integrity sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg== + dependencies: + "@babel/types" "^7.20.7" + +"@types/body-parser@*": + version "1.19.5" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.5.tgz#04ce9a3b677dc8bd681a17da1ab9835dc9d3ede4" + integrity sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg== + dependencies: + "@types/connect" "*" + "@types/node" "*" + +"@types/connect@*": + version "3.4.38" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.38.tgz#5ba7f3bc4fbbdeaff8dded952e5ff2cc53f8d858" + integrity sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug== + dependencies: + "@types/node" "*" + +"@types/express-serve-static-core@^4.17.33": + version "4.19.3" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.19.3.tgz#e469a13e4186c9e1c0418fb17be8bc8ff1b19a7a" + integrity sha512-KOzM7MhcBFlmnlr/fzISFF5vGWVSvN6fTd4T+ExOt08bA/dA5kpSzY52nMsI1KDFmUREpJelPYyuslLRSjjgCg== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + "@types/send" "*" + +"@types/express@*", "@types/express@^4.17.21": + version "4.17.21" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.21.tgz#c26d4a151e60efe0084b23dc3369ebc631ed192d" + integrity sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^4.17.33" + "@types/qs" "*" + "@types/serve-static" "*" + +"@types/graceful-fs@^4.1.3": + version "4.1.9" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4" + integrity sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ== + dependencies: + "@types/node" "*" + +"@types/http-errors@*": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.4.tgz#7eb47726c391b7345a6ec35ad7f4de469cf5ba4f" + integrity sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA== + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" + integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== + +"@types/istanbul-lib-report@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz#53047614ae72e19fc0401d872de3ae2b4ce350bf" + integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz#0f03e3d2f670fbdac586e34b433783070cc16f54" + integrity sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jest@^29.5.12": + version "29.5.12" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.12.tgz#7f7dc6eb4cf246d2474ed78744b05d06ce025544" + integrity sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw== + dependencies: + expect "^29.0.0" + pretty-format "^29.0.0" + +"@types/mime@^1": + version "1.3.5" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690" + integrity sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w== + +"@types/node@*": + version "20.12.13" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.12.13.tgz#90ed3b8a4e52dd3c5dc5a42dde5b85b74ad8ed88" + integrity sha512-gBGeanV41c1L171rR7wjbMiEpEI/l5XFQdLLfhr/REwpgDy/4U8y89+i8kRiLzDyZdOkXh+cRaTetUnCYutoXA== + dependencies: + undici-types "~5.26.4" + +"@types/qs@*": + version "6.9.15" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.15.tgz#adde8a060ec9c305a82de1babc1056e73bd64dce" + integrity sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg== + +"@types/range-parser@*": + version "1.2.7" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.7.tgz#50ae4353eaaddc04044279812f52c8c65857dbcb" + integrity sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ== + +"@types/send@*": + version "0.17.4" + resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.4.tgz#6619cd24e7270793702e4e6a4b958a9010cfc57a" + integrity sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA== + dependencies: + "@types/mime" "^1" + "@types/node" "*" + +"@types/serve-static@*": + version "1.15.7" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.7.tgz#22174bbd74fb97fe303109738e9b5c2f3064f714" + integrity sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw== + dependencies: + "@types/http-errors" "*" + "@types/node" "*" + "@types/send" "*" + +"@types/stack-utils@^2.0.0": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" + integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== + +"@types/strip-bom@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/strip-bom/-/strip-bom-3.0.0.tgz#14a8ec3956c2e81edb7520790aecf21c290aebd2" + integrity sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ== + +"@types/strip-json-comments@0.0.30": + version "0.0.30" + resolved "https://registry.yarnpkg.com/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz#9aa30c04db212a9a0649d6ae6fd50accc40748a1" + integrity sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ== + +"@types/swagger-ui-express@^4.1.6": + version "4.1.6" + resolved "https://registry.yarnpkg.com/@types/swagger-ui-express/-/swagger-ui-express-4.1.6.tgz#d0929e3fabac1a96a8a9c6c7ee8d42362c5cdf48" + integrity sha512-UVSiGYXa5IzdJJG3hrc86e8KdZWLYxyEsVoUI4iPXc7CO4VZ3AfNP8d/8+hrDRIqz+HAaSMtZSqAsF3Nq2X/Dg== + dependencies: + "@types/express" "*" + "@types/serve-static" "*" + +"@types/yargs-parser@*": + version "21.0.3" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" + integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== + +"@types/yargs@^17.0.8": + version "17.0.32" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.32.tgz#030774723a2f7faafebf645f4e5a48371dca6229" + integrity sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog== + dependencies: + "@types/yargs-parser" "*" + +"@typescript-eslint/eslint-plugin@7.13.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.13.0.tgz#3cdeb5d44d051b21a9567535dd90702b2a42c6ff" + integrity sha512-FX1X6AF0w8MdVFLSdqwqN/me2hyhuQg4ykN6ZpVhh1ij/80pTvDKclX1sZB9iqex8SjQfVhwMKs3JtnnMLzG9w== + dependencies: + "@eslint-community/regexpp" "^4.10.0" + "@typescript-eslint/scope-manager" "7.13.0" + "@typescript-eslint/type-utils" "7.13.0" + "@typescript-eslint/utils" "7.13.0" + "@typescript-eslint/visitor-keys" "7.13.0" + graphemer "^1.4.0" + ignore "^5.3.1" + natural-compare "^1.4.0" + ts-api-utils "^1.3.0" + +"@typescript-eslint/parser@7.13.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-7.13.0.tgz#9489098d68d57ad392f507495f2b82ce8b8f0a6b" + integrity sha512-EjMfl69KOS9awXXe83iRN7oIEXy9yYdqWfqdrFAYAAr6syP8eLEFI7ZE4939antx2mNgPRW/o1ybm2SFYkbTVA== + dependencies: + "@typescript-eslint/scope-manager" "7.13.0" + "@typescript-eslint/types" "7.13.0" + "@typescript-eslint/typescript-estree" "7.13.0" + "@typescript-eslint/visitor-keys" "7.13.0" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@7.13.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.13.0.tgz#6927d6451537ce648c6af67a2327378d4cc18462" + integrity sha512-ZrMCe1R6a01T94ilV13egvcnvVJ1pxShkE0+NDjDzH4nvG1wXpwsVI5bZCvE7AEDH1mXEx5tJSVR68bLgG7Dng== + dependencies: + "@typescript-eslint/types" "7.13.0" + "@typescript-eslint/visitor-keys" "7.13.0" + +"@typescript-eslint/type-utils@7.13.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.13.0.tgz#4587282b5227a23753ea8b233805ecafc3924c76" + integrity sha512-xMEtMzxq9eRkZy48XuxlBFzpVMDurUAfDu5Rz16GouAtXm0TaAoTFzqWUFPPuQYXI/CDaH/Bgx/fk/84t/Bc9A== + dependencies: + "@typescript-eslint/typescript-estree" "7.13.0" + "@typescript-eslint/utils" "7.13.0" + debug "^4.3.4" + ts-api-utils "^1.3.0" + +"@typescript-eslint/types@7.13.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.13.0.tgz#0cca95edf1f1fdb0cfe1bb875e121b49617477c5" + integrity sha512-QWuwm9wcGMAuTsxP+qz6LBBd3Uq8I5Nv8xb0mk54jmNoCyDspnMvVsOxI6IsMmway5d1S9Su2+sCKv1st2l6eA== + +"@typescript-eslint/typescript-estree@7.13.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.0.tgz#4cc24fc155088ebf3b3adbad62c7e60f72c6de1c" + integrity sha512-cAvBvUoobaoIcoqox1YatXOnSl3gx92rCZoMRPzMNisDiM12siGilSM4+dJAekuuHTibI2hVC2fYK79iSFvWjw== + dependencies: + "@typescript-eslint/types" "7.13.0" + "@typescript-eslint/visitor-keys" "7.13.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^1.3.0" + +"@typescript-eslint/utils@7.13.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.13.0.tgz#f84e7e8aeceae945a9a3f40d077fd95915308004" + integrity sha512-jceD8RgdKORVnB4Y6BqasfIkFhl4pajB1wVxrF4akxD2QPM8GNYjgGwEzYS+437ewlqqrg7Dw+6dhdpjMpeBFQ== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@typescript-eslint/scope-manager" "7.13.0" + "@typescript-eslint/types" "7.13.0" + "@typescript-eslint/typescript-estree" "7.13.0" + +"@typescript-eslint/visitor-keys@7.13.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.0.tgz#2eb7ce8eb38c2b0d4a494d1fe1908e7071a1a353" + integrity sha512-nxn+dozQx+MK61nn/JP+M4eCkHDSxSLDpgE3WcQo0+fkjEolnaB5jswvIKC4K56By8MMgIho7f1PVxERHEo8rw== + dependencies: + "@typescript-eslint/types" "7.13.0" + eslint-visitor-keys "^3.4.3" + +accepts@~1.3.8: + version "1.3.8" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== + dependencies: + mime-types "~2.1.34" + negotiator "0.6.3" + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn-walk@^8.1.1: + version "8.3.2" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.2.tgz#7703af9415f1b6db9315d6895503862e231d34aa" + integrity sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A== + +acorn@^8.11.3, acorn@^8.4.1: + version "8.11.3" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" + integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== + +ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-escapes@^4.2.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + +anymatch@^3.0.3, anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +assert-options@0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/assert-options/-/assert-options-0.8.1.tgz#f1df7cef7d0b8b29a3c091e6946287a4a9a45ab8" + integrity sha512-5lNGRB5g5i2bGIzb+J1QQE1iKU/WEMVBReFIc5pPDWjcPj23otPL0eI6PB2v7QPi0qU6Mhym5D3y0ZiSIOf3GA== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +axios@^1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.2.tgz#b625db8a7051fbea61c35a3cbb3a1daa7b9c7621" + integrity sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw== + dependencies: + follow-redirects "^1.15.6" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + +babel-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" + integrity sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg== + dependencies: + "@jest/transform" "^29.7.0" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^29.6.3" + chalk "^4.0.0" + graceful-fs "^4.2.9" + slash "^3.0.0" + +babel-plugin-istanbul@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^5.0.4" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz#aadbe943464182a8922c3c927c3067ff40d24626" + integrity sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.1.14" + "@types/babel__traverse" "^7.0.6" + +babel-preset-current-node-syntax@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" + integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.8.3" + "@babel/plugin-syntax-import-meta" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + +babel-preset-jest@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz#fa05fa510e7d493896d7b0dd2033601c840f171c" + integrity sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA== + dependencies: + babel-plugin-jest-hoist "^29.6.3" + babel-preset-current-node-syntax "^1.0.0" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +binary-extensions@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== + +body-parser@1.20.2: + version "1.20.2" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd" + integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA== + dependencies: + bytes "3.1.2" + content-type "~1.0.5" + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" + iconv-lite "0.4.24" + on-finished "2.4.1" + qs "6.11.0" + raw-body "2.5.2" + type-is "~1.6.18" + unpipe "1.0.0" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.3, braces@~3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +browserslist@^4.22.2: + version "4.23.0" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.0.tgz#8f3acc2bbe73af7213399430890f86c63a5674ab" + integrity sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ== + dependencies: + caniuse-lite "^1.0.30001587" + electron-to-chromium "^1.4.668" + node-releases "^2.0.14" + update-browserslist-db "^1.0.13" + +bs-logger@0.x: + version "0.2.6" + resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" + integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== + dependencies: + fast-json-stable-stringify "2.x" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +bytes@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== + +call-bind@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" + integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + set-function-length "^1.2.1" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.2.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-lite@^1.0.30001587: + version "1.0.30001625" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001625.tgz#ead1b155ea691d6a87938754d3cb119c24465b03" + integrity sha512-4KE9N2gcRH+HQhpeiRZXd+1niLB/XNLAhSy4z7fI8EzcbcPoAqjNInxVHTiTwWfTIV4w096XG8OtCOCQQKPv3w== + +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.0.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + +chokidar@^3.5.1: + version "3.6.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +ci-info@^3.2.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" + integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== + +cjs-module-lexer@^1.0.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz#c485341ae8fd999ca4ee5af2d7a1c9ae01e0099c" + integrity sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q== + +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== + +collect-v8-coverage@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz#c0b29bcd33bcd0779a1344c2136051e6afd3d9e9" + integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q== + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +content-disposition@0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" + +content-type@~1.0.4, content-type@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== + +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== + +cookie@0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051" + integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== + +create-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/create-jest/-/create-jest-29.7.0.tgz#a355c5b3cb1e1af02ba177fe7afd7feee49a5320" + integrity sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q== + dependencies: + "@jest/types" "^29.6.3" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-config "^29.7.0" + jest-util "^29.7.0" + prompts "^2.0.1" + +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + +cross-spawn@^7.0.2, cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +crypto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/crypto/-/crypto-1.0.1.tgz#2af1b7cad8175d24c8a1b0778255794a21803037" + integrity sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig== + +currency.js@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/currency.js/-/currency.js-2.0.4.tgz#a8a4d69be3b2e509bf67a560c78220bc04809cf1" + integrity sha512-6/OplJYgJ0RUlli74d93HJ/OsKVBi8lB1+Z6eJYS1YZzBuIp4qKKHpJ7ad+GvTlWmLR/hLJOWTykN5Nm8NJ7+w== + +debug@2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +debug@^4.3.2, debug@^4.3.4: + version "4.3.5" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.5.tgz#e83444eceb9fedd4a1da56d671ae2446a01a6e1e" + integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== + dependencies: + ms "2.1.2" + +dedent@^1.0.0: + version "1.5.3" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.3.tgz#99aee19eb9bae55a67327717b6e848d0bf777e5a" + integrity sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ== + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +deepmerge@^4.2.2: + version "4.3.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" + integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== + +define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +depd@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + +destroy@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" + integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== + +detect-newline@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== + +diff-sequences@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" + integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== + +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +dotenv@^16.4.5: + version "16.4.5" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f" + integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg== + +dynamic-dedupe@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz#06e44c223f5e4e94d78ef9db23a6515ce2f962a1" + integrity sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ== + dependencies: + xtend "^4.0.0" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== + +electron-to-chromium@^1.4.668: + version "1.4.786" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.786.tgz#974d7eeac61c5ffa285dc55555d06b97b05f6831" + integrity sha512-i/A2UB0sxYViMN0M2zIotQFRIOt1jLuVXudACHBDiJ5gGuAUzf/crZxwlBTdA0O52Hy4CNtTzS7AKRAacs/08Q== + +emittery@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" + integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es-define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" + integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== + dependencies: + get-intrinsic "^1.2.4" + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +escalade@^3.1.1, escalade@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" + integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-config-prettier@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz#31af3d94578645966c082fcb71a5846d3c94867f" + integrity sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw== + +eslint-scope@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.0.1.tgz#a9601e4b81a0b9171657c343fb13111688963cfc" + integrity sha512-pL8XjgP4ZOmmwfFE8mEhSxA7ZY4C+LWyqjQ3o4yWkkmD0qcMT9kkW3zWHOczhWcjTSgqycYAgwSlXvZltv65og== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== + +eslint-visitor-keys@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz#e3adc021aa038a2a8e0b2f8b0ce8f66b9483b1fb" + integrity sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw== + +eslint@9.x: + version "9.4.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.4.0.tgz#79150c3610ae606eb131f1d648d5f43b3d45f3cd" + integrity sha512-sjc7Y8cUD1IlwYcTS9qPSvGjAC8Ne9LctpxKKu3x/1IC9bnOg98Zy6GxEJUfr1NojMgVPlyANXYns8oE2c1TAA== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.6.1" + "@eslint/config-array" "^0.15.1" + "@eslint/eslintrc" "^3.1.0" + "@eslint/js" "9.4.0" + "@humanwhocodes/module-importer" "^1.0.1" + "@humanwhocodes/retry" "^0.3.0" + "@nodelib/fs.walk" "^1.2.8" + ajv "^6.12.4" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + escape-string-regexp "^4.0.0" + eslint-scope "^8.0.1" + eslint-visitor-keys "^4.0.0" + espree "^10.0.1" + esquery "^1.4.2" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^8.0.0" + find-up "^5.0.0" + glob-parent "^6.0.2" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + is-path-inside "^3.0.3" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + strip-ansi "^6.0.1" + text-table "^0.2.0" + +espree@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-10.0.1.tgz#600e60404157412751ba4a6f3a2ee1a42433139f" + integrity sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww== + dependencies: + acorn "^8.11.3" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^4.0.0" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.4.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" + integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== + +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== + +expect@^29.0.0, expect@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc" + integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw== + dependencies: + "@jest/expect-utils" "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + +express@^4.19.2: + version "4.19.2" + resolved "https://registry.yarnpkg.com/express/-/express-4.19.2.tgz#e25437827a3aa7f2a827bc8171bbbb664a356465" + integrity sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q== + dependencies: + accepts "~1.3.8" + array-flatten "1.1.1" + body-parser "1.20.2" + content-disposition "0.5.4" + content-type "~1.0.4" + cookie "0.6.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "2.0.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.2.0" + fresh "0.5.2" + http-errors "2.0.0" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "2.4.1" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.7" + qs "6.11.0" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "0.18.0" + serve-static "1.15.0" + setprototypeof "1.2.0" + statuses "2.0.1" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@^3.2.9: + version "3.3.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fastq@^1.6.0: + version "1.17.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" + integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== + dependencies: + reusify "^1.0.4" + +fb-watchman@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.2.tgz#e9524ee6b5c77e9e5001af0f85f3adbb8623255c" + integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== + dependencies: + bser "2.1.1" + +file-entry-cache@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f" + integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ== + dependencies: + flat-cache "^4.0.0" + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + +finalhandler@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" + integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "2.4.1" + parseurl "~1.3.3" + statuses "2.0.1" + unpipe "~1.0.0" + +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat-cache@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c" + integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw== + dependencies: + flatted "^3.2.9" + keyv "^4.5.4" + +flatted@^3.2.9: + version "3.3.1" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" + integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== + +follow-redirects@^1.15.6: + version "1.15.6" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" + integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== + +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@^2.3.2, fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.1.3, get-intrinsic@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" + integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob@^7.1.3, glob@^7.1.4: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globals@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" + integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== + +globby@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + +graceful-fs@^4.2.9: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== + dependencies: + es-define-property "^1.0.0" + +has-proto@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" + integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== + +has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +hasown@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== + dependencies: + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ignore@^5.2.0, ignore@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" + integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== + +import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-local@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" + integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-core-module@^2.13.0: + version "2.13.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" + integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== + dependencies: + hasown "^2.0.0" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-generator-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-path-inside@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" + integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== + +istanbul-lib-instrument@^5.0.4: + version "5.2.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" + integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^6.3.0" + +istanbul-lib-instrument@^6.0.0: + version "6.0.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.2.tgz#91655936cf7380e4e473383081e38478b69993b1" + integrity sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw== + dependencies: + "@babel/core" "^7.23.9" + "@babel/parser" "^7.23.9" + "@istanbuljs/schema" "^0.1.3" + istanbul-lib-coverage "^3.2.0" + semver "^7.5.4" + +istanbul-lib-report@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" + integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^4.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.1.3: + version "3.1.7" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.7.tgz#daed12b9e1dca518e15c056e1e537e741280fa0b" + integrity sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +jest-changed-files@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a" + integrity sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w== + dependencies: + execa "^5.0.0" + jest-util "^29.7.0" + p-limit "^3.1.0" + +jest-circus@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.7.0.tgz#b6817a45fcc835d8b16d5962d0c026473ee3668a" + integrity sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^1.0.0" + is-generator-fn "^2.0.0" + jest-each "^29.7.0" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + p-limit "^3.1.0" + pretty-format "^29.7.0" + pure-rand "^6.0.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-cli@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.7.0.tgz#5592c940798e0cae677eec169264f2d839a37995" + integrity sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg== + dependencies: + "@jest/core" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + chalk "^4.0.0" + create-jest "^29.7.0" + exit "^0.1.2" + import-local "^3.0.2" + jest-config "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + yargs "^17.3.1" + +jest-config@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.7.0.tgz#bcbda8806dbcc01b1e316a46bb74085a84b0245f" + integrity sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ== + dependencies: + "@babel/core" "^7.11.6" + "@jest/test-sequencer" "^29.7.0" + "@jest/types" "^29.6.3" + babel-jest "^29.7.0" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-circus "^29.7.0" + jest-environment-node "^29.7.0" + jest-get-type "^29.6.3" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-runner "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^29.7.0" + slash "^3.0.0" + strip-json-comments "^3.1.1" + +jest-diff@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a" + integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw== + dependencies: + chalk "^4.0.0" + diff-sequences "^29.6.3" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-docblock@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.7.0.tgz#8fddb6adc3cdc955c93e2a87f61cfd350d5d119a" + integrity sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g== + dependencies: + detect-newline "^3.0.0" + +jest-each@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.7.0.tgz#162a9b3f2328bdd991beaabffbb74745e56577d1" + integrity sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ== + dependencies: + "@jest/types" "^29.6.3" + chalk "^4.0.0" + jest-get-type "^29.6.3" + jest-util "^29.7.0" + pretty-format "^29.7.0" + +jest-environment-node@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.7.0.tgz#0b93e111dda8ec120bc8300e6d1fb9576e164376" + integrity sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-mock "^29.7.0" + jest-util "^29.7.0" + +jest-get-type@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1" + integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw== + +jest-haste-map@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.7.0.tgz#3c2396524482f5a0506376e6c858c3bbcc17b104" + integrity sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA== + dependencies: + "@jest/types" "^29.6.3" + "@types/graceful-fs" "^4.1.3" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.9" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + jest-worker "^29.7.0" + micromatch "^4.0.4" + walker "^1.0.8" + optionalDependencies: + fsevents "^2.3.2" + +jest-leak-detector@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz#5b7ec0dadfdfec0ca383dc9aa016d36b5ea4c728" + integrity sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw== + dependencies: + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-matcher-utils@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12" + integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g== + dependencies: + chalk "^4.0.0" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-message-util@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.7.0.tgz#8bc392e204e95dfe7564abbe72a404e28e51f7f3" + integrity sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^29.6.3" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^29.7.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-mock@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.7.0.tgz#4e836cf60e99c6fcfabe9f99d017f3fdd50a6347" + integrity sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-util "^29.7.0" + +jest-pnp-resolver@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" + integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== + +jest-regex-util@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.6.3.tgz#4a556d9c776af68e1c5f48194f4d0327d24e8a52" + integrity sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg== + +jest-resolve-dependencies@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz#1b04f2c095f37fc776ff40803dc92921b1e88428" + integrity sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA== + dependencies: + jest-regex-util "^29.6.3" + jest-snapshot "^29.7.0" + +jest-resolve@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.7.0.tgz#64d6a8992dd26f635ab0c01e5eef4399c6bcbc30" + integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== + dependencies: + chalk "^4.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-pnp-resolver "^1.2.2" + jest-util "^29.7.0" + jest-validate "^29.7.0" + resolve "^1.20.0" + resolve.exports "^2.0.0" + slash "^3.0.0" + +jest-runner@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.7.0.tgz#809af072d408a53dcfd2e849a4c976d3132f718e" + integrity sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ== + dependencies: + "@jest/console" "^29.7.0" + "@jest/environment" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.13.1" + graceful-fs "^4.2.9" + jest-docblock "^29.7.0" + jest-environment-node "^29.7.0" + jest-haste-map "^29.7.0" + jest-leak-detector "^29.7.0" + jest-message-util "^29.7.0" + jest-resolve "^29.7.0" + jest-runtime "^29.7.0" + jest-util "^29.7.0" + jest-watcher "^29.7.0" + jest-worker "^29.7.0" + p-limit "^3.1.0" + source-map-support "0.5.13" + +jest-runtime@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.7.0.tgz#efecb3141cf7d3767a3a0cc8f7c9990587d3d817" + integrity sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/globals" "^29.7.0" + "@jest/source-map" "^29.6.3" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + slash "^3.0.0" + strip-bom "^4.0.0" + +jest-snapshot@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.7.0.tgz#c2c574c3f51865da1bb329036778a69bf88a6be5" + integrity sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw== + dependencies: + "@babel/core" "^7.11.6" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-jsx" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/types" "^7.3.3" + "@jest/expect-utils" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^29.7.0" + graceful-fs "^4.2.9" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + natural-compare "^1.4.0" + pretty-format "^29.7.0" + semver "^7.5.3" + +jest-util@^29.0.0, jest-util@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc" + integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-validate@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.7.0.tgz#7bf705511c64da591d46b15fce41400d52147d9c" + integrity sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw== + dependencies: + "@jest/types" "^29.6.3" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^29.6.3" + leven "^3.1.0" + pretty-format "^29.7.0" + +jest-watcher@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.7.0.tgz#7810d30d619c3a62093223ce6bb359ca1b28a2f2" + integrity sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g== + dependencies: + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.13.1" + jest-util "^29.7.0" + string-length "^4.0.1" + +jest-worker@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.7.0.tgz#acad073acbbaeb7262bd5389e1bcf43e10058d4a" + integrity sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw== + dependencies: + "@types/node" "*" + jest-util "^29.7.0" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest/-/jest-29.7.0.tgz#994676fc24177f088f1c5e3737f5697204ff2613" + integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== + dependencies: + "@jest/core" "^29.7.0" + "@jest/types" "^29.6.3" + import-local "^3.0.2" + jest-cli "^29.7.0" + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +json5@^2.2.2, json5@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + +keyv@^4.5.4: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.memoize@4.x: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +make-dir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" + integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== + dependencies: + semver "^7.5.3" + +make-error@1.x, make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== + dependencies: + tmpl "1.0.5" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== + +micromatch@^4.0.4: + version "4.0.7" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.7.tgz#33e8190d9fe474a9895525f5618eee136d46c2e5" + integrity sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + +mime-db@1.52.0, mime-db@^1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12, mime-types@~2.1.24, mime-types@~2.1.34: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^9.0.4: + version "9.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.4.tgz#8e49c731d1749cbec05050ee5145147b32496a51" + integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw== + dependencies: + brace-expansion "^2.0.1" + +minimist@^1.2.6: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +negotiator@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== + +node-releases@^2.0.14: + version "2.0.14" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" + integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +object-inspect@^1.13.1: + version "1.13.1" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" + integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== + +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +optionator@^0.9.3: + version "0.9.4" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.5" + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2, p-limit@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-json@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +pg-cloudflare@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz#e6d5833015b170e23ae819e8c5d7eaedb472ca98" + integrity sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q== + +pg-connection-string@^2.6.4: + version "2.6.4" + resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.6.4.tgz#f543862adfa49fa4e14bc8a8892d2a84d754246d" + integrity sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA== + +pg-int8@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c" + integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw== + +pg-minify@1.6.4: + version "1.6.4" + resolved "https://registry.yarnpkg.com/pg-minify/-/pg-minify-1.6.4.tgz#b8c353c6ac88985f701cf4191df6269e4956a4f7" + integrity sha512-cf6hBt1YqzqPX0OznXKSv4U7e4o7eUU4zp2zQsbJ+4OCNNr7EnnAVWkIz4k0dv6UN4ouS1ZL4WlXxCrZHHl69g== + +pg-pool@^3.6.2: + version "3.6.2" + resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.6.2.tgz#3a592370b8ae3f02a7c8130d245bc02fa2c5f3f2" + integrity sha512-Htjbg8BlwXqSBQ9V8Vjtc+vzf/6fVUuak/3/XXKA9oxZprwW3IMDQTGHP+KDmVL7rtd+R1QjbnCFPuTHm3G4hg== + +pg-promise@^11.8.0: + version "11.8.0" + resolved "https://registry.yarnpkg.com/pg-promise/-/pg-promise-11.8.0.tgz#f8bad67b670163678e0387f5fb45ee1e19985c05" + integrity sha512-w9hTFpkM4FByJTJ7KCWLtZSOtQa2BKC+XIV8+3ZvDlfYfBYdz8V4V+BttnqhUPY/d12Itug7Bft4XdILihsY+w== + dependencies: + assert-options "0.8.1" + pg "8.11.5" + pg-minify "1.6.4" + spex "3.3.0" + +pg-protocol@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.6.1.tgz#21333e6d83b01faaebfe7a33a7ad6bfd9ed38cb3" + integrity sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg== + +pg-types@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.2.0.tgz#2d0250d636454f7cfa3b6ae0382fdfa8063254a3" + integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA== + dependencies: + pg-int8 "1.0.1" + postgres-array "~2.0.0" + postgres-bytea "~1.0.0" + postgres-date "~1.0.4" + postgres-interval "^1.1.0" + +pg@8.11.5: + version "8.11.5" + resolved "https://registry.yarnpkg.com/pg/-/pg-8.11.5.tgz#e722b0a5f1ed92931c31758ebec3ddf878dd4128" + integrity sha512-jqgNHSKL5cbDjFlHyYsCXmQDrfIX/3RsNwYqpd4N0Kt8niLuNoRNH+aazv6cOd43gPh9Y4DjQCtb+X0MH0Hvnw== + dependencies: + pg-connection-string "^2.6.4" + pg-pool "^3.6.2" + pg-protocol "^1.6.1" + pg-types "^2.1.0" + pgpass "1.x" + optionalDependencies: + pg-cloudflare "^1.1.1" + +pgpass@1.x: + version "1.0.5" + resolved "https://registry.yarnpkg.com/pgpass/-/pgpass-1.0.5.tgz#9b873e4a564bb10fa7a7dbd55312728d422a223d" + integrity sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug== + dependencies: + split2 "^4.1.0" + +picocolors@^1.0.0, picocolors@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" + integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pirates@^4.0.4: + version "4.0.6" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" + integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +postgres-array@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" + integrity sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA== + +postgres-bytea@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35" + integrity sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w== + +postgres-date@~1.0.4: + version "1.0.7" + resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.7.tgz#51bc086006005e5061c591cee727f2531bf641a8" + integrity sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q== + +postgres-interval@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-1.2.0.tgz#b460c82cb1587507788819a06aa0fffdb3544695" + integrity sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ== + dependencies: + xtend "^4.0.0" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prettier@3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.2.tgz#03ff86dc7c835f2d2559ee76876a3914cec4a90a" + integrity sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA== + +pretty-format@^29.0.0, pretty-format@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" + integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== + dependencies: + "@jest/schemas" "^29.6.3" + ansi-styles "^5.0.0" + react-is "^18.0.0" + +prompts@^2.0.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + +proxy-addr@~2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + +punycode@^2.1.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + +pure-rand@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.1.0.tgz#d173cf23258231976ccbdb05247c9787957604f2" + integrity sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA== + +qs@6.11.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== + dependencies: + side-channel "^1.0.4" + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" + integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== + dependencies: + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" + unpipe "1.0.0" + +react-is@^18.0.0: + version "18.3.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" + integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve.exports@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" + integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== + +resolve@^1.0.0, resolve@^1.20.0: + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rimraf@^2.6.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +safe-buffer@5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +semver@^6.3.0, semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.5.3, semver@^7.5.4, semver@^7.6.0: + version "7.6.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13" + integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== + +send@0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" + integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== + dependencies: + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "2.0.0" + mime "1.6.0" + ms "2.1.3" + on-finished "2.4.1" + range-parser "~1.2.1" + statuses "2.0.1" + +serve-static@1.15.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" + integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.18.0" + +set-function-length@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +side-channel@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" + integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + object-inspect "^1.13.1" + +signal-exit@^3.0.3, signal-exit@^3.0.7: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +source-map-support@0.5.13: + version "0.5.13" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-support@^0.5.12: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0, source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +spex@3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/spex/-/spex-3.3.0.tgz#169ecc6146f2eb070d5e846d32046ea355096920" + integrity sha512-VNiXjFp6R4ldPbVRYbpxlD35yRHceecVXlct1J4/X80KuuPnW2AXMq3sGwhnJOhKkUsOxAT6nRGfGE5pocVw5w== + +split2@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4" + integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== + +stack-utils@^2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" + integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== + dependencies: + escape-string-regexp "^2.0.0" + +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== + +string-length@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== + dependencies: + char-regex "^1.0.2" + strip-ansi "^6.0.0" + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== + +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-json-comments@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +swagger-ui-dist@>=5.0.0: + version "5.17.14" + resolved "https://registry.yarnpkg.com/swagger-ui-dist/-/swagger-ui-dist-5.17.14.tgz#e2c222e5bf9e15ccf80ec4bc08b4aaac09792fd6" + integrity sha512-CVbSfaLpstV65OnSjbXfVd6Sta3q3F7Cj/yYuvHMp1P90LztOLs6PfUnKEVAeiIVQt9u2SaPwv0LiH/OyMjHRw== + +swagger-ui-express@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/swagger-ui-express/-/swagger-ui-express-5.0.1.tgz#fb8c1b781d2793a6bd2f8a205a3f4bd6fa020dd8" + integrity sha512-SrNU3RiBGTLLmFU8GIJdOdanJTl4TOmT27tt3bWWHppqYmAZ6IDuEuBvMU6nZq0zLEe6b/1rACXCgLZqO6ZfrA== + dependencies: + swagger-ui-dist ">=5.0.0" + +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +tmpl@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + +tree-kill@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" + integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== + +ts-api-utils@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" + integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== + +ts-jest@^29.1.4: + version "29.1.4" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.1.4.tgz#26f8a55ce31e4d2ef7a1fd47dc7fa127e92793ef" + integrity sha512-YiHwDhSvCiItoAgsKtoLFCuakDzDsJ1DLDnSouTaTmdOcOwIkSzbLXduaQ6M5DRVhuZC/NYaaZ/mtHbWMv/S6Q== + dependencies: + bs-logger "0.x" + fast-json-stable-stringify "2.x" + jest-util "^29.0.0" + json5 "^2.2.3" + lodash.memoize "4.x" + make-error "1.x" + semver "^7.5.3" + yargs-parser "^21.0.1" + +ts-node-dev@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ts-node-dev/-/ts-node-dev-2.0.0.tgz#bdd53e17ab3b5d822ef519928dc6b4a7e0f13065" + integrity sha512-ywMrhCfH6M75yftYvrvNarLEY+SUXtUvU8/0Z6llrHQVBx12GiFk5sStF8UdfE/yfzk9IAq7O5EEbTQsxlBI8w== + dependencies: + chokidar "^3.5.1" + dynamic-dedupe "^0.3.0" + minimist "^1.2.6" + mkdirp "^1.0.4" + resolve "^1.0.0" + rimraf "^2.6.1" + source-map-support "^0.5.12" + tree-kill "^1.2.2" + ts-node "^10.4.0" + tsconfig "^7.0.0" + +ts-node@^10.4.0, ts-node@^10.9.2: + version "10.9.2" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" + integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== + dependencies: + "@cspotcode/source-map-support" "^0.8.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + v8-compile-cache-lib "^3.0.1" + yn "3.1.1" + +tsconfig-paths@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz#ef78e19039133446d244beac0fd6a1632e2d107c" + integrity sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg== + dependencies: + json5 "^2.2.2" + minimist "^1.2.6" + strip-bom "^3.0.0" + +tsconfig@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/tsconfig/-/tsconfig-7.0.0.tgz#84538875a4dc216e5c4a5432b3a4dec3d54e91b7" + integrity sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw== + dependencies: + "@types/strip-bom" "^3.0.0" + "@types/strip-json-comments" "0.0.30" + strip-bom "^3.0.0" + strip-json-comments "^2.0.0" + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-detect@4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +typescript-eslint@^7.13.0: + version "7.13.0" + resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-7.13.0.tgz#bfd6f139b61e12d171af8621869785cb3b29f1b7" + integrity sha512-upO0AXxyBwJ4BbiC6CRgAJKtGYha2zw4m1g7TIVPSonwYEuf7vCicw3syjS1OxdDMTz96sZIXl3Jx3vWJLLKFw== + dependencies: + "@typescript-eslint/eslint-plugin" "7.13.0" + "@typescript-eslint/parser" "7.13.0" + "@typescript-eslint/utils" "7.13.0" + +typescript@^5.4.5: + version "5.4.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.5.tgz#42ccef2c571fdbd0f6718b1d1f5e6e5ef006f611" + integrity sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ== + +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== + +update-browserslist-db@^1.0.13: + version "1.0.16" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz#f6d489ed90fb2f07d67784eb3f53d7891f736356" + integrity sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ== + dependencies: + escalade "^3.1.2" + picocolors "^1.0.1" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== + +v8-compile-cache-lib@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" + integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== + +v8-to-istanbul@^9.0.1: + version "9.2.0" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz#2ed7644a245cddd83d4e087b9b33b3e62dfd10ad" + integrity sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.12" + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^2.0.0" + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== + +walker@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== + dependencies: + makeerror "1.0.12" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +word-wrap@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +write-file-atomic@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" + integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== + dependencies: + imurmurhash "^0.1.4" + signal-exit "^3.0.7" + +xtend@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yargs-parser@^21.0.1, yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs@^17.3.1: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==