diff --git a/.dockerignore b/.dockerignore index 9e49e45..e86c028 100644 --- a/.dockerignore +++ b/.dockerignore @@ -14,7 +14,7 @@ config.json .env # Log files -*.log +logs/ # Git folder .git/ diff --git a/.env.example b/.env.example index c600f23..6e0f6a1 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,4 @@ -ACORE_ARMORY_AOWOW_URL="https://wotlkdb.com" +ACORE_ARMORY_AOWOW_URL="https://wowgaming.altervista.org/aowow" ACORE_ARMORY_WEBSITE_URL="https://mywebsite.com" ACORE_ARMORY_WEBSITE_NAME="My Website" ACORE_ARMORY_WEBSITE_ROOT="" @@ -6,6 +6,8 @@ ACORE_ARMORY_IFRAME_MODE__ENABLED=0 ACORE_ARMORY_IFRAME_MODE__URL="https://mywebsite.com/armory" ACORE_ARMORY_LOAD_DBCS=1 ACORE_ARMORY_HIDE_GAME_MASTERS=1 +ACORE_ARMORY_TRANSMOG_MODULE=0 +ACORE_ARMORY_USE_ZAM_CDN=0 ACORE_ARMORY_REALMS__0__NAME="AzerothCore" ACORE_ARMORY_REALMS__0__REALM_ID=1 ACORE_ARMORY_REALMS__0__AUTH_DATABASE="acore_auth" diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..6d4f875 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,33 @@ +{ + "env": { + "es2021": true + }, + "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"], + "parser": "@typescript-eslint/parser", + "plugins": ["@typescript-eslint"], + "rules": { + "semi": ["error", "always"], + "@typescript-eslint/no-unused-vars": [ + "warn", + { + "args": "none" + } + ], + "no-duplicate-imports": "warn", + "no-promise-executor-return": "warn", + "quote-props": ["warn", "as-needed"], + "indent": "off", + "@typescript-eslint/indent": [ + "error", + "tab", + { + "ignoredNodes": [ + "FunctionExpression > .params[decorators.length > 0]", + "FunctionExpression > .params > :matches(Decorator, :not(:first-child))", + "ClassBody.body > PropertyDefinition[decorators.length > 0] > .key" + ], + "SwitchCase": 1 + } + ] + } +} diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..1eb62d1 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +ko_fi: roboto diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..92c7737 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,13 @@ +name: Build +on: + push: + pull_request: + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + - run: npm ci + - run: npm run build diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..32024ee --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,13 @@ +name: Lint +on: + push: + pull_request: + +jobs: + eslint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + - run: npm ci + - run: npm run lint -- --max-warnings=0 diff --git a/.gitignore b/.gitignore index bf212dc..265ef32 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,6 @@ config.json # Log files *.log + +# IDEs +.vscode/ diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..0e6b8cc --- /dev/null +++ b/.prettierignore @@ -0,0 +1,21 @@ +.tmp +.idea +.vscode +.npmrc +.nvmrc +node_modules/ +.env* +/data/ +build/ +build-tools/ +logs/ +reports/ +coverage/ +dist/ +**/*.md +**/*.yml +package-lock.json +static/**/*.min.js +static/**/*.min.css +static/**/*.hbs +config.json diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..e1157be --- /dev/null +++ b/.prettierrc @@ -0,0 +1,9 @@ +{ + "printWidth": 140, + "useTabs": true, + "semi": true, + "singleQuote": false, + "trailingComma": "all", + "bracketSpacing": true, + "arrowParens": "always" +} diff --git a/README.md b/README.md index 4d0f92c..3e6bc6f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ +[![Build](https://github.com/r-o-b-o-t-o/azerothcore-armory/actions/workflows/build.yml/badge.svg)](https://github.com/r-o-b-o-t-o/azerothcore-armory/actions/workflows/build.yml) [![Stargazers][stars-shield]][stars-url] [![Forks][forks-shield]][forks-url] [![Issues][issues-shield]][issues-url] @@ -11,11 +12,13 @@

A website to view your AzerothCore server's characters
- Report a Bug + Report a Bug · - Request a Feature + Suggest a Feature · - Ask a Question + Ask a Question + · + Demo

@@ -108,45 +111,40 @@ I also noticed that such a tool was frequently requested in the AzerothCore Disc ```sh git clone git@github.com:r-o-b-o-t-o/azerothcore-armory.git ``` -3. Install the dependencies: +2. Install the dependencies: ```sh cd azerothcore-armory/ npm install ``` -4. Configure the application: copy `config.default.json` to `config.json` or `.env.example` to `.env` and edit the resulting file. +3. Configure the application: copy `config.default.json` to `config.json` or `.env.example` to `.env` and edit the resulting file. See the [Configuration Reference](#configuration-reference) below for a description of all values. -5. Download the model viewer's data: - * Download from script: - ```sh - npm run build - npm run fetchdata - ``` - **OR** - * Download the latest archive (`data.zip`) from the [Releases](https://github.com/r-o-b-o-t-o/azerothcore-armory/releases) page and extract it to the `data/` directory. +4. Download the model viewer's data from the [Releases](https://github.com/r-o-b-o-t-o/azerothcore-armory/releases) page and extract it to the `data/` directory. ### Configuration Reference
Main configuration -| config.json | .env | Type | Default value | Description | -|--------------------------------|----------------------------------------------------|-------------------------------|----------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `aowowUrl` | `ACORE_ARMORY_AOWOW_URL` | String | `"https://wotlkdb.com"` | The URL of the AoWoW database to use for tooltips and links | -| `websiteUrl` | `ACORE_ARMORY_WEBSITE_URL` | String | `"https://mywebsite.com"` | Your website's URL. Used to redirect to the homepage on error pages | -| `websiteName` | `ACORE_ARMORY_WEBSITE_NAME` | String | `"My Website"` | Your website's name. Displayed in the redirect button on error pages | -| `websiteRoot` | `ACORE_ARMORY_WEBSITE_ROOT` | String | `""` | The root of your armory's URL. If your armory is hosted on, for example, `http://mywebsite.com/azerothcore-armory`, the `websiteRoot` value should be `"/azerothcore-armory"` | -| `iframeMode` | `ACORE_ARMORY_IFRAME_MODE__`... | Object | | Settings for the iframe mode | -| `iframeMode.enabled` | `ACORE_ARMORY_IFRAME_MODE__ENABLED` | Boolean | `false` | Set to `true` if you want to embed the armory in an iframe | -| `iframeMode.url` | `ACORE_ARMORY_IFRAME_MODE__URL` | String | `"https://mywebsite.com/armory"` | Set this to the URL of the page that hosts the `iframe` | -| `loadDbcs` | `ACORE_ARMORY_LOAD_DBCS` | Boolean | `true` | Loads the DBC data from the `data` directory into memory when starting up. It is highly recommended to set this to `true`. Only use `false` to keep memory usage low, on a test server for example | -| `hideGameMasters` | `ACORE_ARMORY_HIDE_GAME_MASTERS` | Boolean | `true` | Hides Game Master characters if set to `true`. They will not be found in the search page, and their character pages will show a 404 error | -| `realms` | `ACORE_ARMORY_REALMS__`... | Array of objects | | An array of realm configurations | -| `realms[0].name` | `ACORE_ARMORY_REALMS__0__NAME` | String | `"AzerothCore"` | The name of the realm. Will be used in the URLs, shown on the character pages and in the search page if you have multiple realms | -| `realms[0].realmId` | `ACORE_ARMORY_REALMS__0__REALM_ID` | Number | `1` | The realm's ID, this must match the `id` column of the `realmlist` table in the auth database | -| `realms[0].authDatabase` | `ACORE_ARMORY_REALMS__0__AUTH_DATABASE` | String | `"acore_auth"` | The name of the auth database | -| `realms[0].charactersDatabase` | `ACORE_ARMORY_REALMS__0__CHARACTERS_DATABASE__`... | Database configuration object | | Configuration for the characters database. See "Database configuration" below | -| `worldDatabase` | `ACORE_ARMORY_WORLD_DATABASE__`... | Database configuration object | | Configuration for the world database. This is shared between all realms at the moment. See "Database configuration" below | -| `dbQueryTimeout` | `ACORE_ARMORY_DB_QUERY_TIMEOUT` | Number | `10000` | The maximum duration in milliseconds of a database query before it times out | +| config.json | .env | Type | Default value | Description | +|--------------------------------|----------------------------------------------------|-------------------------------|--------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `aowowUrl` | `ACORE_ARMORY_AOWOW_URL` | String | `"https://wowgaming.altervista.org/aowow"` | The URL of the AoWoW database to use for tooltips and links | +| `websiteUrl` | `ACORE_ARMORY_WEBSITE_URL` | String | `"https://mywebsite.com"` | Your website's URL. Used to redirect to the homepage on error pages | +| `websiteName` | `ACORE_ARMORY_WEBSITE_NAME` | String | `"My Website"` | Your website's name. Displayed in the redirect button on error pages | +| `websiteRoot` | `ACORE_ARMORY_WEBSITE_ROOT` | String | `""` | The root of your armory's URL. If your armory is hosted on, for example, `http://mywebsite.com/azerothcore-armory`, the `websiteRoot` value should be `"/azerothcore-armory"` | +| `iframeMode` | `ACORE_ARMORY_IFRAME_MODE__`... | Object | | Settings for the iframe mode | +| `iframeMode.enabled` | `ACORE_ARMORY_IFRAME_MODE__ENABLED` | Boolean | `false` | Set to `true` if you want to embed the armory in an iframe | +| `iframeMode.url` | `ACORE_ARMORY_IFRAME_MODE__URL` | String | `"https://mywebsite.com/armory"` | Set this to the URL of the page that hosts the `iframe` | +| `loadDbcs` | `ACORE_ARMORY_LOAD_DBCS` | Boolean | `true` | Loads the DBC data from the `data` directory into memory when starting up. It is highly recommended to set this to `true`. Only use `false` to keep memory usage low, on a test server for example | +| `hideGameMasters` | `ACORE_ARMORY_HIDE_GAME_MASTERS` | Boolean | `true` | Hides Game Master characters if set to `true`. They will not be found in the search page, and their character pages will show a 404 error | +| `transmogModule` | `ACORE_ARMORY_TRANSMOG_MODULE` | Boolean | `false` | Set this to `true` if your server uses the [transmogrification module](https://github.com/azerothcore/mod-transmog) and you want to display the transmogrified items on the 3D model | +| `useZamCdn` | `ACORE_ARMORY_USE_ZAM_CDN` | Boolean | `false` | Set this to `true` to use the ZAM network CDN for the 3D model viewer instead of the assets in your local `data` folder | +| `realms` | `ACORE_ARMORY_REALMS__`... | Array of objects | | An array of realm configurations | +| `realms[0].name` | `ACORE_ARMORY_REALMS__0__NAME` | String | `"AzerothCore"` | The name of the realm. Will be used in the URLs, shown on the character pages and in the search page if you have multiple realms | +| `realms[0].realmId` | `ACORE_ARMORY_REALMS__0__REALM_ID` | Number | `1` | The realm's ID, this must match the `id` column of the `realmlist` table in the auth database | +| `realms[0].authDatabase` | `ACORE_ARMORY_REALMS__0__AUTH_DATABASE` | String | `"acore_auth"` | The name of the auth database | +| `realms[0].charactersDatabase` | `ACORE_ARMORY_REALMS__0__CHARACTERS_DATABASE__`... | Database configuration object | | Configuration for the characters database. See "Database configuration" below | +| `worldDatabase` | `ACORE_ARMORY_WORLD_DATABASE__`... | Database configuration object | | Configuration for the world database. This is shared between all realms at the moment. See "Database configuration" below | +| `dbQueryTimeout` | `ACORE_ARMORY_DB_QUERY_TIMEOUT` | Number | `10000` | The maximum duration in milliseconds of a database query before it times out |
@@ -180,8 +178,7 @@ Open a web browser and navigate to http://localhost:48733 Other useful npm scripts: * `npm run clean`: cleans the build directory * `npm run watch`: watches for changes and rebuilds automatically, useful for development -* `npm run fetchdata`: downloads the data needed by the 3d model viewer -* `npm run cleardata`: clears the data downloaded for the 3d model viewer +* `npm run cleardata`: clears the data downloaded for the 3D model viewer ### With Docker @@ -257,7 +254,7 @@ This repository is used in production over at [ChromieCraft](https://www.chromie - [X] Character page - [X] Online/offline status - [X] Equipment with tooltips - - [X] 3d model, including mounts + - [X] 3D model, including mounts and [transmogrifications](https://github.com/azerothcore/mod-transmog) - [X] Talent trees, including glyphs and dual spec support - [X] Achievements - [X] PvP statistics, including arena teams @@ -271,6 +268,8 @@ This repository is used in production over at [ChromieCraft](https://www.chromie - [X] Multiple realms support - [ ] PvE ladder - [ ] PvP ladder +- [X] Arena ladder +- [ ] Achievements ladder See the [open issues](https://github.com/r-o-b-o-t-o/azerothcore-armory/issues) for a list of suggested features and known issues. @@ -308,7 +307,7 @@ Distributed under the MIT License. See the [`LICENSE`][license-url] file for mor ## Contact - Feel free to get in touch with me on Discord: `Roboto#9185` + Feel free to get in touch with me on Discord: `roboto_`

(back to top)

@@ -324,4 +323,4 @@ Distributed under the MIT License. See the [`LICENSE`][license-url] file for mor [issues-url]: https://github.com/r-o-b-o-t-o/azerothcore-armory/issues [license-shield]: https://img.shields.io/github/license/r-o-b-o-t-o/azerothcore-armory.svg?style=flat [license-url]: https://github.com/r-o-b-o-t-o/azerothcore-armory/blob/master/LICENSE -[feature-request]: https://github.com/r-o-b-o-t-o/azerothcore-armory/issues/new?template=feature_request.yml +[feature-request]: https://github.com/r-o-b-o-t-o/azerothcore-armory/issues/new?assignees=&labels=enhancement&template=feature_request.yml diff --git a/config.default.json b/config.default.json index f05a2cf..70f9fcb 100644 --- a/config.default.json +++ b/config.default.json @@ -1,5 +1,5 @@ { - "aowowUrl": "https://wotlkdb.com", + "aowowUrl": "https://wowgaming.altervista.org/aowow", "websiteUrl": "https://mywebsite.com", "websiteName": "My Website", "websiteRoot": "", @@ -9,6 +9,10 @@ }, "loadDbcs": true, "hideGameMasters": true, + "hideBotAccounts": true, + "botAccountPatterns": "RNDBOT%", + "transmogModule": false, + "useZamCdn": false, "realms": [ { "name": "AzerothCore", diff --git a/docker-compose.mythica.yml b/docker-compose.mythica.yml new file mode 100644 index 0000000..4153f7e --- /dev/null +++ b/docker-compose.mythica.yml @@ -0,0 +1,92 @@ +# Portainer stack for the Mythica armory. +# +# Differs from the upstream docker-compose.yml in three ways, all of them +# because Portainer deploys from a git checkout it manages itself: +# +# 1. Configuration comes from environment variables set in the Portainer +# stack UI, not from a .env file in the repo (upstream uses env_file, +# which Portainer git stacks do not provide). +# 2. Only the four large model-data directories are bind-mounted from the +# host. The DBC .csv files stay in the image so they stay versioned with +# the code, and Portainer re-cloning the repo cannot wipe the 2 GB of +# model data. +# 3. The unused ac-network block is dropped. +# +# See docs/mythica-deploy.md for the full procedure. + +services: + armory: + build: + context: . + dockerfile: Dockerfile + container_name: mythica-armory + restart: unless-stopped + + environment: + # --- site identity ------------------------------------------------- + ACORE_ARMORY_WEBSITE_NAME: ${ARMORY_WEBSITE_NAME:-Mythica} + ACORE_ARMORY_WEBSITE_URL: ${ARMORY_WEBSITE_URL:-http://192.168.1.77:48733} + ACORE_ARMORY_WEBSITE_ROOT: ${ARMORY_WEBSITE_ROOT:-} + + # Item tooltips and item icons are loaded from this AoWoW instance. + # The default is a public third-party site: point this at your own + # AoWoW if you do not want that dependency. + ACORE_ARMORY_AOWOW_URL: ${ARMORY_AOWOW_URL:-https://wowgaming.altervista.org/aowow} + + # --- embedding ----------------------------------------------------- + # Set both when embedding the armory in a page on the main site. + ACORE_ARMORY_IFRAME_MODE__ENABLED: ${ARMORY_IFRAME_ENABLED:-0} + ACORE_ARMORY_IFRAME_MODE__URL: ${ARMORY_IFRAME_URL:-} + + # --- behaviour ----------------------------------------------------- + ACORE_ARMORY_LOAD_DBCS: ${ARMORY_LOAD_DBCS:-1} + # Off by default here: GM accounts on this realm belong to real + # players who should appear in the armory like anyone else. Set to + # 1 to hide them from search and 404 their character pages. + ACORE_ARMORY_HIDE_GAME_MASTERS: ${ARMORY_HIDE_GMS:-0} + + # Playerbots are ordinary accounts, not game masters, so the GM + # filter does not touch them. Without this the armory lists ~1350 + # bots against ~29 real characters. + # Comma-separated LIKE patterns. RNDBOT% covers the Playerbots + # accounts; ahouse is the auction-house bot, which owns 9 mule + # characters. Add further service accounts here as they appear. + ACORE_ARMORY_HIDE_BOT_ACCOUNTS: ${ARMORY_HIDE_BOTS:-1} + ACORE_ARMORY_BOT_ACCOUNT_PATTERNS: ${ARMORY_BOT_PATTERNS:-RNDBOT%,ahouse} + ACORE_ARMORY_TRANSMOG_MODULE: ${ARMORY_TRANSMOG:-0} + + # 0 = serve 3D model assets from the local data directory. + # Leave it at 0: the upstream fetch tool can no longer rebuild this + # data from the Zam CDN, so the local copy is the only source. + ACORE_ARMORY_USE_ZAM_CDN: ${ARMORY_USE_ZAM_CDN:-0} + + # --- realm --------------------------------------------------------- + ACORE_ARMORY_REALMS__0__NAME: ${ARMORY_REALM_NAME:-Mythica} + ACORE_ARMORY_REALMS__0__REALM_ID: ${ARMORY_REALM_ID:-1} + ACORE_ARMORY_REALMS__0__AUTH_DATABASE: ${ARMORY_AUTH_DB:-acore_auth} + ACORE_ARMORY_REALMS__0__CHARACTERS_DATABASE__HOST: ${ARMORY_DB_HOST:-192.168.1.60} + ACORE_ARMORY_REALMS__0__CHARACTERS_DATABASE__PORT: ${ARMORY_DB_PORT:-3306} + ACORE_ARMORY_REALMS__0__CHARACTERS_DATABASE__USER: ${ARMORY_DB_USER:?set ARMORY_DB_USER} + ACORE_ARMORY_REALMS__0__CHARACTERS_DATABASE__PASSWORD: ${ARMORY_DB_PASS:?set ARMORY_DB_PASS} + ACORE_ARMORY_REALMS__0__CHARACTERS_DATABASE__DATABASE: ${ARMORY_CHARACTERS_DB:-acore_characters} + + # --- world database ------------------------------------------------- + ACORE_ARMORY_WORLD_DATABASE__HOST: ${ARMORY_DB_HOST:-192.168.1.60} + ACORE_ARMORY_WORLD_DATABASE__PORT: ${ARMORY_DB_PORT:-3306} + ACORE_ARMORY_WORLD_DATABASE__USER: ${ARMORY_DB_USER:?set ARMORY_DB_USER} + ACORE_ARMORY_WORLD_DATABASE__PASSWORD: ${ARMORY_DB_PASS:?set ARMORY_DB_PASS} + ACORE_ARMORY_WORLD_DATABASE__DATABASE: ${ARMORY_WORLD_DB:-acore_world} + + ACORE_ARMORY_DB_QUERY_TIMEOUT: ${ARMORY_DB_TIMEOUT:-10000} + + volumes: + # The 3D model payload, extracted from the release archive. These + # four directories are exactly the top level of data.tar.gz. + - ${ARMORY_DATA_DIR:-/opt/mythica-armory/data}/meta:/data/meta + - ${ARMORY_DATA_DIR:-/opt/mythica-armory/data}/bone:/data/bone + - ${ARMORY_DATA_DIR:-/opt/mythica-armory/data}/mo3:/data/mo3 + - ${ARMORY_DATA_DIR:-/opt/mythica-armory/data}/textures:/data/textures + - ${ARMORY_LOG_DIR:-/opt/mythica-armory/logs}:/logs + + ports: + - "${ARMORY_PORT:-48733}:48733" diff --git a/docker-compose.yml b/docker-compose.yml index 373e708..74fbc36 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -17,3 +17,6 @@ services: networks: local-private-net: driver: bridge + ac-network: + name: ${DOCKER_AC_NETWORK_NAME:-azerothcore-wotlk_ac-network} # default network name if you use the docker setup of ac + external: ${DOCKER_AC_NETWORK_EXTERNAL:-false} diff --git a/docs/mythica-deploy.md b/docs/mythica-deploy.md new file mode 100644 index 0000000..2b67642 --- /dev/null +++ b/docs/mythica-deploy.md @@ -0,0 +1,140 @@ +# Deploying the armory on Nox + +This fork of [r-o-b-o-t-o/azerothcore-armory](https://github.com/r-o-b-o-t-o/azerothcore-armory) +(MIT) is set up to run as a Portainer stack on Nox, alongside the Mythica web +page, reading the AzerothCore databases on the game server over the LAN. + +**It must not run on the AzerothCore VM (192.168.1.60).** That box is tuned for +the playerbot load; anything extra there means redoing that balancing. Nothing +in this procedure touches the game server — the armory only reads its databases. + +--- + +## Why the model data is a manual step + +The armory needs about 2 GB of processed 3D model data — bone sets, mo3 meshes, +textures, and the per-race character descriptors. + +Upstream ships a `fetchdata` tool that downloads this from Zam's CDN. **It no +longer works.** Zam reorganised that part of the CDN, and every character path +now 404s (`meta/character/*`, `meta/charactercustomization2/*` — checked against +the `live`, `wrath` and `classic` prefixes and several filename variants). The +armor and item paths still resolve, so a run appears to succeed while silently +producing no character data, and the app then fails at startup on +`data/meta/charactercustomization2/1_0.json`. + +The only remaining source is the snapshot in upstream's v1.0.0 release. That +snapshot is mirrored into this fork's own release so the fork does not depend on +GitHub staying up for the one piece that cannot be regenerated. + +The mirrored copy is **split into five parts** because Nginx Proxy Manager in +front of the forge rejects request bodies at that size (500 MB uploads fine, +2 GB returns 413). Raising `client_max_body_size` on the forge's proxy host +would let it be stored as a single file, if that is ever worth doing. + +--- + +## 1. Put the model data on Nox + +Once. Redeploying the stack does not disturb it. + +```bash +sudo mkdir -p /opt/mythica-armory/data /opt/mythica-armory/logs +sudo chown -R "$USER:$USER" /opt/mythica-armory # else the downloads below fail +cd /opt/mythica-armory/data + +BASE=https://gitlab.hallsworth.ca/yrtria/azerothcore-armory/releases/download/v1.0.0 +for i in 0 1 2 3 4; do curl -LO $BASE/data.tar.gz.part-$i; done +curl -LO $BASE/SHA256SUMS.txt + +cat data.tar.gz.part-* > data.tar.gz +sha256sum -c --ignore-missing SHA256SUMS.txt # data.tar.gz must say OK + +tar xzf data.tar.gz +rm -f data.tar.gz data.tar.gz.part-* +``` + +Afterwards `/opt/mythica-armory/data` holds four directories — `meta`, `bone`, +`mo3`, `textures` — totalling roughly 2.5 GB unpacked. + +Ownership by your own user is fine — the container reads these as root either +way, and it keeps the download and extract steps out of `sudo`. + +The DBC `.csv` files are **not** part of this. They are committed to the repo and +travel in the image, so they stay in step with the code. + +> `data.tar.gz.UPSTREAM-GITHUB-LINK.txt` on the same release is not the archive. +> It is the original external reference Forgejo recorded during migration — a +> short-lived signed GitHub URL, kept only for provenance. + +## 2. Create the Portainer stack + +Repository stack, same pattern as `wow-web-page`: + +| Field | Value | +|---|---| +| Repository URL | `https://gitlab.hallsworth.ca/yrtria/azerothcore-armory.git` | +| Reference | `refs/heads/master` | +| Compose path | `docker-compose.mythica.yml` | + +Environment variables — `ARMORY_DB_USER` and `ARMORY_DB_PASS` are required and +the stack refuses to start without them: + +| Variable | Value | +|---|---| +| `ARMORY_DB_USER` | database user (see §4) | +| `ARMORY_DB_PASS` | its password | +| `ARMORY_DB_HOST` | `192.168.1.60` | +| `ARMORY_WEBSITE_URL` | `https://armory.dionysismedia.ca` once proxied, otherwise `http://192.168.1.77:48733` | +| `ARMORY_WEBSITE_NAME` | `Mythica` | +| `ARMORY_REALM_ID` | `1` | +| `ARMORY_DATA_DIR` | `/opt/mythica-armory/data` | +| `ARMORY_LOG_DIR` | `/opt/mythica-armory/logs` | + +The first build compiles TypeScript, so it takes a few minutes. It listens on +48733. + +## 3. Reverse proxy + +Add a proxy host in NPM pointing at `192.168.1.77:48733`. + +To embed it in the main site instead of giving it its own subdomain, set +`ARMORY_IFRAME_ENABLED=1` and `ARMORY_IFRAME_URL` to the page that hosts the +iframe, then use the snippet in the upstream README. That path keeps the site's +own header and navigation around it. + +## 4. Database access + +`acore` is already granted from `192.168.1.%` and MySQL on the game server binds +`0.0.0.0`, so this works with no changes. But the armory only ever reads, and it +is public-facing, so a dedicated read-only user is worth the two minutes: + +```sql +CREATE USER 'armory'@'192.168.1.%' IDENTIFIED BY ''; +GRANT SELECT ON acore_characters.* TO 'armory'@'192.168.1.%'; +GRANT SELECT ON acore_world.* TO 'armory'@'192.168.1.%'; +GRANT SELECT ON acore_auth.* TO 'armory'@'192.168.1.%'; +FLUSH PRIVILEGES; +``` + +## 5. Things to know + +- **Item icons and tooltips come from a third-party AoWoW instance** + (`wowgaming.altervista.org` by default) — they are hotlinked, so they break if + that site moves or goes down. Point `ARMORY_AOWOW_URL` at your own AoWoW to + remove that dependency. This is the one remaining external asset dependency; + the model data is now self-hosted. +- **The armory has its own talent view** with dual-spec support, which overlaps + the talent page already in `WoW-Web-Page`. Decide which one owns the character + page rather than shipping both. +- **The Dockerfile builds from `node:16`**, which is end-of-life. It builds and + runs fine; bumping it is a separate change from getting this deployed. +- **`hideGameMasters` is off** in this stack, unlike upstream. GM accounts on + this realm belong to real players — `Spinnaker` among them — so hiding them + would hide people who should be listed. Set `ARMORY_HIDE_GMS=1` to restore + upstream behaviour. +- **Service accounts are hidden** via `hideBotAccounts` / `botAccountPatterns`, + a comma-separated list of LIKE patterns defaulting to `RNDBOT%,ahouse` — the + Playerbots accounts and the auction-house bot, which owns 9 mule characters. + None of them are game masters, so the GM filter never touched them. Add more + with `ARMORY_BOT_PATTERNS`, or set `ARMORY_HIDE_BOTS=0` to show them all. diff --git a/package-lock.json b/package-lock.json index 8500b72..5a2d050 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,24 +1,23 @@ { "name": "azerothcore-armory", - "version": "1.0.0", + "version": "1.1.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "azerothcore-armory", - "version": "1.0.0", + "version": "1.1.1", "license": "MIT", "dependencies": { - "@supercharge/promise-pool": "^2.1.0", + "@supercharge/promise-pool": "^2.3.0", "camelcase": "^6.3.0", - "cli-progress": "^3.10.0", - "dotenv": "^16.0.0", - "express": "^4.17.3", - "express-handlebars": "^6.0.2", - "glob": "^7.2.0", - "glob-promise": "^4.2.2", + "cli-progress": "^3.11.2", + "dotenv": "^16.0.1", + "express": "^4.18.1", + "express-handlebars": "^6.0.6", + "glob": "^8.0.3", "handlebars-helpers": "^0.9.8", - "html-entities": "^2.3.2", + "html-entities": "^2.3.3", "mkdirp": "^1.0.4", "morgan": "^1.10.0", "mysql2": "^2.3.3", @@ -27,22 +26,25 @@ "pretty-ms": "^7.0.1", "source-map-support": "^0.5.21", "uuid": "^8.3.2", - "winston": "^3.6.0" + "winston": "^3.8.0" }, "devDependencies": { - "@types/cli-progress": "^3.9.2", + "@types/cli-progress": "^3.11.0", "@types/express": "^4.17.13", "@types/glob": "^7.2.0", "@types/mkdirp": "^1.0.2", "@types/morgan": "^1.9.3", - "@types/node": "^17.0.21", - "@types/node-fetch": "^2.6.1", - "@types/pako": "^1.0.3", + "@types/node": "^18.0.0", + "@types/node-fetch": "^2.6.2", + "@types/pako": "^2.0.0", "@types/uuid": "^8.3.4", - "concurrently": "^7.0.0", - "nodemon": "^2.0.15", + "@typescript-eslint/eslint-plugin": "^5.30.0", + "concurrently": "^7.2.2", + "eslint": "^8.18.0", + "nodemon": "^2.0.18", + "prettier": "^2.7.1", "rimraf": "^3.0.2", - "typescript": "^4.5.5" + "typescript": "^4.7.4" } }, "node_modules/@colors/colors": { @@ -63,6 +65,139 @@ "kuler": "^2.0.0" } }, + "node_modules/@eslint/eslintrc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", + "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.3.2", + "globals": "^13.15.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" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@eslint/eslintrc/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@eslint/eslintrc/node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/@sindresorhus/is": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", @@ -73,9 +208,9 @@ } }, "node_modules/@supercharge/promise-pool": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@supercharge/promise-pool/-/promise-pool-2.1.0.tgz", - "integrity": "sha512-YEKOfn4xF+DQ61UY5NwHNtr8hYjwchXjGTocVJDAHLQceIRZF8VECH7gumFbp+aGTfygPbMbEtBumXJ/mcJz+w==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@supercharge/promise-pool/-/promise-pool-2.3.0.tgz", + "integrity": "sha512-KLf3JBWW4JymplvT/c5JCZhc4KrNE9EBf15FPjvklQiGcoUczSLInpV23iV5dITnvktJlwQ5xq08wfNwBk71Rg==", "engines": { "node": ">=8" } @@ -103,9 +238,9 @@ } }, "node_modules/@types/cli-progress": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/@types/cli-progress/-/cli-progress-3.9.2.tgz", - "integrity": "sha512-VO5/X5Ij+oVgEVjg5u0IXVe3JQSKJX+Ev8C5x+0hPy0AuWyW+bF8tbajR7cPFnDGhs7pidztcac+ccrDtk5teA==", + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/@types/cli-progress/-/cli-progress-3.11.0.tgz", + "integrity": "sha512-XhXhBv1R/q2ahF3BM7qT5HLzJNlIL0wbcGyZVjqOTqAybAnsLisd7gy1UCyIqpL+5Iv6XhlSyzjLCnI2sIdbCg==", "dev": true, "dependencies": { "@types/node": "*" @@ -147,11 +282,18 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "dev": true, "dependencies": { "@types/minimatch": "*", "@types/node": "*" } }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, "node_modules/@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", @@ -161,7 +303,8 @@ "node_modules/@types/minimatch": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==" + "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", + "dev": true }, "node_modules/@types/mkdirp": { "version": "1.0.2", @@ -182,14 +325,15 @@ } }, "node_modules/@types/node": { - "version": "17.0.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz", - "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==" + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.0.tgz", + "integrity": "sha512-cHlGmko4gWLVI27cGJntjs/Sj8th9aYwplmZFwmmgYQQvL5NUsgVJG7OddLvNfLqYS31KFN0s3qlaD9qCaxACA==", + "dev": true }, "node_modules/@types/node-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-oMqjURCaxoSIsHSr1E47QHzbmzNR5rK8McHuNb11BOM9cHcIK3Avy0s/b2JlXHoQGTYS3NsvWzV1M0iK7l0wbA==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz", + "integrity": "sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==", "dev": true, "dependencies": { "@types/node": "*", @@ -197,9 +341,9 @@ } }, "node_modules/@types/pako": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@types/pako/-/pako-1.0.3.tgz", - "integrity": "sha512-EDxOsHAD5dqjbjEUM1xwa7rpKPFb8ECBE5irONTQU7/OsO3thI5YrNEWSPNMvYmvFM0l/OLQJ6Mgw7PEdXSjhg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/pako/-/pako-2.0.0.tgz", + "integrity": "sha512-10+iaz93qR5WYxTo+PMifD5TSxiOtdRaxBf7INGGXMQgTCu8Z/7GYWYFUOS3q/G0nE5boj1r4FEB+WSy7s5gbA==", "dev": true }, "node_modules/@types/qs": { @@ -230,6 +374,503 @@ "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", "dev": true }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.0.tgz", + "integrity": "sha512-lvhRJ2pGe2V9MEU46ELTdiHgiAFZPKtLhiU5wlnaYpMc2+c1R8fh8i80ZAa665drvjHKUJyRRGg3gEm1If54ow==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.30.0", + "@typescript-eslint/type-utils": "5.30.0", + "@typescript-eslint/utils": "5.30.0", + "debug": "^4.3.4", + "functional-red-black-tree": "^1.0.1", + "ignore": "^5.2.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.30.0.tgz", + "integrity": "sha512-3TZxvlQcK5fhTBw5solQucWSJvonXf5yua5nx8OqK94hxdrT7/6W3/CS42MLd/f1BmlmmbGEgQcTHHCktUX5bQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.30.0", + "@typescript-eslint/visitor-keys": "5.30.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.30.0.tgz", + "integrity": "sha512-vfqcBrsRNWw/LBXyncMF/KrUTYYzzygCSsVqlZ1qGu1QtGs6vMkt3US0VNSQ05grXi5Yadp3qv5XZdYLjpp8ag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.0.tgz", + "integrity": "sha512-6WcIeRk2DQ3pHKxU1Ni0qMXJkjO/zLjBymlYBy/53qxe7yjEFSvzKLDToJjURUhSl2Fzhkl4SMXQoETauF74cw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.30.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.23.0.tgz", + "integrity": "sha512-V06cYUkqcGqpFjb8ttVgzNF53tgbB/KoQT/iB++DOIExKmzI9vBJKjZKt/6FuV9c+zrDsvJKbJ2DOCYwX91cbw==", + "dev": true, + "peer": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.23.0", + "@typescript-eslint/types": "5.23.0", + "@typescript-eslint/typescript-estree": "5.23.0", + "debug": "^4.3.2" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "peer": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "peer": true + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.23.0.tgz", + "integrity": "sha512-EhjaFELQHCRb5wTwlGsNMvzK9b8Oco4aYNleeDlNuL6qXWDF47ch4EhVNPh8Rdhf9tmqbN4sWDk/8g+Z/J8JVw==", + "dev": true, + "peer": true, + "dependencies": { + "@typescript-eslint/types": "5.23.0", + "@typescript-eslint/visitor-keys": "5.23.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.30.0.tgz", + "integrity": "sha512-GF8JZbZqSS+azehzlv/lmQQ3EU3VfWYzCczdZjJRxSEeXDQkqFhCBgFhallLDbPwQOEQ4MHpiPfkjKk7zlmeNg==", + "dev": true, + "dependencies": { + "@typescript-eslint/utils": "5.30.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/types": { + "version": "5.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.23.0.tgz", + "integrity": "sha512-NfBsV/h4dir/8mJwdZz7JFibaKC3E/QdeMEDJhiAE3/eMkoniZ7MjbEMCGXw6MZnZDMN3G9S0mH/6WUIj91dmw==", + "dev": true, + "peer": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.23.0.tgz", + "integrity": "sha512-xE9e0lrHhI647SlGMl+m+3E3CKPF1wzvvOEWnuE3CCjjT7UiRnDGJxmAcVKJIlFgK6DY9RB98eLr1OPigPEOGg==", + "dev": true, + "peer": true, + "dependencies": { + "@typescript-eslint/types": "5.23.0", + "@typescript-eslint/visitor-keys": "5.23.0", + "debug": "^4.3.2", + "globby": "^11.0.4", + "is-glob": "^4.0.3", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "peer": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "peer": true + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "peer": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.30.0.tgz", + "integrity": "sha512-0bIgOgZflLKIcZsWvfklsaQTM3ZUbmtH0rJ1hKyV3raoUYyeZwcjQ8ZUJTzS7KnhNcsVT1Rxs7zeeMHEhGlltw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "@typescript-eslint/scope-manager": "5.30.0", + "@typescript-eslint/types": "5.30.0", + "@typescript-eslint/typescript-estree": "5.30.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.30.0.tgz", + "integrity": "sha512-3TZxvlQcK5fhTBw5solQucWSJvonXf5yua5nx8OqK94hxdrT7/6W3/CS42MLd/f1BmlmmbGEgQcTHHCktUX5bQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.30.0", + "@typescript-eslint/visitor-keys": "5.30.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.30.0.tgz", + "integrity": "sha512-vfqcBrsRNWw/LBXyncMF/KrUTYYzzygCSsVqlZ1qGu1QtGs6vMkt3US0VNSQ05grXi5Yadp3qv5XZdYLjpp8ag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.0.tgz", + "integrity": "sha512-hDEawogreZB4n1zoqcrrtg/wPyyiCxmhPLpZ6kmWfKF5M5G0clRLaEexpuWr31fZ42F96SlD/5xCt1bT5Qm4Nw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.30.0", + "@typescript-eslint/visitor-keys": "5.30.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.0.tgz", + "integrity": "sha512-6WcIeRk2DQ3pHKxU1Ni0qMXJkjO/zLjBymlYBy/53qxe7yjEFSvzKLDToJjURUhSl2Fzhkl4SMXQoETauF74cw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.30.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/utils/node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.23.0.tgz", + "integrity": "sha512-Vd4mFNchU62sJB8pX19ZSPog05B0Y0CE2UxAZPT5k4iqhRYjPnqyY3woMxCd0++t9OTqkgjST+1ydLBi7e2Fvg==", + "dev": true, + "peer": true, + "dependencies": { + "@typescript-eslint/types": "5.23.0", + "eslint-visitor-keys": "^3.0.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -248,6 +889,43 @@ "node": ">= 0.6" } }, + "node_modules/acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "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" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/ansi-align": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", @@ -682,6 +1360,15 @@ "node": ">=0.10.0" } }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/array-unique": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", @@ -776,20 +1463,34 @@ } }, "node_modules/body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", + "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", "dependencies": { "bytes": "3.1.2", "content-type": "~1.0.4", "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.8.1", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.9.7", - "raw-body": "2.4.3", - "type-is": "~1.6.18" + "on-finished": "2.4.1", + "qs": "6.10.3", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" }, "engines": { "node": ">= 0.8" @@ -821,6 +1522,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -920,6 +1622,27 @@ "node": ">=8" } }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/camelcase": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", @@ -1134,11 +1857,11 @@ } }, "node_modules/cli-progress": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.10.0.tgz", - "integrity": "sha512-kLORQrhYCAtUPLZxqsAt2YJGOvRdt34+O6jl5cQGb7iF3dM55FQZlTR+rQyIK9JUcO9bBMwZsTlND+3dmFU2Cw==", + "version": "3.11.2", + "resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.11.2.tgz", + "integrity": "sha512-lCPoS6ncgX4+rJu5bS3F/iCz17kZ9MPZ6dpuTtI0KXKABkhyXIdYB3Inby1OpaGti3YlI3EeEkM9AuWpelJrVA==", "dependencies": { - "string-width": "^4.2.0" + "string-width": "^4.2.3" }, "engines": { "node": ">=4" @@ -1253,7 +1976,8 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true }, "node_modules/concat-with-sourcemaps": { "version": "1.1.0", @@ -1264,19 +1988,20 @@ } }, "node_modules/concurrently": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-7.0.0.tgz", - "integrity": "sha512-WKM7PUsI8wyXpF80H+zjHP32fsgsHNQfPLw/e70Z5dYkV7hF+rf8q3D+ScWJIEr57CpkO3OWBko6hwhQLPR8Pw==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-7.2.2.tgz", + "integrity": "sha512-DcQkI0ruil5BA/g7Xy3EWySGrFJovF5RYAYxwGvv9Jf9q9B1v3jPFP2tl6axExNf1qgF30kjoNYrangZ0ey4Aw==", "dev": true, "dependencies": { "chalk": "^4.1.0", "date-fns": "^2.16.1", "lodash": "^4.17.21", - "rxjs": "^6.6.3", + "rxjs": "^7.0.0", + "shell-quote": "^1.7.3", "spawn-command": "^0.0.2-1", "supports-color": "^8.1.0", "tree-kill": "^1.2.2", - "yargs": "^16.2.0" + "yargs": "^17.3.1" }, "bin": { "concurrently": "dist/bin/concurrently.js" @@ -1322,9 +2047,9 @@ } }, "node_modules/cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", "engines": { "node": ">= 0.6" } @@ -1437,6 +2162,20 @@ "node": ">=0.10.0" } }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/crypto-random-string": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", @@ -1512,6 +2251,12 @@ "node": ">=4.0.0" } }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, "node_modules/default-compare": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz", @@ -1566,17 +2311,45 @@ } }, "node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } }, "node_modules/dot-prop": { "version": "5.3.0", @@ -1591,9 +2364,9 @@ } }, "node_modules/dotenv": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.0.tgz", - "integrity": "sha512-qD9WU0MPM4SWLPJy/r2Be+2WgQj8plChsyrCNQzW/0WjvcJQiKQJ9mH3ZgB3fxbUUxgc/11ZJ0Fi5KiimWGz2Q==", + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz", + "integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==", "engines": { "node": ">=12" } @@ -1672,6 +2445,222 @@ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.18.0.tgz", + "integrity": "sha512-As1EfFMVk7Xc6/CvhssHUjsAQSkpfXvUGMFC3ce8JDe6WvqCgRrLOBQbVpsBFr1X1V+RACOadnzVvcUS5ni2bA==", + "dev": true, + "dependencies": { + "@eslint/eslintrc": "^1.3.0", + "@humanwhocodes/config-array": "^0.9.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.2", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "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.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/eslint/node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz", + "integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==", + "dev": true, + "dependencies": { + "acorn": "^8.7.1", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -1774,37 +2763,38 @@ } }, "node_modules/express": { - "version": "4.17.3", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz", - "integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz", + "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.19.2", + "body-parser": "1.20.0", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.4.2", + "cookie": "0.5.0", "cookie-signature": "1.0.6", "debug": "2.6.9", - "depd": "~1.1.2", + "depd": "2.0.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "~1.1.2", + "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.3.0", + "on-finished": "2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", "proxy-addr": "~2.0.7", - "qs": "6.9.7", + "qs": "6.10.3", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.17.2", - "serve-static": "1.14.2", + "send": "0.18.0", + "serve-static": "1.15.0", "setprototypeof": "1.2.0", - "statuses": "~1.5.0", + "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" @@ -1814,16 +2804,27 @@ } }, "node_modules/express-handlebars": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/express-handlebars/-/express-handlebars-6.0.2.tgz", - "integrity": "sha512-PXNT4oDHIDbg0/QBXPwf2laTi+eqErEJ3Ldc7Ky6WHpr7xJMoltsnPM7lScjN6sWZWaIPNdDYJvV+6P9cnv1pg==", + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/express-handlebars/-/express-handlebars-6.0.6.tgz", + "integrity": "sha512-E4QHYCh+9fyfdBEb8uKJ8p6HD4qq/sUSHBq83lRNlLJp2TQKEg2nFJYbVdC+M3QzaV19dODe43lgjQWVaIpbyQ==", "dependencies": { - "glob": "^7.2.0", - "graceful-fs": "^4.2.8", + "glob": "^8.0.2", + "graceful-fs": "^4.2.10", "handlebars": "^4.7.7" }, "engines": { - "node": ">=v12.22.7" + "node": ">=v12.22.9" + } + }, + "node_modules/express/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" } }, "node_modules/extend-shallow": { @@ -1874,11 +2875,124 @@ "node": ">=0.10.0" } }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "dev": true, + "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" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fast-glob/node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fast-glob/node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/fast-glob/node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/fast-glob/node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "node_modules/fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, "node_modules/fecha": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.1.tgz", "integrity": "sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q==" }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, "node_modules/fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", @@ -1894,22 +3008,52 @@ } }, "node_modules/finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", "dependencies": { "debug": "2.6.9", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "parseurl": "~1.3.3", - "statuses": "~1.5.0", + "statuses": "2.0.1", "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.8" } }, + "node_modules/finalhandler/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", + "dev": true + }, "node_modules/fn.name": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", @@ -2002,6 +3146,17 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, "node_modules/generate-function": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", @@ -2019,6 +3174,19 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/get-object": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/get-object/-/get-object-0.2.0.tgz", @@ -2082,19 +3250,18 @@ } }, "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "minimatch": "^5.0.1", + "once": "^1.3.0" }, "engines": { - "node": "*" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -2112,22 +3279,23 @@ "node": ">= 6" } }, - "node_modules/glob-promise": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/glob-promise/-/glob-promise-4.2.2.tgz", - "integrity": "sha512-xcUzJ8NWN5bktoTIX7eOclO1Npxd/dyVqUJxlLIDasT4C7KZyqlPIwkdJ0Ypiy3p2ZKahTjK4M9uC3sNSfNMzw==", + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dependencies": { - "@types/glob": "^7.1.3" + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dependencies": { + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=12" - }, - "funding": { - "type": "individual", - "url": "https://github.com/sponsors/ahmadnassri" - }, - "peerDependencies": { - "glob": "^7.1.6" + "node": ">=10" } }, "node_modules/global-dirs": { @@ -2145,6 +3313,41 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/globals": { + "version": "13.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz", + "integrity": "sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "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" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/got": { "version": "9.6.0", "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", @@ -2168,9 +3371,9 @@ } }, "node_modules/graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" }, "node_modules/gulp-header": { "version": "1.8.12", @@ -2256,7 +3459,7 @@ "node_modules/handlebars-helpers/node_modules/is-glob": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", "dependencies": { "is-extglob": "^2.1.0" }, @@ -2284,6 +3487,17 @@ "node": ">=0.10.0" } }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -2293,6 +3507,17 @@ "node": ">=8" } }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", @@ -2354,7 +3579,7 @@ "node_modules/helper-markdown": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/helper-markdown/-/helper-markdown-0.2.2.tgz", - "integrity": "sha1-ONt/dxhJ4wrpXJL8AhuutT8uMEA=", + "integrity": "sha512-VLbwB3RMq3fJ3H1IcYRa18gd300WS/1rNJVmjc61fuBEK46RcqeqN1vOLRm1ZabBE/o3EdCrUFjKkekB/pBJyQ==", "dependencies": { "isobject": "^2.0.0", "mixin-deep": "^1.1.3", @@ -2367,7 +3592,7 @@ "node_modules/helper-markdown/node_modules/isobject": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", "dependencies": { "isarray": "1.0.0" }, @@ -2390,14 +3615,14 @@ } }, "node_modules/html-entities": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.2.tgz", - "integrity": "sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ==" + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", + "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==" }, "node_modules/html-tag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/html-tag/-/html-tag-1.0.0.tgz", - "integrity": "sha1-leVhKuyCvqko7URZX4VBRen34LU=", + "integrity": "sha512-SXjQ8wG7dh1fIxT/lhj+nKcc2R0rEmMGjvw2Bh46IkijhEaVdEteqYGBFZiICXkUra3PHLy+4zoXwDhh0l55SQ==", "dependencies": { "isobject": "^3.0.0", "void-elements": "^2.0.1" @@ -2413,18 +3638,18 @@ "dev": true }, "node_modules/http-errors": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", - "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "dependencies": { - "depd": "~1.1.2", + "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", - "statuses": ">= 1.5.0 < 2", + "statuses": "2.0.1", "toidentifier": "1.0.1" }, "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/iconv-lite": { @@ -2438,12 +3663,37 @@ "node": ">=0.10.0" } }, + "node_modules/ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, "node_modules/ignore-by-default": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", "dev": true }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/import-lazy": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", @@ -2748,6 +3998,12 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, "node_modules/isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", @@ -2756,12 +4012,42 @@ "node": ">=0.10.0" } }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/js-yaml/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "node_modules/json-buffer": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", "dev": true }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, "node_modules/keyv": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", @@ -2807,6 +4093,19 @@ "node": ">=0.10.0" } }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -2818,6 +4117,12 @@ "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=" }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, "node_modules/lodash.template": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", @@ -2974,6 +4279,15 @@ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -3080,9 +4394,10 @@ } }, "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -3091,9 +4406,9 @@ } }, "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, "node_modules/mixin-deep": { "version": "1.3.2", @@ -3130,9 +4445,9 @@ } }, "node_modules/moment": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", - "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==", + "version": "2.29.2", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.2.tgz", + "integrity": "sha512-UgzG4rvxYpN15jgCmVJwac49h9ly9NurikMWGPdVxm8GZD6XjkKPxDTjQQ43gtGgnV3X0cAyWDdP2Wexoquifg==", "engines": { "node": "*" } @@ -3152,14 +4467,6 @@ "node": ">= 0.8.0" } }, - "node_modules/morgan/node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -3275,6 +4582,12 @@ "node": ">=0.10.0" } }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -3308,9 +4621,9 @@ } }, "node_modules/nodemon": { - "version": "2.0.15", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.15.tgz", - "integrity": "sha512-gdHMNx47Gw7b3kWxJV64NI+Q5nfl0y5DgDbiVtShiwa7Z0IZ07Ll4RLFo6AjrhzMtoEZn5PDE3/c2AbVsiCkpA==", + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.18.tgz", + "integrity": "sha512-uAvrKipi2zAz8E7nkSz4qW4F4zd5fs2wNGsTx+xXlP8KXqd9ucE0vY9wankOsPboeDyuUGN9vsXGV1pLn80l/A==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -3483,6 +4796,14 @@ "node": ">=0.10.0" } }, + "node_modules/object-inspect": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", + "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/object-visit": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", @@ -3540,6 +4861,23 @@ "fn.name": "1.x.x" } }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "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.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/p-cancelable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", @@ -3578,6 +4916,18 @@ "resolved": "https://registry.npmjs.org/pako/-/pako-2.0.4.tgz", "integrity": "sha512-v8tweI900AUkZN6heMU/4Uy4cXRc2AYNRggVmTR+dEncawDJgCdLMximOVA2p4qO57WMynangsfGRb5WD6L1Bg==" }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/parse-ms": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-2.1.0.tgz", @@ -3606,19 +4956,38 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, "engines": { "node": ">=0.10.0" } }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "engines": { "node": ">=8.6" @@ -3635,6 +5004,15 @@ "node": ">=0.10.0" } }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/prepend-http": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", @@ -3644,6 +5022,21 @@ "node": ">=4" } }, + "node_modules/prettier": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/pretty-ms": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-7.0.1.tgz", @@ -3696,6 +5089,15 @@ "once": "^1.3.1" } }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/pupa": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", @@ -3709,9 +5111,12 @@ } }, "node_modules/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==", + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "dependencies": { + "side-channel": "^1.0.4" + }, "engines": { "node": ">=0.6" }, @@ -3719,6 +5124,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -3728,12 +5153,12 @@ } }, "node_modules/raw-body": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz", - "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", "dependencies": { "bytes": "3.1.2", - "http-errors": "1.8.1", + "http-errors": "2.0.0", "iconv-lite": "0.4.24", "unpipe": "1.0.0" }, @@ -3828,6 +5253,18 @@ "node": ">=0.10.0" } }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, "node_modules/registry-auth-token": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", @@ -3908,12 +5345,21 @@ "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, "engines": { "node": ">=0.10.0" } }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", @@ -3937,6 +5383,16 @@ "node": ">=0.12" } }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -3952,18 +5408,64 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.2.tgz", + "integrity": "sha512-NzDgHDiJwKYByLrL5lONmQFpK/2G78SMMfo+E9CuGlX4IkvfKDsiQSNPwAYxEy+e6p7ZQ3uslSLlwlJcqezBmQ==", "dev": true, "dependencies": { - "tslib": "^1.9.0" + "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" }, "engines": { - "npm": ">=2.0.0" + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz", + "integrity": "sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/rxjs/node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "dev": true + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -4035,23 +5537,23 @@ } }, "node_modules/send": { - "version": "0.17.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", - "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", "dependencies": { "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", + "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": "1.8.1", + "http-errors": "2.0.0", "mime": "1.6.0", "ms": "2.1.3", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "range-parser": "~1.2.1", - "statuses": "~1.5.0" + "statuses": "2.0.1" }, "engines": { "node": ">= 0.8.0" @@ -4062,20 +5564,31 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, + "node_modules/send/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/seq-queue": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", "integrity": "sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4=" }, "node_modules/serve-static": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", - "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", "dependencies": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.17.2" + "send": "0.18.0" }, "engines": { "node": ">= 0.8.0" @@ -4111,6 +5624,46 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz", + "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==", + "dev": true + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/signal-exit": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz", @@ -4125,6 +5678,15 @@ "is-arrayish": "^0.3.1" } }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -4448,11 +6010,11 @@ } }, "node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/string_decoder": { @@ -4534,6 +6096,12 @@ "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, "node_modules/through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", @@ -4696,6 +6264,33 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -4752,9 +6347,9 @@ } }, "node_modules/typescript": { - "version": "4.5.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", - "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==", + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -4903,6 +6498,15 @@ "node": ">=10" } }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, "node_modules/urix": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", @@ -4950,6 +6554,12 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -4961,7 +6571,7 @@ "node_modules/void-elements": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", - "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", + "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==", "engines": { "node": ">=0.10.0" } @@ -4988,6 +6598,21 @@ "webidl-conversions": "^3.0.0" } }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/widest-line": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", @@ -5001,9 +6626,9 @@ } }, "node_modules/winston": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.6.0.tgz", - "integrity": "sha512-9j8T75p+bcN6D00sF/zjFVmPp+t8KMPB1MzbbzYjeN9VWxdsYnTB40TkbNUEXAmILEfChMvAMgidlX64OG3p6w==", + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.8.0.tgz", + "integrity": "sha512-Iix1w8rIq2kBDkGvclO0db2CVOHYVamCIkVWcUbs567G9i2pdB+gvqLgDgxx4B4HXHYD6U4Zybh6ojepUOqcFQ==", "dependencies": { "@dabh/diagnostics": "^2.0.2", "async": "^3.2.3", @@ -5059,6 +6684,15 @@ "node": ">= 6" } }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", @@ -5130,30 +6764,30 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", "dev": true, "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "string-width": "^4.2.0", + "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "yargs-parser": "^21.0.0" }, "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", + "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==", "dev": true, "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/year": { @@ -5181,6 +6815,106 @@ "kuler": "^2.0.0" } }, + "@eslint/eslintrc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", + "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.3.2", + "globals": "^13.15.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" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + } + } + }, + "@humanwhocodes/config-array": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, "@sindresorhus/is": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", @@ -5188,9 +6922,9 @@ "dev": true }, "@supercharge/promise-pool": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@supercharge/promise-pool/-/promise-pool-2.1.0.tgz", - "integrity": "sha512-YEKOfn4xF+DQ61UY5NwHNtr8hYjwchXjGTocVJDAHLQceIRZF8VECH7gumFbp+aGTfygPbMbEtBumXJ/mcJz+w==" + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@supercharge/promise-pool/-/promise-pool-2.3.0.tgz", + "integrity": "sha512-KLf3JBWW4JymplvT/c5JCZhc4KrNE9EBf15FPjvklQiGcoUczSLInpV23iV5dITnvktJlwQ5xq08wfNwBk71Rg==" }, "@szmarczak/http-timer": { "version": "1.1.2", @@ -5212,9 +6946,9 @@ } }, "@types/cli-progress": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/@types/cli-progress/-/cli-progress-3.9.2.tgz", - "integrity": "sha512-VO5/X5Ij+oVgEVjg5u0IXVe3JQSKJX+Ev8C5x+0hPy0AuWyW+bF8tbajR7cPFnDGhs7pidztcac+ccrDtk5teA==", + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/@types/cli-progress/-/cli-progress-3.11.0.tgz", + "integrity": "sha512-XhXhBv1R/q2ahF3BM7qT5HLzJNlIL0wbcGyZVjqOTqAybAnsLisd7gy1UCyIqpL+5Iv6XhlSyzjLCnI2sIdbCg==", "dev": true, "requires": { "@types/node": "*" @@ -5256,11 +6990,18 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "dev": true, "requires": { "@types/minimatch": "*", "@types/node": "*" } }, + "@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, "@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", @@ -5270,7 +7011,8 @@ "@types/minimatch": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==" + "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", + "dev": true }, "@types/mkdirp": { "version": "1.0.2", @@ -5291,14 +7033,15 @@ } }, "@types/node": { - "version": "17.0.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz", - "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==" + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.0.tgz", + "integrity": "sha512-cHlGmko4gWLVI27cGJntjs/Sj8th9aYwplmZFwmmgYQQvL5NUsgVJG7OddLvNfLqYS31KFN0s3qlaD9qCaxACA==", + "dev": true }, "@types/node-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-oMqjURCaxoSIsHSr1E47QHzbmzNR5rK8McHuNb11BOM9cHcIK3Avy0s/b2JlXHoQGTYS3NsvWzV1M0iK7l0wbA==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz", + "integrity": "sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==", "dev": true, "requires": { "@types/node": "*", @@ -5306,9 +7049,9 @@ } }, "@types/pako": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@types/pako/-/pako-1.0.3.tgz", - "integrity": "sha512-EDxOsHAD5dqjbjEUM1xwa7rpKPFb8ECBE5irONTQU7/OsO3thI5YrNEWSPNMvYmvFM0l/OLQJ6Mgw7PEdXSjhg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/pako/-/pako-2.0.0.tgz", + "integrity": "sha512-10+iaz93qR5WYxTo+PMifD5TSxiOtdRaxBf7INGGXMQgTCu8Z/7GYWYFUOS3q/G0nE5boj1r4FEB+WSy7s5gbA==", "dev": true }, "@types/qs": { @@ -5339,6 +7082,306 @@ "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", "dev": true }, + "@typescript-eslint/eslint-plugin": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.0.tgz", + "integrity": "sha512-lvhRJ2pGe2V9MEU46ELTdiHgiAFZPKtLhiU5wlnaYpMc2+c1R8fh8i80ZAa665drvjHKUJyRRGg3gEm1If54ow==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.30.0", + "@typescript-eslint/type-utils": "5.30.0", + "@typescript-eslint/utils": "5.30.0", + "debug": "^4.3.4", + "functional-red-black-tree": "^1.0.1", + "ignore": "^5.2.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "dependencies": { + "@typescript-eslint/scope-manager": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.30.0.tgz", + "integrity": "sha512-3TZxvlQcK5fhTBw5solQucWSJvonXf5yua5nx8OqK94hxdrT7/6W3/CS42MLd/f1BmlmmbGEgQcTHHCktUX5bQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.30.0", + "@typescript-eslint/visitor-keys": "5.30.0" + } + }, + "@typescript-eslint/types": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.30.0.tgz", + "integrity": "sha512-vfqcBrsRNWw/LBXyncMF/KrUTYYzzygCSsVqlZ1qGu1QtGs6vMkt3US0VNSQ05grXi5Yadp3qv5XZdYLjpp8ag==", + "dev": true + }, + "@typescript-eslint/visitor-keys": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.0.tgz", + "integrity": "sha512-6WcIeRk2DQ3pHKxU1Ni0qMXJkjO/zLjBymlYBy/53qxe7yjEFSvzKLDToJjURUhSl2Fzhkl4SMXQoETauF74cw==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.30.0", + "eslint-visitor-keys": "^3.3.0" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@typescript-eslint/parser": { + "version": "5.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.23.0.tgz", + "integrity": "sha512-V06cYUkqcGqpFjb8ttVgzNF53tgbB/KoQT/iB++DOIExKmzI9vBJKjZKt/6FuV9c+zrDsvJKbJ2DOCYwX91cbw==", + "dev": true, + "peer": true, + "requires": { + "@typescript-eslint/scope-manager": "5.23.0", + "@typescript-eslint/types": "5.23.0", + "@typescript-eslint/typescript-estree": "5.23.0", + "debug": "^4.3.2" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "peer": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "peer": true + } + } + }, + "@typescript-eslint/scope-manager": { + "version": "5.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.23.0.tgz", + "integrity": "sha512-EhjaFELQHCRb5wTwlGsNMvzK9b8Oco4aYNleeDlNuL6qXWDF47ch4EhVNPh8Rdhf9tmqbN4sWDk/8g+Z/J8JVw==", + "dev": true, + "peer": true, + "requires": { + "@typescript-eslint/types": "5.23.0", + "@typescript-eslint/visitor-keys": "5.23.0" + } + }, + "@typescript-eslint/type-utils": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.30.0.tgz", + "integrity": "sha512-GF8JZbZqSS+azehzlv/lmQQ3EU3VfWYzCczdZjJRxSEeXDQkqFhCBgFhallLDbPwQOEQ4MHpiPfkjKk7zlmeNg==", + "dev": true, + "requires": { + "@typescript-eslint/utils": "5.30.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@typescript-eslint/types": { + "version": "5.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.23.0.tgz", + "integrity": "sha512-NfBsV/h4dir/8mJwdZz7JFibaKC3E/QdeMEDJhiAE3/eMkoniZ7MjbEMCGXw6MZnZDMN3G9S0mH/6WUIj91dmw==", + "dev": true, + "peer": true + }, + "@typescript-eslint/typescript-estree": { + "version": "5.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.23.0.tgz", + "integrity": "sha512-xE9e0lrHhI647SlGMl+m+3E3CKPF1wzvvOEWnuE3CCjjT7UiRnDGJxmAcVKJIlFgK6DY9RB98eLr1OPigPEOGg==", + "dev": true, + "peer": true, + "requires": { + "@typescript-eslint/types": "5.23.0", + "@typescript-eslint/visitor-keys": "5.23.0", + "debug": "^4.3.2", + "globby": "^11.0.4", + "is-glob": "^4.0.3", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "peer": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "peer": true + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "peer": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@typescript-eslint/utils": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.30.0.tgz", + "integrity": "sha512-0bIgOgZflLKIcZsWvfklsaQTM3ZUbmtH0rJ1hKyV3raoUYyeZwcjQ8ZUJTzS7KnhNcsVT1Rxs7zeeMHEhGlltw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "@typescript-eslint/scope-manager": "5.30.0", + "@typescript-eslint/types": "5.30.0", + "@typescript-eslint/typescript-estree": "5.30.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "dependencies": { + "@typescript-eslint/scope-manager": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.30.0.tgz", + "integrity": "sha512-3TZxvlQcK5fhTBw5solQucWSJvonXf5yua5nx8OqK94hxdrT7/6W3/CS42MLd/f1BmlmmbGEgQcTHHCktUX5bQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.30.0", + "@typescript-eslint/visitor-keys": "5.30.0" + } + }, + "@typescript-eslint/types": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.30.0.tgz", + "integrity": "sha512-vfqcBrsRNWw/LBXyncMF/KrUTYYzzygCSsVqlZ1qGu1QtGs6vMkt3US0VNSQ05grXi5Yadp3qv5XZdYLjpp8ag==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.0.tgz", + "integrity": "sha512-hDEawogreZB4n1zoqcrrtg/wPyyiCxmhPLpZ6kmWfKF5M5G0clRLaEexpuWr31fZ42F96SlD/5xCt1bT5Qm4Nw==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.30.0", + "@typescript-eslint/visitor-keys": "5.30.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.0.tgz", + "integrity": "sha512-6WcIeRk2DQ3pHKxU1Ni0qMXJkjO/zLjBymlYBy/53qxe7yjEFSvzKLDToJjURUhSl2Fzhkl4SMXQoETauF74cw==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.30.0", + "eslint-visitor-keys": "^3.3.0" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.23.0.tgz", + "integrity": "sha512-Vd4mFNchU62sJB8pX19ZSPog05B0Y0CE2UxAZPT5k4iqhRYjPnqyY3woMxCd0++t9OTqkgjST+1ydLBi7e2Fvg==", + "dev": true, + "peer": true, + "requires": { + "@typescript-eslint/types": "5.23.0", + "eslint-visitor-keys": "^3.0.0" + } + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -5354,6 +7397,31 @@ "negotiator": "0.6.3" } }, + "acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "requires": {} + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, "ansi-align": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", @@ -5679,6 +7747,12 @@ } } }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, "array-unique": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", @@ -5754,20 +7828,32 @@ "dev": true }, "body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", + "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", "requires": { "bytes": "3.1.2", "content-type": "~1.0.4", "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.8.1", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.9.7", - "raw-body": "2.4.3", - "type-is": "~1.6.18" + "on-finished": "2.4.1", + "qs": "6.10.3", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "dependencies": { + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } + } } }, "boxen": { @@ -5790,6 +7876,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5870,6 +7957,21 @@ } } }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, "camelcase": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", @@ -6032,11 +8134,11 @@ "dev": true }, "cli-progress": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.10.0.tgz", - "integrity": "sha512-kLORQrhYCAtUPLZxqsAt2YJGOvRdt34+O6jl5cQGb7iF3dM55FQZlTR+rQyIK9JUcO9bBMwZsTlND+3dmFU2Cw==", + "version": "3.11.2", + "resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.11.2.tgz", + "integrity": "sha512-lCPoS6ncgX4+rJu5bS3F/iCz17kZ9MPZ6dpuTtI0KXKABkhyXIdYB3Inby1OpaGti3YlI3EeEkM9AuWpelJrVA==", "requires": { - "string-width": "^4.2.0" + "string-width": "^4.2.3" } }, "cliui": { @@ -6141,7 +8243,8 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true }, "concat-with-sourcemaps": { "version": "1.1.0", @@ -6152,19 +8255,20 @@ } }, "concurrently": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-7.0.0.tgz", - "integrity": "sha512-WKM7PUsI8wyXpF80H+zjHP32fsgsHNQfPLw/e70Z5dYkV7hF+rf8q3D+ScWJIEr57CpkO3OWBko6hwhQLPR8Pw==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-7.2.2.tgz", + "integrity": "sha512-DcQkI0ruil5BA/g7Xy3EWySGrFJovF5RYAYxwGvv9Jf9q9B1v3jPFP2tl6axExNf1qgF30kjoNYrangZ0ey4Aw==", "dev": true, "requires": { "chalk": "^4.1.0", "date-fns": "^2.16.1", "lodash": "^4.17.21", - "rxjs": "^6.6.3", + "rxjs": "^7.0.0", + "shell-quote": "^1.7.3", "spawn-command": "^0.0.2-1", "supports-color": "^8.1.0", "tree-kill": "^1.2.2", - "yargs": "^16.2.0" + "yargs": "^17.3.1" } }, "configstore": { @@ -6195,9 +8299,9 @@ "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" }, "cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==" + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" }, "cookie-signature": { "version": "1.0.6", @@ -6286,6 +8390,17 @@ } } }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, "crypto-random-string": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", @@ -6344,6 +8459,12 @@ "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "dev": true }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, "default-compare": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz", @@ -6385,14 +8506,32 @@ "integrity": "sha512-tfiWc6BQLXNLpNiR5iGd0Ocu3P3VpxfzFiqubLgMfhfOw9WyvgJBd46CClNn9k3qfbjvT//0cf7AlYRX/OslMQ==" }, "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" }, "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } }, "dot-prop": { "version": "5.3.0", @@ -6404,9 +8543,9 @@ } }, "dotenv": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.0.tgz", - "integrity": "sha512-qD9WU0MPM4SWLPJy/r2Be+2WgQj8plChsyrCNQzW/0WjvcJQiKQJ9mH3ZgB3fxbUUxgc/11ZJ0Fi5KiimWGz2Q==" + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz", + "integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==" }, "duplexer3": { "version": "0.1.4", @@ -6470,6 +8609,161 @@ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "eslint": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.18.0.tgz", + "integrity": "sha512-As1EfFMVk7Xc6/CvhssHUjsAQSkpfXvUGMFC3ce8JDe6WvqCgRrLOBQbVpsBFr1X1V+RACOadnzVvcUS5ni2bA==", + "dev": true, + "requires": { + "@eslint/eslintrc": "^1.3.0", + "@humanwhocodes/config-array": "^0.9.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.2", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "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.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + } + } + }, + "eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true + }, + "espree": { + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz", + "integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==", + "dev": true, + "requires": { + "acorn": "^8.7.1", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + } + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -6551,49 +8845,60 @@ } }, "express": { - "version": "4.17.3", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz", - "integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz", + "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==", "requires": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.19.2", + "body-parser": "1.20.0", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.4.2", + "cookie": "0.5.0", "cookie-signature": "1.0.6", "debug": "2.6.9", - "depd": "~1.1.2", + "depd": "2.0.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "~1.1.2", + "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.3.0", + "on-finished": "2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", "proxy-addr": "~2.0.7", - "qs": "6.9.7", + "qs": "6.10.3", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.17.2", - "serve-static": "1.14.2", + "send": "0.18.0", + "serve-static": "1.15.0", "setprototypeof": "1.2.0", - "statuses": "~1.5.0", + "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" + }, + "dependencies": { + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } + } } }, "express-handlebars": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/express-handlebars/-/express-handlebars-6.0.2.tgz", - "integrity": "sha512-PXNT4oDHIDbg0/QBXPwf2laTi+eqErEJ3Ldc7Ky6WHpr7xJMoltsnPM7lScjN6sWZWaIPNdDYJvV+6P9cnv1pg==", + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/express-handlebars/-/express-handlebars-6.0.6.tgz", + "integrity": "sha512-E4QHYCh+9fyfdBEb8uKJ8p6HD4qq/sUSHBq83lRNlLJp2TQKEg2nFJYbVdC+M3QzaV19dODe43lgjQWVaIpbyQ==", "requires": { - "glob": "^7.2.0", - "graceful-fs": "^4.2.8", + "glob": "^8.0.2", + "graceful-fs": "^4.2.10", "handlebars": "^4.7.7" } }, @@ -6635,11 +8940,105 @@ } } }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "dev": true, + "requires": { + "@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" + }, + "dependencies": { + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + } + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, "fecha": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.1.tgz", "integrity": "sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q==" }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, "fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", @@ -6652,19 +9051,45 @@ } }, "finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", "requires": { "debug": "2.6.9", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "parseurl": "~1.3.3", - "statuses": "~1.5.0", + "statuses": "2.0.1", "unpipe": "~1.0.0" + }, + "dependencies": { + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } + } } }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", + "dev": true + }, "fn.name": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", @@ -6729,6 +9154,17 @@ "dev": true, "optional": true }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, "generate-function": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", @@ -6743,6 +9179,16 @@ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, + "get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, "get-object": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/get-object/-/get-object-0.2.0.tgz", @@ -6790,16 +9236,33 @@ "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" }, "glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "requires": { + "brace-expansion": "^2.0.1" + } + } } }, "glob-parent": { @@ -6811,14 +9274,6 @@ "is-glob": "^4.0.1" } }, - "glob-promise": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/glob-promise/-/glob-promise-4.2.2.tgz", - "integrity": "sha512-xcUzJ8NWN5bktoTIX7eOclO1Npxd/dyVqUJxlLIDasT4C7KZyqlPIwkdJ0Ypiy3p2ZKahTjK4M9uC3sNSfNMzw==", - "requires": { - "@types/glob": "^7.1.3" - } - }, "global-dirs": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", @@ -6828,6 +9283,29 @@ "ini": "2.0.0" } }, + "globals": { + "version": "13.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz", + "integrity": "sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "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" + } + }, "got": { "version": "9.6.0", "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", @@ -6848,9 +9326,9 @@ } }, "graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" }, "gulp-header": { "version": "1.8.12", @@ -6921,7 +9399,7 @@ "is-glob": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", "requires": { "is-extglob": "^2.1.0" } @@ -6942,12 +9420,25 @@ "typeof-article": "^0.1.1" } }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, "has-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", @@ -6996,7 +9487,7 @@ "helper-markdown": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/helper-markdown/-/helper-markdown-0.2.2.tgz", - "integrity": "sha1-ONt/dxhJ4wrpXJL8AhuutT8uMEA=", + "integrity": "sha512-VLbwB3RMq3fJ3H1IcYRa18gd300WS/1rNJVmjc61fuBEK46RcqeqN1vOLRm1ZabBE/o3EdCrUFjKkekB/pBJyQ==", "requires": { "isobject": "^2.0.0", "mixin-deep": "^1.1.3", @@ -7006,7 +9497,7 @@ "isobject": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", "requires": { "isarray": "1.0.0" } @@ -7025,14 +9516,14 @@ } }, "html-entities": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.2.tgz", - "integrity": "sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ==" + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", + "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==" }, "html-tag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/html-tag/-/html-tag-1.0.0.tgz", - "integrity": "sha1-leVhKuyCvqko7URZX4VBRen34LU=", + "integrity": "sha512-SXjQ8wG7dh1fIxT/lhj+nKcc2R0rEmMGjvw2Bh46IkijhEaVdEteqYGBFZiICXkUra3PHLy+4zoXwDhh0l55SQ==", "requires": { "isobject": "^3.0.0", "void-elements": "^2.0.1" @@ -7045,14 +9536,14 @@ "dev": true }, "http-errors": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", - "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "requires": { - "depd": "~1.1.2", + "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", - "statuses": ">= 1.5.0 < 2", + "statuses": "2.0.1", "toidentifier": "1.0.1" } }, @@ -7064,12 +9555,28 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true + }, "ignore-by-default": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", "dev": true }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, "import-lazy": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", @@ -7292,17 +9799,52 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + } + } + }, "json-buffer": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", "dev": true }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, "keyv": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", @@ -7339,6 +9881,16 @@ "set-getter": "^0.1.0" } }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -7350,6 +9902,12 @@ "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=" }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, "lodash.template": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", @@ -7477,6 +10035,12 @@ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -7555,17 +10119,18 @@ "dev": true }, "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, "mixin-deep": { "version": "1.3.2", @@ -7592,9 +10157,9 @@ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" }, "moment": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", - "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==" + "version": "2.29.2", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.2.tgz", + "integrity": "sha512-UgzG4rvxYpN15jgCmVJwac49h9ly9NurikMWGPdVxm8GZD6XjkKPxDTjQQ43gtGgnV3X0cAyWDdP2Wexoquifg==" }, "morgan": { "version": "1.10.0", @@ -7606,13 +10171,6 @@ "depd": "~2.0.0", "on-finished": "~2.3.0", "on-headers": "~1.0.2" - }, - "dependencies": { - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" - } } }, "ms": { @@ -7715,6 +10273,12 @@ } } }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, "negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -7734,9 +10298,9 @@ } }, "nodemon": { - "version": "2.0.15", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.15.tgz", - "integrity": "sha512-gdHMNx47Gw7b3kWxJV64NI+Q5nfl0y5DgDbiVtShiwa7Z0IZ07Ll4RLFo6AjrhzMtoEZn5PDE3/c2AbVsiCkpA==", + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.18.tgz", + "integrity": "sha512-uAvrKipi2zAz8E7nkSz4qW4F4zd5fs2wNGsTx+xXlP8KXqd9ucE0vY9wankOsPboeDyuUGN9vsXGV1pLn80l/A==", "dev": true, "requires": { "chokidar": "^3.5.2", @@ -7865,6 +10429,11 @@ } } }, + "object-inspect": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", + "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==" + }, "object-visit": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", @@ -7910,6 +10479,20 @@ "fn.name": "1.x.x" } }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "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.3" + } + }, "p-cancelable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", @@ -7941,6 +10524,15 @@ "resolved": "https://registry.npmjs.org/pako/-/pako-2.0.4.tgz", "integrity": "sha512-v8tweI900AUkZN6heMU/4Uy4cXRc2AYNRggVmTR+dEncawDJgCdLMximOVA2p4qO57WMynangsfGRb5WD6L1Bg==" }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, "parse-ms": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-2.1.0.tgz", @@ -7959,17 +10551,30 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true }, "path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, "picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true }, "posix-character-classes": { @@ -7977,12 +10582,24 @@ "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, "prepend-http": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", "dev": true }, + "prettier": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", + "dev": true + }, "pretty-ms": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-7.0.1.tgz", @@ -8026,6 +10643,12 @@ "once": "^1.3.1" } }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, "pupa": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", @@ -8036,9 +10659,18 @@ } }, "qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==" + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "requires": { + "side-channel": "^1.0.4" + } + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true }, "range-parser": { "version": "1.2.1", @@ -8046,12 +10678,12 @@ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" }, "raw-body": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz", - "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", "requires": { "bytes": "3.1.2", - "http-errors": "1.8.1", + "http-errors": "2.0.0", "iconv-lite": "0.4.24", "unpipe": "1.0.0" } @@ -8134,6 +10766,12 @@ } } }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, "registry-auth-token": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", @@ -8192,7 +10830,13 @@ "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, "resolve-url": { @@ -8214,6 +10858,12 @@ "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -8221,15 +10871,48 @@ "dev": true, "requires": { "glob": "^7.1.3" + }, + "dependencies": { + "glob": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.2.tgz", + "integrity": "sha512-NzDgHDiJwKYByLrL5lONmQFpK/2G78SMMfo+E9CuGlX4IkvfKDsiQSNPwAYxEy+e6p7ZQ3uslSLlwlJcqezBmQ==", + "dev": true, + "requires": { + "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" + } + } + } + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" } }, "rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz", + "integrity": "sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==", "dev": true, "requires": { - "tslib": "^1.9.0" + "tslib": "^2.1.0" + }, + "dependencies": { + "tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "dev": true + } } }, "safe-buffer": { @@ -8279,29 +10962,37 @@ } }, "send": { - "version": "0.17.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", - "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", "requires": { "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", + "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": "1.8.1", + "http-errors": "2.0.0", "mime": "1.6.0", "ms": "2.1.3", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "range-parser": "~1.2.1", - "statuses": "~1.5.0" + "statuses": "2.0.1" }, "dependencies": { "ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } } } }, @@ -8311,14 +11002,14 @@ "integrity": "sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4=" }, "serve-static": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", - "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", "requires": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.17.2" + "send": "0.18.0" } }, "set-getter": { @@ -8345,6 +11036,37 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "shell-quote": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz", + "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==", + "dev": true + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, "signal-exit": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz", @@ -8359,6 +11081,12 @@ "is-arrayish": "^0.3.1" } }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -8618,9 +11346,9 @@ } }, "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" }, "string_decoder": { "version": "1.1.1", @@ -8685,6 +11413,12 @@ "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, "through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", @@ -8812,6 +11546,24 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, "type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -8855,9 +11607,9 @@ } }, "typescript": { - "version": "4.5.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", - "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==", + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", "dev": true }, "uglify-js": { @@ -8966,6 +11718,15 @@ } } }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, "urix": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", @@ -9000,6 +11761,12 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -9008,7 +11775,7 @@ "void-elements": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", - "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=" + "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==" }, "warning-symbol": { "version": "0.1.0", @@ -9029,6 +11796,15 @@ "webidl-conversions": "^3.0.0" } }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, "widest-line": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", @@ -9039,9 +11815,9 @@ } }, "winston": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.6.0.tgz", - "integrity": "sha512-9j8T75p+bcN6D00sF/zjFVmPp+t8KMPB1MzbbzYjeN9VWxdsYnTB40TkbNUEXAmILEfChMvAMgidlX64OG3p6w==", + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.8.0.tgz", + "integrity": "sha512-Iix1w8rIq2kBDkGvclO0db2CVOHYVamCIkVWcUbs567G9i2pdB+gvqLgDgxx4B4HXHYD6U4Zybh6ojepUOqcFQ==", "requires": { "@dabh/diagnostics": "^2.0.2", "async": "^3.2.3", @@ -9089,6 +11865,12 @@ } } }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", @@ -9145,24 +11927,24 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", "dev": true, "requires": { "cliui": "^7.0.2", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "string-width": "^4.2.0", + "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "yargs-parser": "^21.0.0" } }, "yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", + "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==", "dev": true }, "year": { diff --git a/package.json b/package.json index 7fb7492..bdfb673 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "azerothcore-armory", - "version": "1.0.0", + "version": "1.1.1", "description": "", "scripts": { "build": "tsc -p tsconfig.json", @@ -8,6 +8,8 @@ "start": "node --expose-gc build/armory/main.js", "watch": "concurrently \"tsc -w --project .\" \"npm run nodemon\"", "nodemon": "nodemon -q -w build -w config.json build/armory/main.js", + "lint": "eslint src/", + "prettier": "prettier . -w", "fetchdata": "node build/tools/fetchdata.js", "cleardata": "rimraf data/bone data/meta data/mo3 data/textures" }, @@ -15,31 +17,33 @@ "homepage": "https://github.com/r-o-b-o-t-o/azerothcore-armory", "license": "MIT", "devDependencies": { - "@types/cli-progress": "^3.9.2", + "@types/cli-progress": "^3.11.0", "@types/express": "^4.17.13", "@types/glob": "^7.2.0", "@types/mkdirp": "^1.0.2", "@types/morgan": "^1.9.3", - "@types/node": "^17.0.21", - "@types/node-fetch": "^2.6.1", - "@types/pako": "^1.0.3", + "@types/node": "^18.0.0", + "@types/node-fetch": "^2.6.2", + "@types/pako": "^2.0.0", "@types/uuid": "^8.3.4", - "concurrently": "^7.0.0", - "nodemon": "^2.0.15", + "@typescript-eslint/eslint-plugin": "^5.30.0", + "concurrently": "^7.2.2", + "eslint": "^8.18.0", + "nodemon": "^2.0.18", + "prettier": "^2.7.1", "rimraf": "^3.0.2", - "typescript": "^4.5.5" + "typescript": "^4.7.4" }, "dependencies": { - "@supercharge/promise-pool": "^2.1.0", + "@supercharge/promise-pool": "^2.3.0", "camelcase": "^6.3.0", - "cli-progress": "^3.10.0", - "dotenv": "^16.0.0", - "express": "^4.17.3", - "express-handlebars": "^6.0.2", - "glob": "^7.2.0", - "glob-promise": "^4.2.2", + "cli-progress": "^3.11.2", + "dotenv": "^16.0.1", + "express": "^4.18.1", + "express-handlebars": "^6.0.6", + "glob": "^8.0.3", "handlebars-helpers": "^0.9.8", - "html-entities": "^2.3.2", + "html-entities": "^2.3.3", "mkdirp": "^1.0.4", "morgan": "^1.10.0", "mysql2": "^2.3.3", @@ -48,6 +52,6 @@ "pretty-ms": "^7.0.1", "source-map-support": "^0.5.21", "uuid": "^8.3.2", - "winston": "^3.6.0" + "winston": "^3.8.0" } } diff --git a/src/armory/Armory.ts b/src/armory/Armory.ts index dc94a85..b2c621a 100644 --- a/src/armory/Armory.ts +++ b/src/armory/Armory.ts @@ -13,6 +13,7 @@ import { CharacterCustomization } from "./data/CharacterCustomization"; import { IndexController } from "./controllers/IndexController"; import { CharacterController } from "./controllers/CharacterController"; import { GuildController } from "./controllers/GuildController"; +import { ArenaController } from "./controllers/ArenaController"; export class Armory { public characterCustomization: CharacterCustomization; @@ -85,22 +86,24 @@ export class Armory { websiteRoot: this.config.websiteRoot, iframeMode: this.config.iframeMode, }; - for (const key in locals) { - if (locals.hasOwnProperty(key)) { - app.locals[key] = locals[key]; - } + for (const key of Object.keys(locals)) { + app.locals[key] = locals[key]; } app.locals.locals = locals; - app.engine(".hbs", handlebarsEngine({ - extname: "hbs", - partialsDir: path.join(process.cwd(), "static", "partials"), - layoutsDir: path.join(process.cwd(), "static"), - defaultLayout: "layout.hbs", - helpers: { - ...require("handlebars-helpers")(), - }, - })); + app.engine( + ".hbs", + handlebarsEngine({ + extname: "hbs", + partialsDir: path.join(process.cwd(), "static", "partials"), + layoutsDir: path.join(process.cwd(), "static"), + defaultLayout: "layout.hbs", + helpers: { + // eslint-disable-next-line @typescript-eslint/no-var-requires + ...require("handlebars-helpers")(), + }, + }), + ); app.set("view engine", "handlebars"); app.set("views", path.join(process.cwd(), "static")); @@ -122,20 +125,22 @@ export class Armory { } return req.socket.remoteAddress; }); - app.use(morgan(":method :url :status - ID :id - IP :ip - :response-time ms", { - stream: { - write: (msg) => this.logger.http(msg.trim()), - }, - })); + app.use( + morgan(":method :url :status - ID :id - IP :ip - :response-time ms", { + stream: { + write: (msg) => this.logger.http(msg.trim()), + }, + }), + ); - app.use("/js", express.static(`static/js`)); - app.use("/css", express.static(`static/css`)); - app.use("/img", express.static(`static/img`)); - app.use("/data/mo3", express.static(`data/mo3`)); - app.use("/data/meta", express.static(`data/meta`)); - app.use("/data/bone", express.static(`data/bone`)); - app.use("/data/textures", express.static(`data/textures`)); - app.use("/data/background.png", express.static(`data/modelviewer-background.png`)); + app.use("/js", express.static("static/js")); + app.use("/css", express.static("static/css")); + app.use("/img", express.static("static/img")); + app.use("/data/mo3", express.static("data/mo3")); + app.use("/data/meta", express.static("data/meta")); + app.use("/data/bone", express.static("data/bone")); + app.use("/data/textures", express.static("data/textures")); + app.use("/data/background.png", express.static("data/modelviewer-background.png")); const indexController = new IndexController(this); app.get("/", this.wrapRoute(indexController.index.bind(indexController))); @@ -153,6 +158,11 @@ export class Armory { app.get("/guild/:realm/:name", this.wrapRoute(guildsController.guild.bind(guildsController))); app.get("/guild/:realm/:guild/members", this.wrapRoute(guildsController.members.bind(guildsController))); + const arenaController = new ArenaController(this); + app.get("/arena", this.wrapRoute(arenaController.index.bind(arenaController))); + app.get("/arena/ladder", this.wrapRoute(arenaController.ladder.bind(arenaController))); + app.get("/arena/team/:realm/:name", this.wrapRoute(arenaController.team.bind(arenaController))); + app.use((err, req: express.Request, res: express.Response, next: express.NextFunction) => { // Error handler @@ -198,14 +208,14 @@ export class Armory { } public getRealm(realm: string): IRealmConfig { - return this.config.realms.find(r => r.name.toLowerCase() === realm.toLowerCase()); + return this.config.realms.find((r) => r.name.toLowerCase() === realm.toLowerCase()); } public async getDatabaseCharset(realm: string): Promise { const db = this.getCharactersDb(realm); if (!(realm in this.charsetCache)) { - const [rows, fields] = await db.query({ + const [rows] = await db.query({ sql: ` SELECT CCSA.character_set_name AS charset FROM information_schema.\`TABLES\` T, information_schema.\`COLLATION_CHARACTER_SET_APPLICABILITY\` CCSA @@ -232,7 +242,7 @@ export class Armory { }, 500); } - private wrapRoute(fn: (req: express.Request, res: express.Response, next: express.NextFunction) => Promise) { + private wrapRoute(fn: (req: express.Request, res: express.Response, next: express.NextFunction) => Promise) { // Adds error handling for promise-based controller methods return async (req: express.Request, res: express.Response, next: express.NextFunction) => { try { diff --git a/src/armory/Config.ts b/src/armory/Config.ts index 3a9427f..fc0bc80 100644 --- a/src/armory/Config.ts +++ b/src/armory/Config.ts @@ -31,12 +31,16 @@ export class Config { public iframeMode: IIframeModeConfig; public loadDbcs: boolean; public hideGameMasters: boolean; + public hideBotAccounts: boolean; + public botAccountPatterns: string; + public transmogModule: boolean; + public useZamCdn: boolean; public realms: IRealmConfig[]; public worldDatabase: IDatabaseConfig; public dbQueryTimeout: number; - private static envPrefix: string = "ACORE_ARMORY"; - private static checkedMissingField: boolean = false; + private static envPrefix = "ACORE_ARMORY"; + private static checkedMissingField = false; public static async load(logger: winston.Logger): Promise { try { @@ -70,13 +74,13 @@ export class Config { return config as Config; } - private static loadObjFromEnv(logger: winston.Logger, obj: object, model: object, parentName: string = "") { + private static loadObjFromEnv(logger: winston.Logger, obj: object, model: object, parentName = "") { if (parentName !== "") { parentName += "."; } for (const field in model) { - if (!model.hasOwnProperty(field)) { + if (!Object.hasOwnProperty.call(model, field)) { continue; } @@ -85,9 +89,9 @@ export class Config { } else if (typeof model[field] === "object") { obj[field] = {}; Config.loadObjFromEnv(logger, obj[field], model[field], parentName + field); - } else if (!obj.hasOwnProperty(field)) { + } else if (!Object.hasOwnProperty.call(obj, field)) { const key = Config.getEnvKey(parentName + field); - if (process.env.hasOwnProperty(key)) { + if (Object.hasOwnProperty.call(process.env, key)) { obj[field] = Config.parseEnvValue(process.env[key], model[field]); } else if (!Config.checkedMissingField) { logger.warn(`Config field ${key} is missing from .env!`); @@ -96,16 +100,16 @@ export class Config { } } - private static loadArrayFromEnv(logger: winston.Logger, model: any, parentName: string = ""): any[] { + private static loadArrayFromEnv(logger: winston.Logger, model, parentName = ""): unknown[] { if (parentName !== "") { parentName += "."; } const arr = []; let i = 0; - while (true) { + for (;;) { const key = Config.getEnvKey(parentName + i); - const found = Object.keys(process.env).some(k => k.startsWith(key)); + const found = Object.keys(process.env).some((k) => k.startsWith(key)); if (!found) { break; } @@ -115,10 +119,10 @@ export class Config { } else if (typeof model === "object") { const obj = {}; Config.loadObjFromEnv(logger, obj, model, parentName + i); - if (Object.keys(obj).length > 0) { + if (Object.keys(obj).length) { arr.push(obj); } - } else if (process.env.hasOwnProperty(key)) { + } else if (Object.hasOwnProperty.call(process.env, key)) { arr.push(Config.parseEnvValue(process.env[key], model)); } else { break; @@ -131,13 +135,17 @@ export class Config { } private static getEnvKey(key: string): string { - return Config.envPrefix + "_" + key - .replace(/\./g, "__") - .replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`) - .toUpperCase(); + return ( + Config.envPrefix + + "_" + + key + .replace(/\./g, "__") + .replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`) + .toUpperCase() + ); } - private static parseEnvValue(value: string, model: any): any { + private static parseEnvValue(value: string, model: boolean | number | string): boolean | number | string { const type = typeof model; const lower = value.toLowerCase(); if (type === "boolean") { @@ -149,7 +157,7 @@ export class Config { return value; } - private static checkAllMissingFields(logger: winston.Logger, obj: object, model: object, parentName: string = "") { + private static checkAllMissingFields(logger: winston.Logger, obj: object, model: object, parentName = "") { const missing = Config.hasMissingFields(obj, model); if (parentName !== "") { parentName += "."; @@ -157,20 +165,16 @@ export class Config { for (const field of missing) { logger.warn(`Field ${parentName}${field} is missing from config.json!`); } - for (const key in model) { - if (typeof model[key] === "object" && obj.hasOwnProperty(key)) { + for (const key of Object.keys(model)) { + if (typeof model[key] === "object" && Object.hasOwnProperty.call(obj, key)) { Config.checkAllMissingFields(logger, obj[key], model[key], parentName + key); } } } private static hasMissingFields(obj: object, model: object): string[] { - const missing = []; - for (const key in model) { - if (!obj.hasOwnProperty(key)) { - missing.push(key); - } - } - return missing; + const objProp = Object.keys(obj); + const missingProps = Object.keys(model).filter((key) => !objProp.includes(key)); + return missingProps; } -}; +} diff --git a/src/armory/DataTablesSsp.ts b/src/armory/DataTablesSsp.ts index 36324f9..ba75041 100644 --- a/src/armory/DataTablesSsp.ts +++ b/src/armory/DataTablesSsp.ts @@ -1,17 +1,17 @@ -import { Pool } from "mysql2/promise"; +import { Pool, RowDataPacket } from "mysql2/promise"; import { Query } from "express-serve-static-core"; export interface IResult { recordsTotal: number; recordsFiltered: number; draw: number; - data: any[][]; + data: unknown[][]; } export interface IColumnSettings { name: string; collation?: string; - formatter?: (data: string | number | null, row: any) => string; + formatter?: (data: string | number | null, row: unknown) => string; table?: string; database?: string; } @@ -23,6 +23,7 @@ export interface IColumnJoin { column2: string; database2?: string; kind: "INNER" | "FULL OUTER" | "LEFT" | "RIGHT"; + where?: string; } export class DataTablesSsp { @@ -38,52 +39,55 @@ export class DataTablesSsp { private start: number; private length: number; private _order: { - column: number, - dir: string, + column: number; + dir: string; }[]; private columns: { - data: number, - name: string, - searchable: boolean, - orderable: boolean, + data: number; + name: string; + searchable: boolean; + orderable: boolean; search: { - value: string, - regex: boolean, - } + value: string; + regex: boolean; + }; }[]; private search: { - value: string, - regex: boolean, + value: string; + regex: boolean; }; private wheres: string[] = []; private filterBindings: (string | number)[] = []; private customBindings: (string | number)[] = []; - private filterWhereSql: string = "1"; - private customWhereSql: string = "1"; - private limitSql: string = ""; - private orderSql: string = ""; - private joinSql: string = ""; + private filterWhereSql = "1"; + private customWhereSql = "1"; + private limitSql = ""; + private orderSql = ""; + private joinSql = ""; public constructor(query: Query, db: Pool, table: string, primaryKey: string, columnSettings: IColumnSettings[]) { - this.start = parseInt(query.start as string, 10); - this.length = parseInt(query.length as string, 10); + this.start = Math.max(0, parseInt(query.start as string, 10)); + this.length = Math.min(100, Math.max(0, parseInt(query.length as string, 10))); this.draw = parseInt(query.draw as string, 10); - this._order = (query.order as { column: string, dir: string }[]) - .map(order => { return { column: parseInt(order.column, 10), dir: order.dir, }; }); - this.columns = (query.columns as { data: string, name: string, searchable: string, orderable: string, search: any }[]) - .map(column => { - return { - data: parseInt(column.data, 10), - name: column.name, - searchable: column.searchable === "true", - orderable: column.orderable === "true", - search: { value: column.search.value, regex: column.search.regex === "true" }, - }; - }); + this._order = (query.order as { column: string; dir: string }[]).map((order) => { + const dir = order.dir.toUpperCase() === "DESC" ? "DESC" : "ASC"; + return { column: parseInt(order.column, 10), dir }; + }); + this.columns = ( + query.columns as { data: string; name: string; searchable: string; orderable: string; search: { value: string; regex: string } }[] + ).map((column) => { + return { + data: parseInt(column.data, 10), + name: column.name, + searchable: column.searchable === "true", + orderable: column.orderable === "true", + search: { value: column.search.value, regex: column.search.regex === "true" }, + }; + }); this.search = { - value: (query.search as any).value as string, - regex: (query.search as any).regex === "true", + value: (query.search as unknown)["value"] as string, + regex: (query.search as unknown)["regex"] === "true", }; this.db = db; @@ -93,7 +97,7 @@ export class DataTablesSsp { } private colSettingsToStr(colSettings: IColumnSettings) { - const db = colSettings.database ? ("`" + colSettings.database + "`.") : ""; + const db = colSettings.database ? "`" + colSettings.database + "`." : ""; return `${db}\`${colSettings.table || this.table}\`.\`${colSettings.name}\``; } @@ -130,8 +134,9 @@ export class DataTablesSsp { private join() { for (const join of this.joins) { - const db2 = join.database2 ? "`" + join.database2 + "`." : ""; - this.joinSql += `${join.kind} JOIN ${db2}\`${join.table2}\` ON ${db2}\`${join.table2}\`.\`${join.column2}\` = \`${join.table1}\`.\`${join.column1}\`\n`; + const db2 = join.database2 ? `\`${join.database2}\`.` : ""; + const where = join.where ? ` ${join.where}` : ""; + this.joinSql += `${join.kind} JOIN ${db2}\`${join.table2}\` ON ${db2}\`${join.table2}\`.\`${join.column2}\` = \`${join.table1}\`.\`${join.column1}\`${where}\n`; } return this; @@ -153,19 +158,16 @@ export class DataTablesSsp { this.filterBindings.push(`%${this.search.value}%`); } if (filterWheres.length > 0) { - this.filterWhereSql = "(" + filterWheres.map(w => `(${w})`).join(" OR ") + ")"; + this.filterWhereSql = "(" + filterWheres.map((w) => `(${w})`).join(" OR ") + ")"; } } - this.customWhereSql = this.wheres.map(w => `(${w})`).join(" AND "); + this.customWhereSql = this.wheres.map((w) => `(${w})`).join(" AND "); return this; } public sql(): string { - const columns = [ - ...this.columnSettings.map(c => this.colSettingsToStr(c)), - ...this.extraDataColumns, - ]; + const columns = [...this.columnSettings.map((c) => this.colSettingsToStr(c)), ...this.extraDataColumns]; return ` SELECT ${columns.join(", ")} FROM ${this.table} @@ -198,35 +200,32 @@ export class DataTablesSsp { `; } - public async run(queryTimeout: number = 10_000): Promise { - this.limit() - .order() - .join() - .filter(); + public async run(queryTimeout = 10_000): Promise { + this.limit().order().join().filter(); const bindings = [...this.filterBindings, ...this.customBindings]; - let [rows, fields] = await this.db.query({ + let [rows] = await this.db.query({ sql: this.buildTotalCountSql(), values: this.customBindings, timeout: queryTimeout, }); const recordsTotal = rows[0].count; - [rows, fields] = await this.db.query({ + [rows] = await this.db.query({ sql: this.buildFilteredCountSql(), values: bindings, timeout: queryTimeout, }); const recordsFiltered = rows[0].count; - [rows, fields] = await this.db.query({ + [rows] = await this.db.query({ sql: this.sql(), rowsAsArray: true, values: bindings, timeout: queryTimeout, }); - rows = (rows as any[][]).map(row => { + rows = (rows as RowDataPacket[]).map((row) => { for (let i = 0; i < this.columnSettings.length; ++i) { const col = this.columnSettings[i]; if (col.formatter !== undefined) { @@ -240,7 +239,7 @@ export class DataTablesSsp { recordsTotal, recordsFiltered, draw: this.draw, - data: rows, + data: rows as unknown[][], }; } diff --git a/src/armory/Utils.ts b/src/armory/Utils.ts index 7f0c427..6e0a062 100644 --- a/src/armory/Utils.ts +++ b/src/armory/Utils.ts @@ -41,7 +41,16 @@ export class Utils { return [1, 3, 4, 7, 11].includes(race) ? EFaction.Alliance : EFaction.Horde; } - public static makeEmblemObject(obj: any, padWithZeroes: boolean = true): IEmblem { + public static makeEmblemObject( + obj: { + background: number; + emblemStyle: number; + emblemColor: number; + borderStyle: number; + borderColor: number; + }, + padWithZeroes = true, + ): IEmblem { const padLength = padWithZeroes ? 2 : 0; return { icon: obj.emblemStyle.toString().padStart(padLength, "0"), @@ -51,4 +60,37 @@ export class Utils { background: obj.background.toString().padStart(padLength, "0"), }; } + + /** + * Quote a configuration-supplied string for inline use in SQL. + * + * The bot-account filter has to be spliced into join clauses that the query + * builder emits as raw SQL, so it cannot be passed as a bound parameter the + * way a normal value would be. The value comes from the operator's own + * config rather than from a request, but quoting it keeps a stray apostrophe + * from producing a broken or surprising query. + */ + public static quoteSqlString(value: string): string { + return `'${String(value).replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`; + } + + /** + * Build the LIKE test that identifies non-player accounts. + * + * `patterns` is a comma-separated list, so a realm can name several service + * accounts at once — Playerbots plus an auction-house bot, say. Returns an + * empty string when nothing is configured, which callers treat as "do not + * filter" rather than emitting an always-false clause. + */ + public static botAccountFilter(column: string, patterns: string): string { + const list = String(patterns ?? "") + .split(",") + .map((p) => p.trim()) + .filter((p) => p.length > 0); + + if (list.length === 0) { + return ""; + } + return `(${list.map((p) => `${column} LIKE ${Utils.quoteSqlString(p)}`).join(" OR ")})`; + } } diff --git a/src/armory/controllers/ArenaController.ts b/src/armory/controllers/ArenaController.ts new file mode 100644 index 0000000..0eb93f3 --- /dev/null +++ b/src/armory/controllers/ArenaController.ts @@ -0,0 +1,156 @@ +import * as express from "express"; +import { RowDataPacket } from "mysql2"; + +import { Armory } from "../Armory"; +import { IRealmConfig } from "../Config"; +import { IEmblem, Utils } from "../Utils"; +import { DataTablesSsp } from "../DataTablesSsp"; + +interface ITeamMemberData { + name: string; + weekGames: number; + weekWins: number; + seasonGames: number; + seasonWins: number; + personalRating: number; + race: number; + class: number; + gender: string; + online: boolean; +} + +interface ITeamData { + name: string; + captainGuid: number; + type: number; + rating: number; + seasonGames: number; + seasonWins: number; + weekGames: number; + weekWins: number; + emblem: IEmblem; + members: ITeamMemberData[]; +} + +export class ArenaController { + private armory: Armory; + + public constructor(armory: Armory) { + this.armory = armory; + } + + public async index(req: express.Request, res: express.Response, next: express.NextFunction): Promise { + res.render("ladder-arena.hbs", { + title: `Arena Ladder`, + realms: this.armory.config.realms.map((r) => r.name), + }); + } + + public async team(req: express.Request, res: express.Response, next: express.NextFunction): Promise { + const realmName = req.params.realm; + const teamName = req.params.name; + + const realm = this.armory.getRealm(realmName); + if (realm === undefined) { + // Could not find realm + return next(404); + } + + const teamData = await this.getTeamData(realm, teamName); + if (teamData === null) { + // Could not find team + return next(404); + } + + res.render("arena-team.hbs", { + title: `Armory - ${teamData.name}`, + realm: realm.name, + ...teamData, + }); + } + + public async ladder(req: express.Request, res: express.Response, next: express.NextFunction): Promise { + const realmName = req.query.realm as string; + const realm = realmName === undefined ? this.armory.config.realms[0] : this.armory.config.realms.find((r) => r.name === realmName); + if (realm === undefined) { + return next(400); + } + + const teamSize = parseInt(req.query.teamsize as string); + if (!(teamSize === 2 || teamSize === 3 || teamSize === 5)) { + return next(400); + } + + const db = this.armory.getCharactersDb(realm.name); + const charSet = await this.armory.getDatabaseCharset(realm.name); + + const ssp = new DataTablesSsp(req.query, db, "arena_team", "arenaTeamId", [ + { name: "name", collation: `${charSet}_general_ci` }, + { name: "rating" }, + { name: "seasonWins" }, + { name: "seasonGames" }, + ]); + + const result = await ssp.where("`type` = " + teamSize).run(this.armory.config.dbQueryTimeout); + + res.json({ + ...result, + realm: realm.name, + teamSize, + }); + } + + private async getTeamData(realm: IRealmConfig, teamName: string): Promise { + const db = this.armory.getCharactersDb(realm.name); + const [rows] = await db.query({ + sql: ` + SELECT arenaTeamId, name, captainGuid, type, rating, seasonGames, seasonWins, weekGames, weekWins, emblemStyle, emblemColor, borderStyle, borderColor, backgroundColor AS background + FROM arena_team WHERE name = ? + `, + values: [teamName], + timeout: this.armory.config.dbQueryTimeout, + }); + if ((rows as RowDataPacket[]).length === 0) { + return null; + } + const team = rows[0]; + + const [memberRows] = await db.query({ + sql: ` + SELECT name, weekGames, weekWins, seasonGames, seasonWins, personalRating, race, class, gender, online + FROM arena_team_member + LEFT JOIN characters ON arena_team_member.guid = characters.guid + WHERE arenaTeamId = ? + `, + values: [team.arenaTeamId], + timeout: this.armory.config.dbQueryTimeout, + }); + const members: ITeamMemberData[] = (memberRows as RowDataPacket[]).map((row) => { + return { + name: row.name, + weekGames: row.weekGames, + weekWins: row.weekWins, + seasonGames: row.seasonGames, + seasonWins: row.seasonWins, + personalRating: row.personalRating, + race: Utils.raceNames[row.race], + class: Utils.classNames[row.class], + gender: row.gender === 0 ? "male" : "female", + online: row.online === 1, + }; + }); + + return { + name: team.name, + captainGuid: team.captainGuid, + type: team.type, + rating: team.rating, + seasonGames: team.seasonGames, + seasonWins: team.seasonWins, + weekGames: team.weekGames, + weekWins: team.weekWins, + emblem: Utils.makeEmblemObject(team, false), + members, + }; + } +} diff --git a/src/armory/controllers/CharacterController.ts b/src/armory/controllers/CharacterController.ts index bc56c90..1623502 100644 --- a/src/armory/controllers/CharacterController.ts +++ b/src/armory/controllers/CharacterController.ts @@ -1,10 +1,10 @@ import * as express from "express"; import { RowDataPacket } from "mysql2/promise"; -import { Utils } from "../Utils"; import { Armory } from "../Armory"; import { IRealmConfig } from "../Config"; -import { IAchievement } from "../data/DbcReader"; +import { IEmblem, Utils } from "../Utils"; +import { IAchievement as IAchievementDbc } from "../data/DbcReader"; interface ICharacterData { guid: number; @@ -27,8 +27,14 @@ interface IEquipmentData { slot: number; itemEntry: number; flags: number; - enchantments: string; + enchantments: string | number[]; randomPropertyId: number; + classId: number; + subclassId: number; + quality: number; + transmog?: number; + icon?: number; + gems?: number[]; } interface ICustomizationOption { @@ -42,6 +48,30 @@ interface IMount { icon: string; } +interface IAchievement { + id: number; + category: number; + title: string; + description: string; + points: number; + icon: string; +} + +interface IArenaTeam { + id: number; + name: string; + type: number; + rating: number; + seasonWins: number; + seasonGames: number; + background: number; + emblemStyle: number; + emblemColor: number; + borderStyle: number; + borderColor: number; + emblem?: IEmblem; +} + const ItemClassGem = 3; const SpellMechanicMounted = 21; const RaceDisplayName = { @@ -78,7 +108,7 @@ export class CharacterController { private itemSocketBonuses: { [key: number]: number }; private mountSpells: number[]; private mountBySpellId: { [key: number]: IMount }; - private achievementById: { [key: number]: IAchievement }; + private achievementById: { [key: number]: IAchievementDbc }; public constructor(armory: Armory) { this.armory = armory; @@ -88,7 +118,7 @@ export class CharacterController { this.itemInventoryTypes = {}; const itemsRetail = await this.armory.dbc.itemRetail().toArray(); for await (const item of this.armory.dbc.item()) { - const retailItem = itemsRetail.find(row => row.id === item.id); + const retailItem = itemsRetail.find((row) => row.id === item.id); if (retailItem !== undefined) { this.itemInventoryTypes[item.id] = retailItem.inventoryType; } @@ -107,7 +137,7 @@ export class CharacterController { } this.gemItems = {}; - for await (const row of this.armory.dbc.item().filter(item => item.classId === ItemClassGem)) { + for await (const row of this.armory.dbc.item().filter((item) => item.classId === ItemClassGem)) { this.gemItems[row.id] = true; } @@ -117,7 +147,7 @@ export class CharacterController { } this.itemSocketBonuses = {}; - let [rows, fields] = await this.armory.worldDb.query({ + const [rows] = await this.armory.worldDb.query({ sql: "SELECT entry, socketBonus FROM item_template WHERE socketBonus <> 0", timeout: this.armory.config.dbQueryTimeout, }); @@ -125,16 +155,17 @@ export class CharacterController { this.itemSocketBonuses[row.entry] = row.socketBonus; } - const mountSpells = await this.armory.dbc.spell() - .filter(m => m.mechanic === SpellMechanicMounted) + const mountSpells = await this.armory.dbc + .spell() + .filter((m) => m.mechanic === SpellMechanicMounted) .toArray(); - this.mountSpells = mountSpells.map(spell => spell.id); + this.mountSpells = mountSpells.map((spell) => spell.id); this.mountBySpellId = {}; for (const spell of mountSpells) { - const mount = await this.armory.dbc.mount().find(m => m.sourceSpellId === spell.id); - const icon = await this.armory.dbc.spellIcon().find(icon => icon.id === spell.spellIconId); + const mount = await this.armory.dbc.mount().find((m) => m.sourceSpellId === spell.id); + const icon = await this.armory.dbc.spellIcon().find((icon) => icon.id === spell.spellIconId); if (mount !== undefined) { - const display = await this.armory.dbc.mountDisplay().find(d => d.mountId === mount.id); + const display = await this.armory.dbc.mountDisplay().find((d) => d.mountId === mount.id); if (display !== undefined) { this.mountBySpellId[spell.id] = { creatureDisplayId: display.creatureDisplayInfoId, @@ -169,23 +200,27 @@ export class CharacterController { const equipmentData = await this.getEquipmentData(realmName, charData.guid); const customization = this.getCustomizationOptions(charData); - const equipment = equipmentData.map(row => { - (row as any).icon = this.itemIcons[row.itemEntry]; - (row as any).gems = this.getGemsFromEnchantments(row.enchantments); - (row as any).enchantments = this.filterEnchantments(row.itemEntry, row.enchantments); + const equipment = equipmentData.map((row) => { + row.icon = this.itemIcons[row.itemEntry]; + row.gems = this.getGemsFromEnchantments(row.enchantments as string); + row.enchantments = this.filterEnchantments(row.itemEntry, row.enchantments as string); return row; }); const mounts = await this.getMounts(realmName, charData.guid); + const transmogs: number[][] = this.armory.config.transmogModule ? [] : undefined; + const characterModelItems = await this.getModelViewerItems(equipmentData, charData.class, transmogs); res.render("character.hbs", { title: `Armory - ${charData.name}`, ...this.makeSharedDataObject(realm, charData), + contentPath: this.armory.config.useZamCdn ? "https://wow.zamimg.com/modelviewer/live/" : this.armory.config.websiteRoot + "/data/", data: { race: charData.race, gender: charData.gender, class: charData.class, flags: charData.playerFlags, - characterModelItems: await this.getModelViewerItems(equipmentData, charData.class), + characterModelItems, + characterModelTransmogs: transmogs, customizationOptions: customization, equipment, mounts, @@ -262,7 +297,7 @@ export class CharacterController { res.json({ categories: await this.armory.dbc.achievementCategory().toArray(), - ...await this.getAchievements(realm.name, charData), + ...(await this.getAchievements(realm.name, charData)), }); } @@ -284,6 +319,7 @@ export class CharacterController { res.render("character-pvp.hbs", { title: `Armory - ${charData.name} - PvP`, + realm: realm.name, ...this.makeSharedDataObject(realm, charData), faction: Utils.getFactionFromRaceId(charData.race), kills: await this.getPvpKills(realm.name, charData.guid), @@ -306,16 +342,32 @@ export class CharacterController { private async getCharacterData(realm: IRealmConfig, character: string | number): Promise { const where = typeof character === "string" ? "LOWER(`characters`.`name`) = LOWER(?)" : "`characters`.`guid` = ?"; - const [rows, fields] = await this.armory.getCharactersDb(realm.name).query({ + + // Bot accounts are hidden the same way game masters are: left join the + // rows we do not want, then require the join to have missed. Keeping the + // pattern inline rather than bound avoids disturbing the positional + // values below. + const botFilter = this.armory.config.hideBotAccounts + ? Utils.botAccountFilter("`bot_account`.`username`", this.armory.config.botAccountPatterns) + : ""; + const botJoin = + botFilter === "" + ? "" + : `LEFT JOIN \`${realm.authDatabase}\`.\`account\` AS \`bot_account\` ON \`bot_account\`.\`id\` = \`characters\`.\`account\` AND ${botFilter}`; + const botWhere = botFilter === "" ? "" : "AND `bot_account`.`id` IS NULL"; + + const [rows] = await this.armory.getCharactersDb(realm.name).query({ sql: ` - SELECT \`characters\`.\`guid\`, \`characters\`.\`name\`, \`race\`, \`class\`, \`gender\`, \`level\`, \`skin\`, \`face\`, \`hairStyle\`, \`hairColor\`, \`facialStyle\`, \`playerFlags\`, \`online\`, \`guild\`.\`name\` AS \`guild\` + SELECT \`characters\`.\`guid\`, \`characters\`.\`name\`, \`characters\`.\`race\`, \`characters\`.\`class\`, \`characters\`.\`gender\`, \`characters\`.\`level\`, \`characters\`.\`skin\`, \`characters\`.\`face\`, \`characters\`.\`hairStyle\`, \`characters\`.\`hairColor\`, \`characters\`.\`facialStyle\`, \`characters\`.\`playerFlags\`, \`characters\`.\`online\`, \`guild\`.\`name\` AS \`guild\` FROM \`characters\` LEFT JOIN \`guild_member\` ON \`guild_member\`.\`guid\` = \`characters\`.\`guid\` LEFT JOIN \`guild\` ON \`guild\`.\`guildid\` = \`guild_member\`.\`guildid\` - LEFT JOIN \`${realm.authDatabase}\`.\`account_access\` ON \`account_access\`.\`id\` = \`characters\`.\`account\` + LEFT JOIN \`${realm.authDatabase}\`.\`account_access\` ON \`account_access\`.\`id\` = \`characters\`.\`account\` AND \`account_access\`.\`RealmID\` IN (-1, ${realm.realmId}) AND \`account_access\`.\`gmlevel\` > 0 + ${botJoin} WHERE ${where} - AND (\`account_access\`.\`id\` IS NULL OR \`account_access\`.\`RealmID\` NOT IN (-1, ${realm.realmId}) OR \`account_access\`.\`gmlevel\` = 0 OR ? = 0) + AND (\`account_access\`.\`id\` IS NULL OR ? = 0) + ${botWhere} `, values: [character, this.armory.config.hideGameMasters ? 1 : 0], timeout: this.armory.config.dbQueryTimeout, @@ -328,21 +380,50 @@ export class CharacterController { } private async getEquipmentData(realm: string, charGuid: number): Promise { - const [rows, fields] = await this.armory.getCharactersDb(realm).query({ + const transmogSelect = this.armory.config.transmogModule ? ", custom_transmogrification.FakeEntry AS transmog" : ""; + const transmogJoin = this.armory.config.transmogModule + ? "LEFT JOIN custom_transmogrification ON custom_transmogrification.GUID = item_instance.guid" + : ""; + let [rows] = await this.armory.getCharactersDb(realm).query({ sql: ` - SELECT character_inventory.slot, item_instance.itemEntry, item_instance.flags, item_instance.enchantments, item_instance.randomPropertyId + SELECT + character_inventory.slot, item_instance.itemEntry, item_instance.flags, item_instance.enchantments, item_instance.randomPropertyId + ${transmogSelect} FROM character_inventory JOIN item_instance ON item_instance.guid = character_inventory.item + ${transmogJoin} WHERE character_inventory.guid = ? AND character_inventory.bag = 0 AND character_inventory.slot IN (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18) `, values: [charGuid], timeout: this.armory.config.dbQueryTimeout, }); - return rows as RowDataPacket[] as IEquipmentData[]; + + const data = rows as RowDataPacket[] as IEquipmentData[]; + if (data.length === 0) { + return []; + } + + for (const row of data) { + const item = await this.armory.dbc.item().find((item) => item.id === row.itemEntry); + row.classId = item.classId; + row.subclassId = item.subclassId; + } + + [rows] = await this.armory.worldDb.query({ + sql: "SELECT entry, quality FROM item_template WHERE entry IN (?)", + values: [data.map((row) => row.itemEntry)], + timeout: this.armory.config.dbQueryTimeout, + }); + for (const row of rows as RowDataPacket[]) { + const item = data.find((item) => item.itemEntry === row.entry); + item.quality = row.quality; + } + + return data; } private async getMounts(realm: string, charGuid: number): Promise { - const [rows, fields] = await this.armory.getCharactersDb(realm).query({ + const [rows] = await this.armory.getCharactersDb(realm).query({ sql: ` SELECT spell FROM character_spell @@ -352,34 +433,52 @@ export class CharacterController { timeout: this.armory.config.dbQueryTimeout, }); - return (rows as RowDataPacket[]) - .map(row => this.mountBySpellId[row.spell]) - .filter(m => m !== undefined); + return (rows as RowDataPacket[]).map((row) => this.mountBySpellId[row.spell]).filter((m) => m !== undefined); } - private async getModelViewerItems(equipmentData: IEquipmentData[], charClass: number): Promise { + private async getModelViewerItems(equipmentData: IEquipmentData[], charClass: number, transmogOut?: number[][]): Promise { if (charClass !== 3) { // Keep ranged weapon only if the character is a hunter - equipmentData = equipmentData.filter(row => row.slot !== 17); + equipmentData = equipmentData.filter((row) => row.slot !== 17); } - const visibleEquipment = equipmentData. - filter(item => + const visibleEquipment = equipmentData.filter( + (item) => [0, 2, 3, 4, 5, 6, 7, 8, 9, 14, 15, 16, 17, 18].includes(item.slot) && // visible slots - item.itemEntry !== 5976 // filter out Guild Tabard (displays blank otherwise) - ); + item.itemEntry !== 5976, // filter out Guild Tabard (displays blank otherwise) + ); const items: number[][] = []; for (const equipment of visibleEquipment) { - const modifiedAppearance = await this.armory.dbc.itemModifiedAppearance().find(row => row.itemId === equipment.itemEntry); + const modifiedAppearance = await this.armory.dbc.itemModifiedAppearance().find((row) => row.itemId === equipment.itemEntry); if (modifiedAppearance === undefined) { continue; } - const appearance = await this.armory.dbc.itemAppearance().find(row => row.id === modifiedAppearance.itemAppearanceId); + let appearance = await this.armory.dbc.itemAppearance().find((row) => row.id === modifiedAppearance.itemAppearanceId); if (appearance === undefined) { continue; } + appearance = { ...appearance }; - items.push([this.itemInventoryTypes[equipment.itemEntry], appearance.itemDisplayInfoId]); + let invType = this.itemInventoryTypes[equipment.itemEntry]; + items.push([invType, appearance.itemDisplayInfoId]); + + if (transmogOut !== undefined) { + if (equipment.transmog !== undefined) { + if (equipment.transmog === 1) { + appearance.itemDisplayInfoId = -1; // Hidden gear piece from transmog + } else { + const modifiedAppearance = await this.armory.dbc.itemModifiedAppearance().find((row) => row.itemId === equipment.transmog); + if (modifiedAppearance !== undefined) { + const tmogAppearance = await this.armory.dbc.itemAppearance().find((row) => row.id === modifiedAppearance.itemAppearanceId); + if (tmogAppearance !== undefined) { + appearance = tmogAppearance; + invType = this.itemInventoryTypes[equipment.transmog]; + } + } + } + } + transmogOut.push([invType, appearance.itemDisplayInfoId]); + } } return items; @@ -389,52 +488,53 @@ export class CharacterController { return enchantments .trim() .split(" ") - .map(enchant => parseInt(enchant)) - .filter(enchant => enchant !== 0); + .map((enchant) => parseInt(enchant)) + .filter((enchant) => enchant !== 0); } private getGemsFromEnchantments(enchantments: string): number[] { return this.parseEnchantmentsString(enchantments) - .filter(enchant => enchant in this.enchantSrcItems && this.enchantSrcItems[enchant] in this.gemItems) - .map(enchant => this.enchantSrcItems[enchant]); + .filter((enchant) => enchant in this.enchantSrcItems && this.enchantSrcItems[enchant] in this.gemItems) + .map((enchant) => this.enchantSrcItems[enchant]); } private filterEnchantments(item: number, enchantments: string): number[] { const socketBonus = this.itemSocketBonuses[item]; - return this.parseEnchantmentsString(enchantments) - .filter(enchant => enchant in this.enchantSrcItems && !(this.enchantSrcItems[enchant] in this.gemItems) && enchant !== socketBonus); + return this.parseEnchantmentsString(enchantments).filter( + (enchant) => enchant in this.enchantSrcItems && !(this.enchantSrcItems[enchant] in this.gemItems) && enchant !== socketBonus, + ); } private getCustomizationOptions(charData: ICharacterData): ICustomizationOption[] { const data = this.armory.characterCustomization.getCharacterCustomizationData(charData.race, charData.gender); const options = []; const setOptionByChoiceIndex = (optionName: string, choiceIndex: number) => { - const option = data.Options.find(opt => opt.Name === optionName); + const option = data["Options"].find((opt) => opt.Name === optionName); if (option !== undefined) { - const choice = option.Choices.find(choice => choice.OrderIndex === choiceIndex); + const choice = option.Choices.find((choice) => choice.OrderIndex === choiceIndex); if (choice !== undefined) { options.push({ optionId: option.Id, choiceId: choice.Id }); } } }; const setOptionByChoiceName = (optionName: string, choiceName: string) => { - const option = data.Options.find(opt => opt.Name === optionName); + const option = data["Options"].find((opt) => opt.Name === optionName); if (option !== undefined) { - const choice = option.Choices.find(ch => ch.Name === choiceName); + const choice = option.Choices.find((ch) => ch.Name === choiceName); if (choice !== undefined) { options.push({ optionId: option.Id, choiceId: choice.Id }); } } }; const setOptionByChoiceId = (optionName: string, choiceId: number) => { - const option = data.Options.find(opt => opt.Name === optionName); + const option = data["Options"].find((opt) => opt.Name === optionName); if (option !== undefined) { options.push({ optionId: option.Id, choiceId: choiceId }); } }; const optionMapping = { - "Face": charData.face, + Face: charData.face, "Skin Color": charData.skin, "Hair Style": charData.hairStyle, "Hair Color": charData.hairColor, @@ -447,19 +547,54 @@ export class CharacterController { switch (charData.race) { case 1: // Human if (charData.gender === 0) { - setOptionByChoiceName("Mustache", { 0: "Horseshoe", 1: "Brush", 2: "Horseshoe", 3: "None", 4: "Brush", 5: "Brush", 6: "Horseshoe", 7: "Brush", 8: "None" }[charData.facialStyle]); - setOptionByChoiceName("Beard", { 0: "Short", 1: "Chin Puff", 2: "Soul Patch", 3: "Goatee", 4: "Goatee", 5: "None", 6: "Goatee", 7: "None", 8: "None" }[charData.facialStyle]); - setOptionByChoiceName("Sideburns", { 0: "Medium", 1: "None", 2: "None", 3: "Medium", 4: "Long", 5: "Long", 6: "None", 8: "None", 7: "None" }[charData.facialStyle]); + setOptionByChoiceName( + "Mustache", + { 0: "Horseshoe", 1: "Brush", 2: "Horseshoe", 3: "None", 4: "Brush", 5: "Brush", 6: "Horseshoe", 7: "Brush", 8: "None" }[ + charData.facialStyle + ], + ); + setOptionByChoiceName( + "Beard", + { 0: "Short", 1: "Chin Puff", 2: "Soul Patch", 3: "Goatee", 4: "Goatee", 5: "None", 6: "Goatee", 7: "None", 8: "None" }[ + charData.facialStyle + ], + ); + setOptionByChoiceName( + "Sideburns", + { 0: "Medium", 1: "None", 2: "None", 3: "Medium", 4: "Long", 5: "Long", 6: "None", 8: "None", 7: "None" }[charData.facialStyle], + ); setOptionByChoiceName("Eyebrows", "Natural"); setOptionByChoiceName("Face Shape", "Narrow"); - setOptionByChoiceId("Eye Color", { 0: 4138, 1: 4140, 2: 4130, 3: 4136, 4: 4141, 5: 4134, 6: 4130, 7: 4138, 8: 4144, 9: 4135, 10: 4126, 11: 4136 }[charData.face]); + setOptionByChoiceId( + "Eye Color", + { 0: 4138, 1: 4140, 2: 4130, 3: 4136, 4: 4141, 5: 4134, 6: 4130, 7: 4138, 8: 4144, 9: 4135, 10: 4126, 11: 4136 }[charData.face], + ); } else { setOptionByChoiceIndex("Piercings", charData.facialStyle); setOptionByChoiceName("Eyebrows", "Natural"); setOptionByChoiceName("Face Shape", "Narrow"); setOptionByChoiceName("Makeup", "None"); setOptionByChoiceName("Necklace", "None"); - setOptionByChoiceId("Eye Color", { 0: 4162, 1: 4153, 2: 4161, 3: 4164, 4: 4154, 5: 4160, 6: 4160, 7: 4157, 8: 4152, 9: 4154, 10: 4155, 11: 4165, 12: 4163, 13: 4155, 14: 4151 }[charData.face]); + setOptionByChoiceId( + "Eye Color", + { + 0: 4162, + 1: 4153, + 2: 4161, + 3: 4164, + 4: 4154, + 5: 4160, + 6: 4160, + 7: 4157, + 8: 4152, + 9: 4154, + 10: 4155, + 11: 4165, + 12: 4163, + 13: 4155, + 14: 4151, + }[charData.face], + ); } if (charData.class === 6) { // Death Knight @@ -471,14 +606,32 @@ export class CharacterController { setOptionByChoiceIndex("Tattoo Color", 0); setOptionByChoiceIndex("Eyebrows", 0); if (charData.gender === 0) { - setOptionByChoiceName("Mustache", { 0: "Trimmed", 1: "Bushy", 2: "Grand", 3: "Thin Braids", 4: "Wise", 5: "Thick Braids", 6: "Fancy", 7: "Bold", 8: "Tied", 9: "None", 10: "None", }[charData.facialStyle]); + setOptionByChoiceName( + "Mustache", + { + 0: "Trimmed", + 1: "Bushy", + 2: "Grand", + 3: "Thin Braids", + 4: "Wise", + 5: "Thick Braids", + 6: "Fancy", + 7: "Bold", + 8: "Tied", + 9: "None", + 10: "None", + }[charData.facialStyle], + ); setOptionByChoiceIndex("Beard", charData.facialStyle); setOptionByChoiceName("Earrings", "None"); setOptionByChoiceName("Nose Ring", "None"); setOptionByChoiceIndex("Eye Color", 0); // TODO } else { setOptionByChoiceIndex("Earrings", { 0: 0, 1: 1, 2: 2, 3: 3, 4: 0, 5: 4 }[charData.facialStyle]); - setOptionByChoiceName("Piercings", { 0: "None", 1: "None", 2: "None", 3: "None", 4: "Right Nostril", 5: "None" }[charData.facialStyle]); + setOptionByChoiceName( + "Piercings", + { 0: "None", 1: "None", 2: "None", 3: "None", 4: "Right Nostril", 5: "None" }[charData.facialStyle], + ); setOptionByChoiceIndex("Eye Color", 0); // TODO } if (charData.class === 6) { @@ -508,7 +661,10 @@ export class CharacterController { setOptionByChoiceName("Ears", "Thin"); setOptionByChoiceName("Scars", "None"); if (charData.gender === 0) { - setOptionByChoiceName("Sideburns", { 0: "None", 1: "Groomed", 2: "None", 3: "Short", 4: "Medium", 5: "Groomed" }[charData.facialStyle]); + setOptionByChoiceName( + "Sideburns", + { 0: "None", 1: "Groomed", 2: "None", 3: "Short", 4: "Medium", 5: "Groomed" }[charData.facialStyle], + ); setOptionByChoiceName("Mustache", { 0: "None", 1: "Groomed", 2: "None", 3: "Thin", 4: "None", 5: "None" }[charData.facialStyle]); setOptionByChoiceName("Beard", { 0: "None", 1: "Trimmed", 2: "Full", 3: "None", 4: "Short", 5: "Long" }[charData.facialStyle]); setOptionByChoiceName("Eyebrows", { 0: "Shaved", 1: "Short", 2: "Long", 3: "Flat", 4: "Short", 5: "Owl" }[charData.facialStyle]); @@ -538,10 +694,21 @@ export class CharacterController { setOptionByChoiceName("Horn Decoration", "None"); setOptionByChoiceName("Tail", charData.gender === 0 ? "Long" : "Short"); if (charData.gender === 0) { - setOptionByChoiceName("Facial Hair", { 0: "Bare", 1: "Bare", 2: "Burns", 3: "Chops", 4: "Mustache", 5: "Soul Patch", 6: "Handlebar", 7: "Bare" }[charData.facialStyle]); - setOptionByChoiceName("Tendrils", { 0: "None", 1: "Splayed", 2: "Double", 3: "Fanned", 4: "Single", 5: "Paired", 6: "Uniform", 7: "Twin" }[charData.facialStyle]); + setOptionByChoiceName( + "Facial Hair", + { 0: "Bare", 1: "Bare", 2: "Burns", 3: "Chops", 4: "Mustache", 5: "Soul Patch", 6: "Handlebar", 7: "Bare" }[ + charData.facialStyle + ], + ); + setOptionByChoiceName( + "Tendrils", + { 0: "None", 1: "Splayed", 2: "Double", 3: "Fanned", 4: "Single", 5: "Paired", 6: "Uniform", 7: "Twin" }[charData.facialStyle], + ); } else { - setOptionByChoiceName("Horns", { 0: "Sweeping", 1: "Curled", 2: "Curved", 3: "Thick", 4: "Wide", 5: "Grand", 6: "Short" }[charData.facialStyle]); + setOptionByChoiceName( + "Horns", + { 0: "Sweeping", 1: "Curled", 2: "Curved", 3: "Thick", 4: "Wide", 5: "Grand", 6: "Short" }[charData.facialStyle], + ); } if (charData.class === 6) { // Death Knight @@ -557,8 +724,28 @@ export class CharacterController { setOptionByChoiceName("War Paint", "None"); setOptionByChoiceName("War Paint Color", "None"); if (charData.gender === 0) { - setOptionByChoiceName("Beard", { 0: "None", 1: "Stubble", 2: "Thick", 3: "Full", 4: "Tied", 5: "Braid", 6: "Twin Braids", 7: "None", 8: "Ringed", 9: "Split", 10: "Goatee" }[charData.facialStyle]); - setOptionByChoiceName("Sideburns", { 0: "None", 1: "None", 2: "Full", 3: "Low", 4: "Full", 5: "None", 6: "None", 7: "Braids", 8: "None", 9: "Full", 10: "Thick" }[charData.facialStyle]); + setOptionByChoiceName( + "Beard", + { + 0: "None", + 1: "Stubble", + 2: "Thick", + 3: "Full", + 4: "Tied", + 5: "Braid", + 6: "Twin Braids", + 7: "None", + 8: "Ringed", + 9: "Split", + 10: "Goatee", + }[charData.facialStyle], + ); + setOptionByChoiceName( + "Sideburns", + { 0: "None", 1: "None", 2: "Full", 3: "Low", 4: "Full", 5: "None", 6: "None", 7: "Braids", 8: "None", 9: "Full", 10: "Thick" }[ + charData.facialStyle + ], + ); setOptionByChoiceName("Earrings", "None"); setOptionByChoiceName("Nose Ring", "None"); setOptionByChoiceName("Tusks", "Natural"); @@ -578,13 +765,71 @@ export class CharacterController { case 5: // Undead setOptionByChoiceName("Skin Type", "Bony"); if (charData.gender === 0) { - setOptionByChoiceName("Jaw Features", { 0: "Intact", 1: "Rot-Kissed", 2: "Intact", 3: "Slackjawed", 4: "Drooler", 5: "Intact", 6: "Slackjawed", 7: "Drooler", 8: "Bonejawed", 9: "Jawsome", 10: "Toothy", 11: "Unhinged", 12: "Cheeky", 13: "Loose", 14: "Intact", 15: "Slackjawed", 16: "Slobber" }[charData.facialStyle]); - setOptionByChoiceIndex("Face Features", { 0: 0, 1: 0, 2: 1, 3: 1, 4: 1, 5: 2, 6: 3, 7: 3, 8: 0, 9: 0, 10: 0, 11: 0, 12: 0, 13: 0, 14: 4, 15: 4, 16: 0 }[charData.facialStyle]); - setOptionByChoiceId("Eye Color", { 0: 5330, 1: 5330, 2: 6304, 3: 6304, 4: 6304, 5: 5330, 6: 5330, 7: 5330, 8: 5330, 9: 5330, 10: 6304, 11: 6304, 12: 5330, 13: 5330, 14: 5330, 15: 5330, 16: 5330 }[charData.facialStyle]); + setOptionByChoiceName( + "Jaw Features", + { + 0: "Intact", + 1: "Rot-Kissed", + 2: "Intact", + 3: "Slackjawed", + 4: "Drooler", + 5: "Intact", + 6: "Slackjawed", + 7: "Drooler", + 8: "Bonejawed", + 9: "Jawsome", + 10: "Toothy", + 11: "Unhinged", + 12: "Cheeky", + 13: "Loose", + 14: "Intact", + 15: "Slackjawed", + 16: "Slobber", + }[charData.facialStyle], + ); + setOptionByChoiceIndex( + "Face Features", + { 0: 0, 1: 0, 2: 1, 3: 1, 4: 1, 5: 2, 6: 3, 7: 3, 8: 0, 9: 0, 10: 0, 11: 0, 12: 0, 13: 0, 14: 4, 15: 4, 16: 0 }[ + charData.facialStyle + ], + ); + setOptionByChoiceId( + "Eye Color", + { + 0: 5330, + 1: 5330, + 2: 6304, + 3: 6304, + 4: 6304, + 5: 5330, + 6: 5330, + 7: 5330, + 8: 5330, + 9: 5330, + 10: 6304, + 11: 6304, + 12: 5330, + 13: 5330, + 14: 5330, + 15: 5330, + 16: 5330, + }[charData.facialStyle], + ); } else { - setOptionByChoiceName("Face Features", { 0: "None", 1: "None", 2: "Strapped", 3: "Rotting", 4: "None", 5: "None", 6: "None", 7: "Putrid" }[charData.facialStyle]); - setOptionByChoiceName("Jaw Features", { 0: "Intact", 1: "Stitched", 2: "Intact", 3: "Intact", 4: "Bonejawed", 5: "Toothy", 6: "Cheeky", 7: "Intact" }[charData.facialStyle]); - setOptionByChoiceId("Eye Color", { 0: 5337, 1: 5337, 2: 6305, 3: 5337, 4: 5337, 5: 6305, 6: 5337, 7: 5337 }[charData.facialStyle]); + setOptionByChoiceName( + "Face Features", + { 0: "None", 1: "None", 2: "Strapped", 3: "Rotting", 4: "None", 5: "None", 6: "None", 7: "Putrid" }[charData.facialStyle], + ); + setOptionByChoiceName( + "Jaw Features", + { 0: "Intact", 1: "Stitched", 2: "Intact", 3: "Intact", 4: "Bonejawed", 5: "Toothy", 6: "Cheeky", 7: "Intact" }[ + charData.facialStyle + ], + ); + setOptionByChoiceId( + "Eye Color", + { 0: 5337, 1: 5337, 2: 6305, 3: 5337, 4: 5337, 5: 6305, 6: 5337, 7: 5337 }[charData.facialStyle], + ); } if (charData.class === 6) { // Death Knight @@ -603,9 +848,18 @@ export class CharacterController { setOptionByChoiceName("Body Paint", "None"); setOptionByChoiceIndex("Paint Color", 0); if (charData.gender === 0) { - setOptionByChoiceName("Hair", { 0: "Mane", 1: "Braids", 2: "Chops", 3: "Sideburns", 4: "Mane", 5: "Wrapped", 6: "Braids" }[charData.facialStyle]); - setOptionByChoiceName("Facial Hair", { 0: "Clean", 1: "Braid", 2: "Beard", 3: "Wrapped", 4: "Curtain", 5: "Clean", 6: "Split" }[charData.facialStyle]); - setOptionByChoiceName("Nose Ring", { 0: "None", 1: "Small", 2: "Open", 3: "None", 4: "None", 5: "Bead", 6: "Open" }[charData.facialStyle]); + setOptionByChoiceName( + "Hair", + { 0: "Mane", 1: "Braids", 2: "Chops", 3: "Sideburns", 4: "Mane", 5: "Wrapped", 6: "Braids" }[charData.facialStyle], + ); + setOptionByChoiceName( + "Facial Hair", + { 0: "Clean", 1: "Braid", 2: "Beard", 3: "Wrapped", 4: "Curtain", 5: "Clean", 6: "Split" }[charData.facialStyle], + ); + setOptionByChoiceName( + "Nose Ring", + { 0: "None", 1: "Small", 2: "Open", 3: "None", 4: "None", 5: "Bead", 6: "Open" }[charData.facialStyle], + ); setOptionByChoiceIndex("Eye Color", 0); // TODO } else { setOptionByChoiceIndex("Hair", charData.facialStyle); @@ -623,8 +877,38 @@ export class CharacterController { setOptionByChoiceName("Body Paint Color", "None"); setOptionByChoiceName("Piercing", "None"); if (charData.gender === 0) { - setOptionByChoiceName("Tusks", { 0: "Tusked", 1: "Gougers", 2: "Mammoth", 3: "Spears", 4: "Bridle", 5: "Tusked", 6: "Gougers", 7: "Mammoth", 8: "Spears", 9: "Bridle", 10: "Gougers" }[charData.facialStyle]); - setOptionByChoiceName("Face Paint", { 0: "None", 1: "None", 2: "None", 3: "None", 4: "None", 5: "Berserker", 6: "Fangs", 7: "Mask", 8: "Oni", 9: "Prophet", 10: "War" }[charData.facialStyle]); + setOptionByChoiceName( + "Tusks", + { + 0: "Tusked", + 1: "Gougers", + 2: "Mammoth", + 3: "Spears", + 4: "Bridle", + 5: "Tusked", + 6: "Gougers", + 7: "Mammoth", + 8: "Spears", + 9: "Bridle", + 10: "Gougers", + }[charData.facialStyle], + ); + setOptionByChoiceName( + "Face Paint", + { + 0: "None", + 1: "None", + 2: "None", + 3: "None", + 4: "None", + 5: "Berserker", + 6: "Fangs", + 7: "Mask", + 8: "Oni", + 9: "Prophet", + 10: "War", + }[charData.facialStyle], + ); setOptionByChoiceIndex("Face Paint Color", charData.hairColor + 1); setOptionByChoiceName("Earrings", "None"); setOptionByChoiceIndex("Eye Color", 0); // TODO @@ -677,7 +961,7 @@ export class CharacterController { } private async getTalents(realm: string, character: number): Promise { - const [rows, fields] = await this.armory.getCharactersDb(realm).query({ + const [rows] = await this.armory.getCharactersDb(realm).query({ sql: ` SELECT spell, specMask FROM character_talent @@ -701,16 +985,18 @@ export class CharacterController { } private async getTalentTrees(classId: number) { - const items = await this.armory.dbc.talentTab() - .filter(tab => tab.classMask === Math.pow(2, classId - 1)) - .map(async tab => { - const icon = await this.armory.dbc.spellIcon().find(icon => icon.id === tab.spellIconId); - const spells = await this.armory.dbc.talent() - .filter(row => row.tabId === tab.id) - .map(async row => { - const spell = await this.armory.dbc.spell().find(spell => spell.id === row.spellRank0); - const icon = await this.armory.dbc.spellIcon().find(icon => icon.id === spell?.spellIconId); - return { ...row, icon: this.processSpellIconTexture(icon?.textureFilename ?? ""), }; + const items = await this.armory.dbc + .talentTab() + .filter((tab) => tab.classMask === Math.pow(2, classId - 1)) + .map(async (tab) => { + const icon = await this.armory.dbc.spellIcon().find((icon) => icon.id === tab.spellIconId); + const spells = await this.armory.dbc + .talent() + .filter((row) => row.tabId === tab.id) + .map(async (row) => { + const spell = await this.armory.dbc.spell().find((spell) => spell.id === row.spellRank0); + const icon = await this.armory.dbc.spellIcon().find((icon) => icon.id === spell?.spellIconId); + return { ...row, icon: this.processSpellIconTexture(icon?.textureFilename ?? "") }; }) .toArray(); return { @@ -724,15 +1010,11 @@ export class CharacterController { } private processSpellIconTexture(texturePath: string): string { - return texturePath - .toLowerCase() - .replace("interface\\icons\\", "") - .replace("interface\\spellbook\\", "") - .replace(/\.$/, ""); + return texturePath.toLowerCase().replace("interface\\icons\\", "").replace("interface\\spellbook\\", "").replace(/\.$/, ""); } - private async getGlyphs(realm: string, character: number): Promise { - const [rows, fields] = await this.armory.getCharactersDb(realm).query({ + private async getGlyphs(realm: string, character: number): Promise { + const [rows] = await this.armory.getCharactersDb(realm).query({ sql: ` SELECT guid, talentGroup, glyph1, glyph2, glyph3, glyph4, glyph5, glyph6 FROM character_glyphs @@ -742,11 +1024,11 @@ export class CharacterController { timeout: this.armory.config.dbQueryTimeout, }); - const glyphs = [[], []]; + const glyphs: number[][] = [[], []]; for (const row of rows as RowDataPacket[]) { - const glyphIds = [row.glyph1, row.glyph2, row.glyph3, row.glyph4, row.glyph5, row.glyph6].filter(id => id !== 0); + const glyphIds = [row.glyph1, row.glyph2, row.glyph3, row.glyph4, row.glyph5, row.glyph6].filter((id) => id !== 0); for (const glyphId of glyphIds) { - const glyph = await this.armory.dbc.glyphProperties().find(g => g.id === glyphId); + const glyph = await this.armory.dbc.glyphProperties().find((g) => g.id === glyphId); if (glyph === undefined) { continue; } @@ -757,11 +1039,15 @@ export class CharacterController { return glyphs; } - private async getAchievements(realm: string, charData: ICharacterData): Promise<{ achievements: any[]; earned: { [key: number]: any }; }> { - const promises = await this.armory.dbc.achievement() - .filter(ach => ach.faction === -1 || ach.faction === Utils.getFactionFromRaceId(charData.race)) + private async getAchievements( + realm: string, + charData: ICharacterData, + ): Promise<{ achievements: IAchievement[]; earned: { [key: number]: number } }> { + const promises = await this.armory.dbc + .achievement() + .filter((ach) => ach.faction === -1 || ach.faction === Utils.getFactionFromRaceId(charData.race)) .map(async (ach) => { - const icon = await this.armory.dbc.spellIcon().find(icon => icon.id === ach.iconId); + const icon = await this.armory.dbc.spellIcon().find((icon) => icon.id === ach.iconId); return { id: ach.id, category: ach.category, @@ -774,7 +1060,7 @@ export class CharacterController { .toArray(); const achievements = await Promise.all(promises); - const [rows, fields] = await this.armory.getCharactersDb(realm).query({ + const [rows] = await this.armory.getCharactersDb(realm).query({ sql: ` SELECT achievement, date FROM character_achievement @@ -783,11 +1069,9 @@ export class CharacterController { values: [charData.guid], timeout: this.armory.config.dbQueryTimeout, }); - const earned = {}; + const earned: { [key: number]: number } = {}; for (const row of rows as RowDataPacket[]) { - earned[row.achievement] = { - date: row.date, - }; + earned[row.achievement] = row.date; } return { @@ -796,8 +1080,8 @@ export class CharacterController { }; } - private async getPvpKills(realm: string, charGuid: number): Promise<{ total: number, today: number, yesterday: number }> { - const [rows, fields] = await this.armory.getCharactersDb(realm).query({ + private async getPvpKills(realm: string, charGuid: number): Promise<{ total: number; today: number; yesterday: number }> { + const [rows] = await this.armory.getCharactersDb(realm).query({ sql: ` SELECT totalKills, todayKills, yesterdayKills FROM characters @@ -815,8 +1099,8 @@ export class CharacterController { }; } - private async getArenaTeams(realm: string, charGuid: number): Promise { - const [rows, fields] = await this.armory.getCharactersDb(realm).query({ + private async getArenaTeams(realm: string, charGuid: number): Promise { + const [rows] = await this.armory.getCharactersDb(realm).query({ sql: ` SELECT arena_team.arenaTeamId AS id, arena_team.name, arena_team.type, arena_team.rating, arena_team.seasonWins, arena_team.seasonGames, @@ -830,7 +1114,7 @@ export class CharacterController { timeout: this.armory.config.dbQueryTimeout, }); - return (rows as RowDataPacket[]).map(row => { + return (rows as IArenaTeam[]).map((row) => { row.emblem = Utils.makeEmblemObject(row, false); return row; }); diff --git a/src/armory/controllers/GuildController.ts b/src/armory/controllers/GuildController.ts index df92261..e7ca050 100644 --- a/src/armory/controllers/GuildController.ts +++ b/src/armory/controllers/GuildController.ts @@ -2,16 +2,25 @@ import * as express from "express"; import { encode } from "html-entities"; import { RowDataPacket } from "mysql2/promise"; -import { Utils } from "../Utils"; import { Armory } from "../Armory"; import { IRealmConfig } from "../Config"; import { DataTablesSsp } from "../DataTablesSsp"; +import { Utils, IEmblem, EFaction } from "../Utils"; interface IGuildRank { id: number; name: string; } +interface IGuildData { + id: number; + name: string; + leader: string; + faction: EFaction; + emblem: IEmblem; + membersCount: number; +} + export class GuildController { private armory: Armory; @@ -64,37 +73,59 @@ export class GuildController { { name: "name", table: "characters", collation: `${charSet}_general_ci` }, { name: "rank" }, { name: "level", table: "characters" }, - { name: "class", table: "characters", formatter: cls => Utils.classNames[cls] }, + { name: "class", table: "characters", formatter: (cls) => Utils.classNames[cls] }, { name: "race", table: "characters", formatter: (race, row) => `${Utils.raceNames[race]}_${row[6] === 0 ? "male" : "female"}` }, - { name: "online", table: "characters", formatter: online => online === 1 }, + { name: "online", table: "characters", formatter: (online) => online === 1 }, ]); - ssp.joins = [ - { table1: "guild_member", column1: "guid", table2: "characters", column2: "guid", kind: "LEFT" }, - ]; + ssp.joins = [{ table1: "guild_member", column1: "guid", table2: "characters", column2: "guid", kind: "LEFT" }]; ssp.extraDataColumns = ["`characters`.`gender`"]; if (this.armory.config.hideGameMasters) { - ssp.joins.push({ table1: "characters", column1: "account", table2: "account_access", column2: "id", database2: realm.authDatabase, kind: "LEFT" }); - ssp = ssp.where(`\`account_access\`.\`id\` IS NULL OR \`account_access\`.\`RealmID\` NOT IN (-1, ${realm.realmId}) OR \`account_access\`.\`gmlevel\` = 0`); + ssp.joins.push({ + table1: "characters", + column1: "account", + table2: "account_access", + column2: "id", + database2: realm.authDatabase, + kind: "LEFT", + where: `AND \`account_access\`.\`RealmID\` IN (-1, ${realm.realmId}) AND \`account_access\`.\`gmlevel\` > 0`, + }); + ssp = ssp.where("`account_access`.`id` IS NULL"); } - const result = await ssp - .where("`guildid` = ?", guildId) - .where("`deleteInfos_Account` IS NULL") - .run(this.armory.config.dbQueryTimeout); + const botFilter = this.armory.config.hideBotAccounts + ? Utils.botAccountFilter(`\`${realm.authDatabase}\`.\`account\`.\`username\``, this.armory.config.botAccountPatterns) + : ""; + if (botFilter !== "") { + ssp.joins.push({ + table1: "characters", + column1: "account", + table2: "account", + column2: "id", + database2: realm.authDatabase, + kind: "LEFT", + where: `AND ${botFilter}`, + }); + ssp = ssp.where(`\`${realm.authDatabase}\`.\`account\`.\`id\` IS NULL`); + } + + const result = await ssp.where("`guildid` = ?", guildId).where("`deleteInfos_Account` IS NULL").run(this.armory.config.dbQueryTimeout); const ranks = await this.getGuildRanks(realm, guildId); - (result as any).ranks = {}; + const ranksObj: { [key: number]: string } = {}; for (const rank of ranks) { - (result as any).ranks[rank.id] = encode(rank.name); + ranksObj[rank.id] = encode(rank.name); } - res.json(result); + res.json({ + ...result, + ranks: ranksObj, + }); } - private async getGuildData(realm: IRealmConfig, name: string): Promise { + private async getGuildData(realm: IRealmConfig, name: string): Promise { const db = this.armory.getCharactersDb(realm.name); - let [rows, fields] = await db.query({ + let [rows] = await db.query({ sql: ` SELECT guildid, name, leaderguid, EmblemStyle AS emblemStyle, EmblemColor AS emblemColor, BorderStyle AS borderStyle, BorderColor AS borderColor, BackgroundColor AS background FROM guild WHERE name = ? @@ -107,7 +138,7 @@ export class GuildController { } const guild = rows[0]; - [rows, fields] = await db.query({ + [rows] = await db.query({ sql: ` SELECT name, race FROM characters WHERE guid = ? @@ -117,7 +148,7 @@ export class GuildController { }); const leader = rows[0]; - [rows, fields] = await db.query({ + [rows] = await db.query({ sql: ` SELECT COUNT(guid) AS \`count\` FROM guild_member WHERE guildid = ? @@ -139,7 +170,7 @@ export class GuildController { private async getGuildId(realm: IRealmConfig, name: string): Promise { const db = this.armory.getCharactersDb(realm.name); - const [rows, fields] = await db.query({ + const [rows] = await db.query({ sql: ` SELECT guildid FROM guild WHERE name = ? @@ -156,7 +187,7 @@ export class GuildController { private async guildExists(realm: IRealmConfig, id: number): Promise { const db = this.armory.getCharactersDb(realm.name); - const [rows, fields] = await db.query({ + const [rows] = await db.query({ sql: ` SELECT guildid FROM guild WHERE guildid @@ -170,7 +201,7 @@ export class GuildController { private async getGuildRanks(realm: IRealmConfig, id: number): Promise { const db = this.armory.getCharactersDb(realm.name); - const [rows, fields] = await db.query({ + const [rows] = await db.query({ sql: ` SELECT rid AS id, rname AS name FROM guild_rank WHERE guildid = ? diff --git a/src/armory/controllers/IndexController.ts b/src/armory/controllers/IndexController.ts index 0322a6f..16c9052 100644 --- a/src/armory/controllers/IndexController.ts +++ b/src/armory/controllers/IndexController.ts @@ -14,15 +14,13 @@ export class IndexController { public async index(req: express.Request, res: express.Response): Promise { res.render("index.hbs", { title: "Armory", - realms: this.armory.config.realms.map(r => r.name), + realms: this.armory.config.realms.map((r) => r.name), }); } public async search(req: express.Request, res: express.Response, next: express.NextFunction): Promise { const realmName = req.query.realm as string; - const realm = realmName === undefined ? - this.armory.config.realms[0] : - this.armory.config.realms.find(r => r.name === realmName); + const realm = realmName === undefined ? this.armory.config.realms[0] : this.armory.config.realms.find((r) => r.name === realmName); if (realm === undefined) { return next(400); } @@ -34,9 +32,9 @@ export class IndexController { { name: "name", collation: `${charSet}_general_ci` }, { table: "guild", name: "name" }, { name: "level" }, - { name: "class", formatter: cls => Utils.classNames[cls] }, + { name: "class", formatter: (cls) => Utils.classNames[cls] }, { name: "race", formatter: (race, row) => `${Utils.raceNames[race]}_${row[6] === 0 ? "male" : "female"}` }, - { name: "online", formatter: online => online === 1 }, + { name: "online", formatter: (online) => online === 1 }, ]); ssp.joins = [ { table1: "characters", column1: "guid", table2: "guild_member", column2: "guid", kind: "LEFT" }, @@ -45,15 +43,39 @@ export class IndexController { ssp.extraDataColumns = ["`characters`.`gender`"]; if (this.armory.config.hideGameMasters) { - ssp.joins.push({ table1: "characters", column1: "account", table2: "account_access", column2: "id", database2: realm.authDatabase, kind: "LEFT" }); - ssp = ssp.where(`\`account_access\`.\`id\` IS NULL OR \`account_access\`.\`RealmID\` NOT IN (-1, ${realm.realmId}) OR \`account_access\`.\`gmlevel\` = 0`); + ssp.joins.push({ + table1: "characters", + column1: "account", + table2: "account_access", + column2: "id", + database2: realm.authDatabase, + kind: "LEFT", + where: `AND \`account_access\`.\`RealmID\` IN (-1, ${realm.realmId}) AND \`account_access\`.\`gmlevel\` > 0`, + }); + ssp = ssp.where("`account_access`.`id` IS NULL"); } - const result = await ssp - .where("`deleteInfos_Account` IS NULL") - .run(this.armory.config.dbQueryTimeout); - (result as any).realm = realm.name; + const botFilter = this.armory.config.hideBotAccounts + ? Utils.botAccountFilter(`\`${realm.authDatabase}\`.\`account\`.\`username\``, this.armory.config.botAccountPatterns) + : ""; + if (botFilter !== "") { + ssp.joins.push({ + table1: "characters", + column1: "account", + table2: "account", + column2: "id", + database2: realm.authDatabase, + kind: "LEFT", + where: `AND ${botFilter}`, + }); + ssp = ssp.where(`\`${realm.authDatabase}\`.\`account\`.\`id\` IS NULL`); + } - res.json(result); + const result = await ssp.where("`deleteInfos_Account` IS NULL").run(this.armory.config.dbQueryTimeout); + + res.json({ + ...result, + realm: realm.name, + }); } } diff --git a/src/armory/data/CharacterCustomization.ts b/src/armory/data/CharacterCustomization.ts index 2c45318..b3a3b1d 100644 --- a/src/armory/data/CharacterCustomization.ts +++ b/src/armory/data/CharacterCustomization.ts @@ -3,7 +3,7 @@ const fsp = fs.promises; import * as path from "path"; export class CharacterCustomization { - private data: { [key: number]: { [key: number]: any } }; + private data: { [key: number]: { [key: number]: unknown } }; public async loadData(): Promise { this.data = {}; @@ -21,7 +21,7 @@ export class CharacterCustomization { } } - public getCharacterCustomizationData(race: number, gender: number): any { + public getCharacterCustomizationData(race: number, gender: number): unknown { return this.data[race][gender]; } } diff --git a/src/armory/data/DbcReader.ts b/src/armory/data/DbcReader.ts index 2fa6582..13983ac 100644 --- a/src/armory/data/DbcReader.ts +++ b/src/armory/data/DbcReader.ts @@ -28,6 +28,7 @@ export interface IAchievementCategory { export interface IItemDbc { id: number; classId: number; + subclassId: number; displayInfoId: number; inventoryType: number; } @@ -147,11 +148,13 @@ class AsyncGenWrapper implements IAsyncGeneratorWithArrayMethods { } public static from(array: T[]): AsyncGenWrapper { - return new AsyncGenWrapper(async function* () { - for (const x of array) { - yield x; - } - }()); + return new AsyncGenWrapper( + (async function* () { + for (const x of array) { + yield x; + } + })(), + ); } public async *[Symbol.asyncIterator](): AsyncGenerator { @@ -216,11 +219,15 @@ class DbcReader { return; } - const headerCols = headerLine.value - .map(header => camelCase(header).replace(/[\[\]]/g, "")); + const headerCols = headerLine.value.map((header) => camelCase(header).replace(/[[\]]/g, "")); for await (const arr of itr) { - const cols = arr.map(value => isNaN(value as any) ? value : parseInt(value, 10)); + const cols = arr.map((value) => { + if (value === "") { + return value; + } + return isNaN(+value) ? value : parseInt(value, 10); + }); const row = {}; headerCols.forEach((header, headerIdx) => { if (this.fields.length === 0 || this.fields.includes(header)) { @@ -241,7 +248,8 @@ class DbcReader { const str = chunk.toString(); // Iterate over each character, keep track of current column (of the returned array) for (let c = 0; c < str.length; ++c) { - let ch = str[c], nch = str[c + 1]; // Current character, next character + const ch = str[c]; + const nch = str[c + 1]; // Current character, next character if (!(col in arr)) { arr[col] = ""; // Create a new column (start with empty string) if necessary } @@ -262,14 +270,14 @@ class DbcReader { } // If it's a comma and we're not in a quoted field, move on to the next column - if (ch == ',' && !quote) { + if (ch == "," && !quote) { ++col; continue; } // If it's a newline (CRLF) and we're not in a quoted field, skip the next character // and move on to the next row and move to column 0 of that new row - if (ch == '\r' && nch == '\n' && !quote) { + if (ch == "\r" && nch == "\n" && !quote) { yield arr; arr.length = 0; // Clear the row col = 0; @@ -279,7 +287,7 @@ class DbcReader { // If it's a newline (LF or CR) and we're not in a quoted field, // move on to the next row and move to column 0 of that new row - if (!quote && (ch == '\r' || ch == '\n')) { + if (!quote && (ch == "\r" || ch == "\n")) { yield arr; arr.length = 0; // Clear the row col = 0; @@ -316,7 +324,7 @@ const dbcFields = { achievement: ["id", "faction", "titleLang0", "descriptionLang0", "category", "points", "flags", "iconId"], achievementCategory: ["id", "parent", "nameLang0"], glyphProperties: ["id", "spellId"], - item: ["id", "classId", "displayInfoId", "inventoryType"], + item: ["id", "classId", "subclassId", "displayInfoId", "inventoryType"], itemRetail: ["id", "inventoryType"], itemAppearance: ["id", "itemDisplayInfoId"], itemModifiedAppearance: ["id", "itemId", "itemAppearanceId"], @@ -326,7 +334,19 @@ const dbcFields = { spell: ["id", "mechanic", "spellIconId"], spellItemEnchantment: ["id", "srcItemId"], spellIcon: ["id", "textureFilename"], - talent: ["id", "tabId", "tierId", "columnIndex", "spellRank0", "spellRank1", "spellRank2", "spellRank3", "spellRank4", "prereqTalent0", "prereqRank0"], + talent: [ + "id", + "tabId", + "tierId", + "columnIndex", + "spellRank0", + "spellRank1", + "spellRank2", + "spellRank3", + "spellRank4", + "prereqTalent0", + "prereqRank0", + ], talentTab: ["id", "nameLang0", "spellIconId", "classMask"], }; @@ -349,17 +369,26 @@ export class DbcManager { public async loadAllFiles(): Promise { this._achievement = await this.read(DbcFiles.achievement, dbcFields.achievement).toArray(); - this._achievementCategory = await this.read(DbcFiles.achievementCategory, dbcFields.achievementCategory).toArray(); + this._achievementCategory = await this.read( + DbcFiles.achievementCategory, + dbcFields.achievementCategory, + ).toArray(); this._glyphProperties = await this.read(DbcFiles.glyphProperties, dbcFields.glyphProperties).toArray(); this._item = await this.read(DbcFiles.item, dbcFields.item).toArray(); this._itemRetail = await this.read(DbcFiles.itemRetail, dbcFields.itemRetail).toArray(); this._itemAppearance = await this.read(DbcFiles.itemAppearance, dbcFields.itemAppearance).toArray(); - this._itemModifiedAppearance = await this.read(DbcFiles.itemModifiedAppearance, dbcFields.itemModifiedAppearance).toArray(); + this._itemModifiedAppearance = await this.read( + DbcFiles.itemModifiedAppearance, + dbcFields.itemModifiedAppearance, + ).toArray(); this._itemDisplayInfo = await this.read(DbcFiles.itemDisplayInfo, dbcFields.itemDisplayInfo).toArray(); this._mount = await this.read(DbcFiles.mount, dbcFields.mount).toArray(); this._mountDisplay = await this.read(DbcFiles.mountDisplay, dbcFields.mountDisplay).toArray(); this._spell = await this.read(DbcFiles.spell, dbcFields.spell).toArray(); - this._spellItemEnchantment = await this.read(DbcFiles.spellItemEnchantment, dbcFields.spellItemEnchantment).toArray(); + this._spellItemEnchantment = await this.read( + DbcFiles.spellItemEnchantment, + dbcFields.spellItemEnchantment, + ).toArray(); this._spellIcon = await this.read(DbcFiles.spellIcon, dbcFields.spellIcon).toArray(); this._talent = await this.read(DbcFiles.talent, dbcFields.talent).toArray(); this._talentTab = await this.read(DbcFiles.talentTab, dbcFields.talentTab).toArray(); diff --git a/src/armory/main.ts b/src/armory/main.ts index cc8312e..635820e 100644 --- a/src/armory/main.ts +++ b/src/armory/main.ts @@ -1,9 +1,9 @@ import "dotenv/config"; +import "source-map-support/register"; + import { Armory } from "./Armory"; async function main(): Promise { - require("source-map-support").install(); - const armory = new Armory(); await armory.start(); } diff --git a/src/index.d.ts b/src/index.d.ts index b862ee6..0d1677d 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -1,4 +1,4 @@ -declare module Express { +declare namespace Express { export interface Request { id: string; } diff --git a/src/tools/fetchdata.ts b/src/tools/fetchdata.ts index 9e6b412..7ff74d6 100644 --- a/src/tools/fetchdata.ts +++ b/src/tools/fetchdata.ts @@ -3,20 +3,30 @@ const fsp = fs.promises; import * as path from "path"; import * as pako from "pako"; -import fetch from "node-fetch"; import * as mkdirp from "mkdirp"; -import * as glob from "glob-promise"; -import { Response } from "node-fetch"; +import * as glob from "glob"; +import "source-map-support/register"; import * as prettyMs from "pretty-ms"; import * as cliProgress from "cli-progress"; +import fetch, { Response } from "node-fetch"; import promisepool = require("@supercharge/promise-pool"); import { DbcManager, IItemAppearanceDbc, IItemModifiedAppearanceDbc, IMountDbc, IMountXDisplayDbc } from "../armory/data/DbcReader"; -require("source-map-support").install(); - const baseUrl = "https://wow.zamimg.com/modelviewer/live"; +const globAsync = (pattern: string, options?: glob.IOptions) => { + return new Promise((res, rej) => { + glob(pattern, options, (err, matches) => { + if (err) { + rej(err); + } else { + res(matches); + } + }); + }); +}; + class Stopwatch { private startTime: number; @@ -54,9 +64,12 @@ class Progress { } private createProgressBar(text: string, total: number): cliProgress.SingleBar { - const progress = new cliProgress.SingleBar({ - format: `${text} {bar} {percentage}% ({value} / {total})`, - }, cliProgress.Presets.shades_classic); + const progress = new cliProgress.SingleBar( + { + format: `${text} {bar} {percentage}% ({value} / {total})`, + }, + cliProgress.Presets.shades_classic, + ); progress.start(total, 0); return progress; } @@ -89,54 +102,46 @@ const modelsDownloadQueue = new Set(); const texturesDownloadQueue = new Set(); const bonesDownloadQueue = new Set(); -async function download(dir: string, file: string): Promise { +async function download(dir: string, file: string): Promise { const dataDir = path.join(process.cwd(), "data"); const fullPath = `${dir}/${file}`; - try { - const res = await fetch(`${baseUrl}/${fullPath}`); - if (res.status !== 200) { - throw new HttpRequestError(res); - } + const res = await fetch(`${baseUrl}/${fullPath}`); + if (res.status !== 200) { + throw new HttpRequestError(res); + } - await mkdirp(path.join(dataDir, dir)); + await mkdirp(path.join(dataDir, dir)); - if (res.headers.get("Content-Type") === "application/json") { - const json = await res.json(); - fsp.writeFile(path.join(dataDir, fullPath), JSON.stringify(json)); - return json; - } else { - const fileStream = fs.createWriteStream(path.join(dataDir, fullPath)); - await new Promise((resolve, rej) => { - res.body.pipe(fileStream); - res.body.on("error", rej); - fileStream.on("finish", resolve); - }); + if (res.headers.get("Content-Type") === "application/json") { + const json = await res.json(); + fsp.writeFile(path.join(dataDir, fullPath), JSON.stringify(json)); + return json; + } else { + const fileStream = fs.createWriteStream(path.join(dataDir, fullPath)); + await new Promise((resolve, rej) => { + res.body.pipe(fileStream); + res.body.on("error", rej); + fileStream.on("finish", resolve); + }); - return fileStream.path.toString(); - } - } catch (err) { - throw err; + return fileStream.path.toString(); } } -function queueTexturesAndModels(item: any): void { +function queueTexturesAndModels(item): void { if (item.TextureFiles !== null) { - for (const key in item.TextureFiles) { - for (const file of item.TextureFiles[key]) { - if (file.FileDataId !== 0) { - texturesDownloadQueue.add(file.FileDataId); - } + for (const file in Object.values(item.TextureFiles)) { + if (file["FileDataId"] !== 0) { + texturesDownloadQueue.add(file["FileDataId"]); } } } if (item.ModelFiles !== null) { - for (const key in item.ModelFiles) { - for (const file of item.ModelFiles[key]) { - if (file.FileDataId !== 0) { - modelsDownloadQueue.add(file.FileDataId); - } + for (const file of Object.values(item.ModelFiles)) { + if (file["FileDataId"] !== 0) { + modelsDownloadQueue.add(file["FileDataId"]); } } } @@ -146,7 +151,7 @@ function queueTexturesAndModels(item: any): void { } if (item.Textures !== null) { - for (const key in item.Textures) { + for (const key of Object.keys(item.Textures)) { if (item.Textures[key] !== 0) { texturesDownloadQueue.add(item.Textures[key]); } @@ -154,7 +159,7 @@ function queueTexturesAndModels(item: any): void { } if (item.Textures2 !== null) { - for (const key in item.Textures2) { + for (const key of Object.keys(item.Textures2)) { if (item.Textures2[key] !== 0) { texturesDownloadQueue.add(item.Textures2[key]); } @@ -163,35 +168,27 @@ function queueTexturesAndModels(item: any): void { } async function downloadRaces(): Promise { - const races = [ - "human", - "nightelf", - "dwarf", - "gnome", - "draenei", - "orc", - "troll", - "tauren", - "bloodelf", - "scourge", - ]; + const races = ["human", "nightelf", "dwarf", "gnome", "draenei", "orc", "troll", "tauren", "bloodelf", "scourge"]; const genders = ["male", "female"]; const raceGenderCombo = races.map((race) => [race + genders[0], race + genders[1]]).flat(); const progress = new Progress("Downloading races data...", raceGenderCombo.length); - await promisepool.PromisePool - .for(raceGenderCombo) + await promisepool.PromisePool.for(raceGenderCombo) .withConcurrency(4) .process(async (race) => { const characterJson = await download("meta/character", `${race}.json`); - modelsDownloadQueue.add(characterJson.Model); + modelsDownloadQueue.add(characterJson["Model"]); - const customizationJson = await download("meta/charactercustomization2", `${characterJson.Race}_${characterJson.Gender}.json`); - for (const option of customizationJson.Options) { + const customizationJson = await download("meta/charactercustomization2", `${characterJson["Race"]}_${characterJson["Gender"]}.json`); + for (const option of customizationJson["Options"]) { for (const choice of option.Choices) { for (const element of choice.Elements) { - if (element.SkinnedModel !== null && typeof element.SkinnedModel.CollectionFileDataID === "number" && element.SkinnedModel.CollectionFileDataID !== 0) { + if ( + element.SkinnedModel !== null && + typeof element.SkinnedModel.CollectionFileDataID === "number" && + element.SkinnedModel.CollectionFileDataID !== 0 + ) { modelsDownloadQueue.add(element.SkinnedModel.CollectionFileDataID); } if (element.BoneSet !== null && typeof element.BoneSet.BoneFileDataID === "number" && element.BoneSet.BoneFileDataID !== 0) { @@ -201,11 +198,9 @@ async function downloadRaces(): Promise { } } - const textureFiles = Object.keys(customizationJson.TextureFiles) - .map(key => customizationJson.TextureFiles[key]) - .flat(); + const textureFiles = Object.values(customizationJson["TextureFiles"]).flat(); for (const file of textureFiles) { - texturesDownloadQueue.add(file.FileDataId); + texturesDownloadQueue.add(file["FileDataId"]); } progress.increment(); @@ -215,12 +210,14 @@ async function downloadRaces(): Promise { } async function downloadArmors(): Promise { - const rows = await dbc.item().filter((row) => row.classId === classIdArmor).toArray(); + const rows = await dbc + .item() + .filter((row) => row.classId === classIdArmor) + .toArray(); const progress = new Progress("Downloading armor data...", rows.length); - await promisepool.PromisePool - .for(rows) + await promisepool.PromisePool.for(rows) .withConcurrency(50) .process(async (row) => { const modifiedAppearance = dbcItemModifiedAppearanceByItemId[row.id]; @@ -247,12 +244,14 @@ async function downloadArmors(): Promise { } async function downloadWeapons(): Promise { - const rows = await dbc.item().filter((row) => row.classId === classIdWeapon).toArray(); + const rows = await dbc + .item() + .filter((row) => row.classId === classIdWeapon) + .toArray(); const progress = new Progress("Downloading weapon data...", rows.length); - await promisepool.PromisePool - .for(rows) + await promisepool.PromisePool.for(rows) .withConcurrency(50) .process(async (row) => { const modifiedAppearance = dbcItemModifiedAppearanceByItemId[row.id]; @@ -262,7 +261,7 @@ async function downloadWeapons(): Promise { } const appearance = dbcItemAppearanceById[modifiedAppearance.itemAppearanceId]; try { - const itemJson = await download(`meta/item`, `${appearance.itemDisplayInfoId}.json`); + const itemJson = await download("meta/item", `${appearance.itemDisplayInfoId}.json`); queueTexturesAndModels(itemJson); progress.increment(); } catch (err) { @@ -307,11 +306,13 @@ async function readDbcData(): Promise { } async function downloadMounts(): Promise { - const mountSpells = await dbc.spell().filter(spell => spell.mechanic === spellMechanicMounted).toArray(); + const mountSpells = await dbc + .spell() + .filter((spell) => spell.mechanic === spellMechanicMounted) + .toArray(); const progress = new Progress("Downloading mount data...", mountSpells.length); - await promisepool.PromisePool - .for(mountSpells) + await promisepool.PromisePool.for(mountSpells) .withConcurrency(50) .process(async (spell) => { const mount = dbcMountBySourceSpellId[spell.id]; @@ -333,8 +334,7 @@ async function downloadMounts(): Promise { async function downloadTextures(): Promise { const progress = new Progress("Downloading textures...", texturesDownloadQueue.size); - await promisepool.PromisePool - .for(Array.from(texturesDownloadQueue)) + await promisepool.PromisePool.for(Array.from(texturesDownloadQueue)) .withConcurrency(25) .process(async (fileDataId) => { await download("textures", `${fileDataId}.png`); @@ -347,8 +347,7 @@ async function downloadTextures(): Promise { async function downloadModels(): Promise { const progress = new Progress("Downloading models...", modelsDownloadQueue.size); - await promisepool.PromisePool - .for(Array.from(modelsDownloadQueue)) + await promisepool.PromisePool.for(Array.from(modelsDownloadQueue)) .withConcurrency(25) .process(async (fileDataId) => { await download("mo3", `${fileDataId}.mo3`); @@ -361,8 +360,7 @@ async function downloadModels(): Promise { async function downloadBones(): Promise { const progress = new Progress("Downloading bones...", bonesDownloadQueue.size); - await promisepool.PromisePool - .for(Array.from(bonesDownloadQueue)) + await promisepool.PromisePool.for(Array.from(bonesDownloadQueue)) .withConcurrency(25) .process(async (fileDataId) => { try { @@ -381,11 +379,10 @@ async function downloadBones(): Promise { } async function parseModels(): Promise { - const files = await glob("data/mo3/*.mo3"); + const files = await globAsync("data/mo3/*.mo3"); const progress = new Progress("Reading model files for texture references...", files.length); - await promisepool.PromisePool - .for(files) + await promisepool.PromisePool.for(files) .withConcurrency(20) .process(async (file) => { const buffer = await fsp.readFile(file); diff --git a/static/arena-team.hbs b/static/arena-team.hbs new file mode 100644 index 0000000..350c8f5 --- /dev/null +++ b/static/arena-team.hbs @@ -0,0 +1,115 @@ + +{{> datatables}} +{{> emblems}} + +Back to Arena Ladder +

+ +
+
+
+ +
+
+ +
+
{{name}}
+
+ {{type}}v{{type}} Team, {{realm}} +
+
+
+ +
+ +
Rating: {{rating}}
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
GamesWinsLossesWin Rate
Week{{weekGames}}{{weekWins}}{{subtract weekGames weekWins}} + {{#if (isnt weekGames 0)}} + {{toPrecision (multiply (divide weekWins weekGames) 100) 3}} % + {{/if}} +
Season{{seasonGames}}{{seasonWins}}{{subtract seasonGames seasonWins}} + {{#if (isnt seasonGames 0)}} + {{toPrecision (multiply (divide seasonWins seasonGames) 100) 3}} % + {{/if}} +
+ +
+
Members:
+ + + + + + + + + + + + + + + + {{#each members}} + + + + + + + + + + + + {{/each}} + +
NameClassRaceWeek WinsWeek LossesSeason WinsSeason LossesRatingOnline
+ + {{name}} + + + + + + {{weekWins}}{{subtract weekGames weekWins}}{{seasonWins}}{{subtract seasonGames seasonWins}}{{personalRating}}{{#if online}}🟢{{else}}🔴{{/if}}
+ + diff --git a/static/character-achievements.hbs b/static/character-achievements.hbs index 78975ab..9d06e23 100644 --- a/static/character-achievements.hbs +++ b/static/character-achievements.hbs @@ -69,193 +69,194 @@ diff --git a/static/character-pvp.hbs b/static/character-pvp.hbs index b520309..17be745 100644 --- a/static/character-pvp.hbs +++ b/static/character-pvp.hbs @@ -20,7 +20,9 @@
-
{{this.name}}
+
{{this.type}}v{{this.type}} Team
Rating: {{this.rating}}
{{this.seasonWins}} W / {{subtract this.seasonGames this.seasonWins}} L
@@ -36,7 +38,9 @@
diff --git a/static/character-talents.hbs b/static/character-talents.hbs index 6a5ee73..85252fc 100644 --- a/static/character-talents.hbs +++ b/static/character-talents.hbs @@ -3,7 +3,6 @@ - {{> character-header }} @@ -47,189 +46,193 @@
-
- - -
- diff --git a/static/character.hbs b/static/character.hbs index 0a93c09..6d3cad9 100644 --- a/static/character.hbs +++ b/static/character.hbs @@ -1,8 +1,13 @@ {{> icons }} + - {{> character-header }} @@ -16,8 +21,16 @@ -
-
+
+
+ +
+
+ +
+
+ + +
+ +
+ + +
-
+
-
+ +
+ + +
+ diff --git a/static/css/arena-team.css b/static/css/arena-team.css new file mode 100644 index 0000000..5fc7071 --- /dev/null +++ b/static/css/arena-team.css @@ -0,0 +1,29 @@ +#arena-header { + display: flex; +} + +#arena-header .emblem-container { + margin-right: 1em; +} + +#arena-header .info { + text-align: center; + display: flex; + flex-direction: column; + justify-content: center; +} + +#arena-header .info .team-name { + margin-top: -8px; +} + +#stats td, +#stats th { + border: 1px solid #dddddd; + text-align: left; + padding: 8px; +} + +.dataTables_info { + display: none; +} diff --git a/static/css/character.css b/static/css/character.css index ce1d94d..ff88ff3 100644 --- a/static/css/character.css +++ b/static/css/character.css @@ -24,3 +24,12 @@ height: 100% !important; width: 100% !important; } + +.no-link-text a span { + display: none; +} + +#list-transmogs-container, +#lbl-hide-transmogs { + display: none; +} diff --git a/static/css/icons.css b/static/css/icons.css index 6eb341e..b7b4e8b 100644 --- a/static/css/icons.css +++ b/static/css/icons.css @@ -45,6 +45,7 @@ position: absolute; background-repeat: no-repeat; z-index: 1; + background-size: 36px; } .iconlarge { diff --git a/static/css/index.css b/static/css/index.css index dbe53d4..bdf4160 100644 --- a/static/css/index.css +++ b/static/css/index.css @@ -1,7 +1,3 @@ -#select-realm { - margin-bottom: 16px; -} - #results_processing { height: 70px; } diff --git a/static/css/ladder-arena.css b/static/css/ladder-arena.css new file mode 100644 index 0000000..bd81c04 --- /dev/null +++ b/static/css/ladder-arena.css @@ -0,0 +1,8 @@ +#select-arena-type-container { + display: flex; +} + +#select-arena-type-container .arena-type-label { + align-self: center; + margin-right: 4px; +} diff --git a/static/guild.hbs b/static/guild.hbs index 2342c28..56b3e9c 100644 --- a/static/guild.hbs +++ b/static/guild.hbs @@ -59,43 +59,45 @@ diff --git a/static/img/icon-border/large/default.png b/static/img/icon-border/large/default.png new file mode 100644 index 0000000..5a2221a Binary files /dev/null and b/static/img/icon-border/large/default.png differ diff --git a/static/img/icon-border/large/q0.png b/static/img/icon-border/large/q0.png new file mode 100644 index 0000000..36047a3 Binary files /dev/null and b/static/img/icon-border/large/q0.png differ diff --git a/static/img/icon-border/large/q1.png b/static/img/icon-border/large/q1.png new file mode 100644 index 0000000..866992e Binary files /dev/null and b/static/img/icon-border/large/q1.png differ diff --git a/static/img/icon-border/large/q2.png b/static/img/icon-border/large/q2.png new file mode 100644 index 0000000..3c33d2c Binary files /dev/null and b/static/img/icon-border/large/q2.png differ diff --git a/static/img/icon-border/large/q3.png b/static/img/icon-border/large/q3.png new file mode 100644 index 0000000..61ddea1 Binary files /dev/null and b/static/img/icon-border/large/q3.png differ diff --git a/static/img/icon-border/large/q4.png b/static/img/icon-border/large/q4.png new file mode 100644 index 0000000..ab20c91 Binary files /dev/null and b/static/img/icon-border/large/q4.png differ diff --git a/static/img/icon-border/large/q5.png b/static/img/icon-border/large/q5.png new file mode 100644 index 0000000..67d39c9 Binary files /dev/null and b/static/img/icon-border/large/q5.png differ diff --git a/static/img/icon-border/large/q6.png b/static/img/icon-border/large/q6.png new file mode 100644 index 0000000..83afe88 Binary files /dev/null and b/static/img/icon-border/large/q6.png differ diff --git a/static/img/icon-border/large/q7.png b/static/img/icon-border/large/q7.png new file mode 100644 index 0000000..83afe88 Binary files /dev/null and b/static/img/icon-border/large/q7.png differ diff --git a/static/img/icon-border/large/q8.png b/static/img/icon-border/large/q8.png new file mode 100644 index 0000000..83afe88 Binary files /dev/null and b/static/img/icon-border/large/q8.png differ diff --git a/static/img/icon-border/large/q9.png b/static/img/icon-border/large/q9.png new file mode 100644 index 0000000..7f5d999 Binary files /dev/null and b/static/img/icon-border/large/q9.png differ diff --git a/static/img/icon-border/medium/default.png b/static/img/icon-border/medium/default.png new file mode 100644 index 0000000..9d91ac9 Binary files /dev/null and b/static/img/icon-border/medium/default.png differ diff --git a/static/img/icon-border/medium/q0.png b/static/img/icon-border/medium/q0.png new file mode 100644 index 0000000..4901e95 Binary files /dev/null and b/static/img/icon-border/medium/q0.png differ diff --git a/static/img/icon-border/medium/q1.png b/static/img/icon-border/medium/q1.png new file mode 100644 index 0000000..56cfea1 Binary files /dev/null and b/static/img/icon-border/medium/q1.png differ diff --git a/static/img/icon-border/medium/q2.png b/static/img/icon-border/medium/q2.png new file mode 100644 index 0000000..866bc6f Binary files /dev/null and b/static/img/icon-border/medium/q2.png differ diff --git a/static/img/icon-border/medium/q3.png b/static/img/icon-border/medium/q3.png new file mode 100644 index 0000000..bc43301 Binary files /dev/null and b/static/img/icon-border/medium/q3.png differ diff --git a/static/img/icon-border/medium/q4.png b/static/img/icon-border/medium/q4.png new file mode 100644 index 0000000..ea74f5b Binary files /dev/null and b/static/img/icon-border/medium/q4.png differ diff --git a/static/img/icon-border/medium/q5.png b/static/img/icon-border/medium/q5.png new file mode 100644 index 0000000..b9f4b89 Binary files /dev/null and b/static/img/icon-border/medium/q5.png differ diff --git a/static/img/icon-border/medium/q6.png b/static/img/icon-border/medium/q6.png new file mode 100644 index 0000000..cedeb6e Binary files /dev/null and b/static/img/icon-border/medium/q6.png differ diff --git a/static/img/icon-border/medium/q7.png b/static/img/icon-border/medium/q7.png new file mode 100644 index 0000000..cedeb6e Binary files /dev/null and b/static/img/icon-border/medium/q7.png differ diff --git a/static/img/icon-border/medium/q8.png b/static/img/icon-border/medium/q8.png new file mode 100644 index 0000000..cedeb6e Binary files /dev/null and b/static/img/icon-border/medium/q8.png differ diff --git a/static/img/icon-border/medium/q9.png b/static/img/icon-border/medium/q9.png new file mode 100644 index 0000000..8db67b1 Binary files /dev/null and b/static/img/icon-border/medium/q9.png differ diff --git a/static/index.hbs b/static/index.hbs index b49052c..19d3e95 100644 --- a/static/index.hbs +++ b/static/index.hbs @@ -3,8 +3,11 @@

Armory

-{{#if (not (equalsLength realms 1))}} +Arena Ladder  +

+ +{{#if (not (equalsLength realms 1))}}
Realm:
@@ -34,49 +37,51 @@ diff --git a/static/js/emblems.js b/static/js/emblems.js index ed1d9d3..cfce3aa 100644 --- a/static/js/emblems.js +++ b/static/js/emblems.js @@ -1,14 +1,16 @@ function waitForEmblemImages($emblem) { - return Promise.all($emblem.find(".images img").map((idx, img) => { - return new Promise((res, rej) => { - if (img.complete) { - res(); - } else { - img.addEventListener("load", res); - img.addEventListener("error", rej); - } - }); - })); + return Promise.all( + $emblem.find(".images img").map((idx, img) => { + return new Promise((res, rej) => { + if (img.complete) { + res(); + } else { + img.addEventListener("load", res); + img.addEventListener("error", rej); + } + }); + }), + ); } function createGuildEmblem(emblem, el) { @@ -16,7 +18,8 @@ function createGuildEmblem(emblem, el) { const canvas = $emblem.find("canvas")[0]; const ctx = canvas.getContext("2d"); - const imgUrl = (type, section, value, value2) => `${handlebarsData.websiteRoot}/img/guild-emblems/${type}_${value}${value2 ? ("_" + value2) : ""}_T${section}_U.PNG`; + const imgUrl = (type, section, value, value2) => + `${handlebarsData.websiteRoot}/img/guild-emblems/${type}_${value}${value2 ? "_" + value2 : ""}_T${section}_U.PNG`; const $images = $("
").addClass("images").appendTo($emblem); const bgUpper = $("").attr("src", imgUrl("Background", "U", emblem.background)).appendTo($images)[0]; @@ -64,7 +67,10 @@ function createArenaEmblem(teamSize, emblem, el) { const canvas = $emblem.find("canvas")[0]; const ctx = canvas.getContext("2d"); - const imgUrl = (teamSize, type, value) => `${handlebarsData.websiteRoot}/img/arena-banners/PVP-Banner${teamSize ? ("-" + teamSize) : ""}${type ? ("-" + type) : ""}${value ? ("-" + value) : ""}.PNG`; + const imgUrl = (teamSize, type, value) => + `${handlebarsData.websiteRoot}/img/arena-banners/PVP-Banner${teamSize ? "-" + teamSize : ""}${type ? "-" + type : ""}${ + value ? "-" + value : "" + }.PNG`; const $images = $("
").addClass("images").appendTo($emblem); const banner = $("").attr("src", imgUrl(teamSize)).appendTo($images)[0]; diff --git a/static/js/sync-url.js b/static/js/sync-url.js index cb2401a..a32d3dc 100644 --- a/static/js/sync-url.js +++ b/static/js/sync-url.js @@ -1,3 +1,6 @@ -window.parent.postMessage({ - url: window.location.pathname.replace(handlebarsData.websiteRoot, ""), -}, "*"); +window.parent.postMessage( + { + url: window.location.pathname.replace(handlebarsData.websiteRoot, ""), + }, + "*", +); diff --git a/static/ladder-arena.hbs b/static/ladder-arena.hbs new file mode 100644 index 0000000..20a18f7 --- /dev/null +++ b/static/ladder-arena.hbs @@ -0,0 +1,101 @@ + + +{{> datatables}} + +

Arena Ladder

+ +Armory  + +

+ +{{#if (not (equalsLength realms 1))}} +
+ Realm: +
+ +
+   +
+ +
+
+{{else}} +
+ Type: +
+ +
+
+{{/if}} + +
+ + + + + + + + + + + +
NameRatingWinsLosses
+ + diff --git a/static/layout.hbs b/static/layout.hbs index b46cc1a..ef0ec46 100644 --- a/static/layout.hbs +++ b/static/layout.hbs @@ -15,6 +15,7 @@ const handlebarsData = {{{JSONstringify locals}}}; + {{#if iframeMode.enabled}}