diff --git a/.codebattle b/.codebattle new file mode 100644 index 000000000..29a5ada47 --- /dev/null +++ b/.codebattle @@ -0,0 +1,63 @@ +FROM node:18.15.0-alpine AS assets-image +ENV MIX_ENV=prod + +WORKDIR /tmp/codebattle/assets + +COPY apps/codebattle/package.json apps/codebattle/pnpm-lock.yaml ./ +RUN pnpm install --frozen-lockfile --network-timeout 300000 + +COPY apps/codebattle/postcss.config.js ./ +COPY apps/codebattle/assets ./assets +COPY apps/codebattle/priv/gettext ./priv/gettext + +RUN pnpm run build + +FROM elixir:1.20.2-otp-28-alpine AS compile-image +ARG GIT_HASH + +ENV APP_VERSION=$GIT_HASH +ENV MIX_ENV=prod + +WORKDIR /opt/app + +RUN apk update && apk add --no-cache build-base git ca-certificates make curl \ + && mix local.hex --force \ + && mix local.rebar --force + +COPY mix.exs . +COPY mix.lock . +COPY config ./config +COPY apps/runner/mix.exs apps/runner/mix.exs +COPY apps/codebattle/mix.exs apps/codebattle/mix.exs + +RUN mix do deps.get --only prod, deps.compile + +COPY ./apps/codebattle/ ./apps/codebattle/ +COPY ./apps/runner/ ./apps/runner/ + +COPY --from=assets-image /tmp/codebattle/assets/priv/static ./apps/codebattle/priv/static + +RUN mix phx.digest \ + && mix release codebattle \ + && mv _build/prod/rel/codebattle /opt/release + +FROM nginx:alpine AS nginx-assets + +COPY nginx.conf /etc/nginx/conf.d/default.conf + +COPY --from=compile-image /opt/release/lib/codebattle-0.1.0/priv/static/assets/ /var/www/assets + +FROM elixir:1.20.2-otp-28-alpine AS runtime-image + +RUN apk add --no-cache ca-certificates chromium git make curl vim + +ARG GIT_HASH + +ENV APP_VERSION=$GIT_HASH +ENV PORT=4000 +ENV MIX_ENV=prod +EXPOSE ${PORT} +WORKDIR /opt/app +COPY --from=compile-image /opt/release . +COPY Makefile Makefile +CMD exec /opt/app/bin/codebattle start diff --git a/.codex/config.toml b/.codex/config.toml new file mode 100644 index 000000000..cd9e1dbbd --- /dev/null +++ b/.codex/config.toml @@ -0,0 +1,7 @@ +[mcp_servers.postgres] +command = "npx" +args = [ + "-y", + "@modelcontextprotocol/server-postgres", + "postgresql://postgres:postgres@localhost:5432/codebattle_dev" +] diff --git a/services/app/.credo.exs b/.credo.exs similarity index 100% rename from services/app/.credo.exs rename to .credo.exs diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..619405d19 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,44 @@ +# Elixir specific +**/.elixir_ls +**/_build +**/cover +**/deps +**/priv/plts + +# Node/Frontend +**/node_modules +**/priv/static + +# Testing +**/test + +# Build & Development +**/tmp +**/.env +**/.env.* +!**/.env.example + +# Git +.git +.gitignore + +# IDE & Editor +**/.vscode +**/.idea +**/*.swp +**/*.swo +**/*~ + +# OS +**/.DS_Store +**/Thumbs.db + +# Container +**/Containerfile +**/.dockerignore + +# Documentation & CI +**/README.md +**/LICENSE +**/.github +**/.gitlab-ci.yml diff --git a/.env.container b/.env.container new file mode 100644 index 000000000..b2f9f4a20 --- /dev/null +++ b/.env.container @@ -0,0 +1,17 @@ +NODE_ENV=development +CODEBATTLE_DB_NAME=none +CODEBATTLE_PORT=none +CODEBATTLE_SECRET_KEY_BASE=none +CODEBATTLE_DB_HOSTNAME=none +CODEBATTLE_DB_USERNAME=none +CODEBATTLE_DB_PASSWORD=none +CODEBATTLE_DB_NAME=none +CODEBATTLE_DB_PORT=none +GITHUB_CLIENT_SECRET=none +GITHUB_CLIENT_ID=none +DISCORD_CLIENT_SECRET=none +DISCORD_CLIENT_ID=none +FIREBASE_API_KEY=none +FIREBASE_SENDER_ID=none +ONESIGNAL_API_KEY=none +ONESIGNAL_APP_ID=none diff --git a/.formatter.exs b/.formatter.exs new file mode 100644 index 000000000..9c53ba302 --- /dev/null +++ b/.formatter.exs @@ -0,0 +1,12 @@ +# Used by "mix format" +[ + plugins: [Styler, Phoenix.LiveView.HTMLFormatter], + inputs: [ + "*.{heex,ex,exs}", + "priv/*/seeds.exs", + "{config,lib,test}/**/*.{heex,ex,exs}", + "apps/*/*.{heex,ex,exs}", + "apps/*/priv/*/seeds.exs", + "apps/*/{config,lib,test}/**/*.{heex,ex,exs}" + ] +] diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100755 index 000000000..69010438c --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,69 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(git rev-parse --show-toplevel)" +cd "$ROOT_DIR" + +JS_PREFIX="apps/codebattle/assets/js/" +SCSS_PREFIX="apps/codebattle/assets/css/" +APP_DIR="apps/codebattle" +APP_PREFIX="apps/codebattle/" +ELIXIR_PATTERN='(^mix\.exs$|^\.formatter\.exs$|^config/.*\.exs$|.*\.(ex|exs)$)' + +JS_STAGED_FILES=() +while IFS= read -r file; do + JS_STAGED_FILES+=("$file") +done < <( + git diff --cached --name-only --diff-filter=ACMR | + grep -E "^${JS_PREFIX}.*\\.(js|jsx|ts|tsx)$" || true +) + +SCSS_STAGED_FILES=() +while IFS= read -r file; do + SCSS_STAGED_FILES+=("$file") +done < <( + git diff --cached --name-only --diff-filter=ACMR | + grep -E "^${SCSS_PREFIX}.*\\.scss$" || true +) + +ELIXIR_STAGED_FILES=() +while IFS= read -r file; do + ELIXIR_STAGED_FILES+=("$file") +done < <( + git diff --cached --name-only --diff-filter=ACMR | + grep -E "${ELIXIR_PATTERN}" || true +) + +if [ "${#JS_STAGED_FILES[@]}" -eq 0 ] \ + && [ "${#SCSS_STAGED_FILES[@]}" -eq 0 ] \ + && [ "${#ELIXIR_STAGED_FILES[@]}" -eq 0 ]; then + exit 0 +fi + +if [ "${#ELIXIR_STAGED_FILES[@]}" -gt 0 ]; then + mix format "${ELIXIR_STAGED_FILES[@]}" + git add -- "${ELIXIR_STAGED_FILES[@]}" + mix credo +fi + +if [ "${#JS_STAGED_FILES[@]}" -gt 0 ]; then + JS_APP_FILES=() + for file in "${JS_STAGED_FILES[@]}"; do + JS_APP_FILES+=("${file#${APP_PREFIX}}") + done + + pnpm --dir "$APP_DIR" exec oxfmt --write "${JS_APP_FILES[@]}" + pnpm --dir "$APP_DIR" exec oxlint --fix "${JS_APP_FILES[@]}" || true + git add -- "${JS_STAGED_FILES[@]}" +fi + +if [ "${#SCSS_STAGED_FILES[@]}" -gt 0 ]; then + SCSS_APP_FILES=() + for file in "${SCSS_STAGED_FILES[@]}"; do + SCSS_APP_FILES+=("${file#${APP_PREFIX}}") + done + + pnpm --dir "$APP_DIR" exec prettier --write "${SCSS_APP_FILES[@]}" + pnpm --dir "$APP_DIR" exec stylelint --fix "${SCSS_APP_FILES[@]}" || true + git add -- "${SCSS_STAGED_FILES[@]}" +fi diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index 32f073ebf..563ccb955 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -6,23 +6,67 @@ on: - master workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: - build: + changes: + if: github.repository == 'hexlet-codebattle/codebattle' + runs-on: ubuntu-latest + outputs: + codebattle_image: ${{ steps.filter.outputs.codebattle_image }} + runner_image: ${{ steps.filter.outputs.runner_image }} + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Detect image-related changes + id: filter + uses: dorny/paths-filter@v3 + with: + filters: | + codebattle_image: + - 'Containerfile.codebattle' + - 'nginx.conf' + - 'nginx-assets-entrypoint.sh' + - 'mix.exs' + - 'mix.lock' + - 'apps/codebattle/**' + - 'apps/runner/**' + - 'config/**' + runner_image: + - 'Containerfile.runner' + - 'mix.exs' + - 'mix.lock' + - 'apps/runner/**' + + backend_tests: if: github.repository == 'hexlet-codebattle/codebattle' runs-on: ubuntu-latest - timeout-minutes: 30 # Add timeout to prevent hanging builds + timeout-minutes: 25 env: MIX_ENV: test - DOCKER_BUILDKIT: 1 # Enable buildkit for faster docker builds + POSTGRES_PASSWORD: postgres + CODEBATTLE_DB_HOSTNAME: localhost + CODEBATTLE_DB_PORT: '5432' + CODEBATTLE_DB_USERNAME: postgres + CODEBATTLE_DB_PASSWORD: postgres + CODEBATTLE_DB_NAME: codebattle_test + CODEBATTLE_DB_SSL: 'false' + OTP_VERSION: '29.0.3' + ELIXIR_VERSION: '1.20.2' services: db: image: postgres:16-alpine - ports: ["5432:5432"] + ports: ['5432:5432'] env: - POSTGRES_PASSWORD: postgres - POSTGRES_HOST_AUTH_METHOD: trust # Simplify auth for CI + POSTGRES_PASSWORD: ${{ env.POSTGRES_PASSWORD }} + POSTGRES_HOST_AUTH_METHOD: trust options: >- --health-cmd pg_isready --health-interval 10s @@ -34,108 +78,224 @@ jobs: steps: - uses: actions/checkout@v4 with: - fetch-depth: 0 # Fetch complete history for better caching + fetch-depth: 1 + + - name: Setup Elixir + uses: erlef/setup-beam@v1 + with: + otp-version: ${{ env.OTP_VERSION }} + elixir-version: ${{ env.ELIXIR_VERSION }} + + - name: Cache deps + uses: actions/cache@v4 + with: + path: ./deps + key: ${{ runner.os }}-deps-${{ env.OTP_VERSION }}-${{ env.ELIXIR_VERSION }}-${{ hashFiles('mix.lock') }} + restore-keys: | + ${{ runner.os }}-deps-${{ env.OTP_VERSION }}-${{ env.ELIXIR_VERSION }}- + + - name: Cache build artifacts + uses: actions/cache@v4 + with: + path: ./_build + key: ${{ runner.os }}-build-${{ env.MIX_ENV }}-${{ env.OTP_VERSION }}-${{ env.ELIXIR_VERSION }}-${{ hashFiles('mix.lock', 'mix.exs', 'apps/**/mix.exs', 'config/**/*.exs') }} + restore-keys: | + ${{ runner.os }}-build-${{ env.MIX_ENV }}-${{ env.OTP_VERSION }}-${{ env.ELIXIR_VERSION }}- + + - name: Get deps + run: | + mix local.hex --force + mix local.rebar --force + mix deps.get + working-directory: . + + - name: Mix deps.compile + run: mix compile --warnings-as-errors + working-directory: . + + - name: Setup db + run: mix ecto.create && mix ecto.migrate + working-directory: . + + - name: Mix tests + run: make test + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v3 + with: + token: ${{ secrets.CODECOV_TOKEN }} + file: ./apps/codebattle/cover/excoveralls.json + fail_ci_if_error: false + + elixir_quality: + if: github.repository == 'hexlet-codebattle/codebattle' + runs-on: ubuntu-latest + timeout-minutes: 25 + + env: + MIX_ENV: test + OTP_VERSION: '29.0.3' + ELIXIR_VERSION: '1.20.2' + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 1 - name: Setup Elixir uses: erlef/setup-beam@v1 with: - otp-version: "27.2" - elixir-version: "1.18.3" + otp-version: ${{ env.OTP_VERSION }} + elixir-version: ${{ env.ELIXIR_VERSION }} + + - name: Cache deps + uses: actions/cache@v4 + with: + path: ./deps + key: ${{ runner.os }}-deps-${{ env.OTP_VERSION }}-${{ env.ELIXIR_VERSION }}-${{ hashFiles('mix.lock') }} + restore-keys: | + ${{ runner.os }}-deps-${{ env.OTP_VERSION }}-${{ env.ELIXIR_VERSION }}- - - name: Cache Dependencies + - name: Cache build artifacts uses: actions/cache@v4 - id: deps-cache with: - path: | - ./services/app/deps - ./services/app/_build - key: ${{ runner.os }}-mix-${{ hashFiles('**/mix.lock') }} + path: ./_build + key: ${{ runner.os }}-build-${{ env.MIX_ENV }}-${{ env.OTP_VERSION }}-${{ env.ELIXIR_VERSION }}-${{ hashFiles('mix.lock', 'mix.exs', 'apps/**/mix.exs', 'config/**/*.exs') }} restore-keys: | - ${{ runner.os }}-mix- + ${{ runner.os }}-build-${{ env.MIX_ENV }}-${{ env.OTP_VERSION }}-${{ env.ELIXIR_VERSION }}- + + - name: Ensure Dialyzer PLT directory + run: mkdir -p priv/plts + + - name: Cache Dialyzer PLT + uses: actions/cache@v4 + with: + path: priv/plts + key: ${{ runner.os }}-dialyzer-plt-${{ env.OTP_VERSION }}-${{ env.ELIXIR_VERSION }}-${{ hashFiles('mix.lock', 'mix.exs', 'apps/**/mix.exs') }} + restore-keys: | + ${{ runner.os }}-dialyzer-plt-${{ env.OTP_VERSION }}-${{ env.ELIXIR_VERSION }}- - name: Get deps run: | mix local.hex --force mix local.rebar --force mix deps.get - working-directory: ./services/app + working-directory: . - name: Mix deps.compile run: mix compile --warnings-as-errors - working-directory: ./services/app + working-directory: . - name: Mix format run: mix format --check-formatted - working-directory: ./services/app + working-directory: . - name: Mix credo run: mix credo - working-directory: ./services/app + working-directory: . + + # - name: Hex audit + # run: mix hex.audit + # working-directory: . + + # - name: Deps audit + # run: mix deps.audit + # working-directory: . + + - name: Mix dialyzer + run: make dialyzer + + frontend_quality: + if: github.repository == 'hexlet-codebattle/codebattle' + runs-on: ubuntu-latest + timeout-minutes: 20 + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 1 - - name: Get yarn cache - id: yarn-cache - run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 11.11.0 + run_install: false - - uses: actions/cache@v4 + - name: Setup Node + uses: actions/setup-node@v4 with: - path: ${{ steps.yarn-cache.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn- + node-version: '24' + cache: 'pnpm' + cache-dependency-path: ./apps/codebattle/pnpm-lock.yaml - - name: Install yarn dependencies - run: yarn install --frozen-lockfile --network-timeout 300000 - working-directory: ./services/app/apps/codebattle + - name: Install pnpm dependencies + run: pnpm install --frozen-lockfile + working-directory: ./apps/codebattle - - name: Eslint - run: yarn lint - working-directory: ./services/app/apps/codebattle + # TODO: uncomment when pnpm fixes audit for new npm bulk advisory endpoint + # https://github.com/pnpm/pnpm/issues/11265 + # - name: Frontend deps audit + # run: pnpm audit --audit-level high + # working-directory: ./apps/codebattle - - name: Run jest - run: yarn test - working-directory: ./services/app/apps/codebattle + - name: Frontend lint (JS + SCSS) + run: pnpm run lint + working-directory: ./apps/codebattle - - name: Mix audit - run: mix hex.audit - working-directory: ./services/app + - name: Frontend format check (JS + SCSS) + run: pnpm run format:check + working-directory: ./apps/codebattle - - name: Setup db - run: mix ecto.create && mix ecto.migrate - working-directory: ./services/app + - name: Run jest + run: pnpm run test + working-directory: ./apps/codebattle - - name: Mix tests - run: make test + build_images: + needs: [changes, backend_tests, elixir_quality, frontend_quality] + if: | + github.repository == 'hexlet-codebattle/codebattle' && + (needs.changes.outputs.codebattle_image == 'true' || needs.changes.outputs.runner_image == 'true') + runs-on: ubuntu-latest + timeout-minutes: 70 - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v3 + steps: + - uses: actions/checkout@v4 with: - token: ${{ secrets.CODECOV_TOKEN }} - file: ./services/app/assp/codebattle/cover/excoveralls.json - fail_ci_if_error: false + fetch-depth: 1 - - name: Login to Docker Hub + - name: Login to Github Container Registry uses: docker/login-action@v3 with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} + registry: ghcr.io + username: vtm9 + password: ${{ secrets.GH_REGISTRY_TOKEN }} - - name: Set up Docker Buildx + - name: Setup Docker Buildx uses: docker/setup-buildx-action@v3 - - name: Build and push codebattle image + - name: Build codebattle image layers + if: needs.changes.outputs.codebattle_image == 'true' run: | - make GIT_HASH=${{ github.sha }} docker-build-codebattle - make docker-push-codebattle + make BUILDX_OUTPUT=--load GIT_HASH=${{ github.sha }} build-codebattle - - name: Build and push runner image + - name: Build runner image layers + if: needs.changes.outputs.runner_image == 'true' run: | - make docker-build-runner - make docker-push-runner + make BUILDX_OUTPUT=--load GIT_HASH=${{ github.sha }} build-runner - # stop integratoin tests on CI becaues of https://github.com/hexlet-codebattle/codebattle/runs/580337561?check_suite_focus=true - # - name: Pull dockers - # run: mix dockers.pull - # working-directory: ./services/app + - name: Login to Github Container Registry (before push) + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: vtm9 + password: ${{ secrets.GH_REGISTRY_TOKEN }} - # - name: Run code checkers tests - # run: make test-code-checkers + - name: Push codebattle image set + if: needs.changes.outputs.codebattle_image == 'true' + run: | + make push-codebattle + + - name: Push runner image set + if: needs.changes.outputs.runner_image == 'true' + run: | + make push-runner diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index ac8a23c36..513538c1f 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -14,15 +14,16 @@ jobs: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true - # Use test environment by default env: MIX_ENV: test POSTGRES_PASSWORD: postgres + OTP_VERSION: '29.0.3' + ELIXIR_VERSION: '1.20.2' services: db: image: postgres:16-alpine - ports: ["5432:5432"] + ports: ['5432:5432'] env: POSTGRES_PASSWORD: ${{ env.POSTGRES_PASSWORD }} options: >- @@ -41,65 +42,101 @@ jobs: - name: Setup Elixir uses: erlef/setup-beam@v1 with: - otp-version: "27.2" - elixir-version: "1.18.2" + otp-version: ${{ env.OTP_VERSION }} + elixir-version: ${{ env.ELIXIR_VERSION }} - name: Cache Dependencies uses: actions/cache@v4 id: deps-cache with: path: | - ./services/app/deps - ./services/app/_build + ./deps + ./_build key: ${{ runner.os }}-mix-${{ hashFiles('**/mix.lock') }} restore-keys: | ${{ runner.os }}-mix- + - name: Ensure Dialyzer PLT directory + run: mkdir -p priv/plts + + - name: Cache Dialyzer PLT + uses: actions/cache@v4 + with: + path: priv/plts + key: ${{ runner.os }}-dialyzer-plt-${{ env.OTP_VERSION }}-${{ env.ELIXIR_VERSION }}-${{ hashFiles('mix.lock', 'mix.exs') }} + restore-keys: | + ${{ runner.os }}-dialyzer-plt-${{ env.OTP_VERSION }}-${{ env.ELIXIR_VERSION }}- + - name: Get deps if: steps.deps-cache.outputs.cache-hit != 'true' run: mix deps.get - working-directory: ./services/app + working-directory: . - name: Mix deps.compile run: mix compile --warnings-as-errors - working-directory: ./services/app + working-directory: . - name: Mix format run: mix format --check-formatted - working-directory: ./services/app + working-directory: . - name: Mix credo run: mix credo --strict - working-directory: ./services/app + working-directory: . + + - name: Hex audit + run: mix hex.audit + working-directory: . - - name: Get yarn cache - id: yarn-cache - run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT + - name: Deps audit + run: mix deps.audit + working-directory: . - - uses: actions/cache@v4 + - name: Mix dialyzer + run: make dialyzer + + # --- pnpm setup & caching --- + - name: Setup Node + uses: actions/setup-node@v4 with: - path: ${{ steps.yarn-cache.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn- + node-version: '24' + cache: 'pnpm' + cache-dependency-path: ./apps/codebattle/pnpm-lock.yaml + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 11.11.0 + run_install: false + + - name: Install pnpm dependencies + run: pnpm install --frozen-lockfile + working-directory: ./apps/codebattle + + # TODO: uncomment when pnpm fixes audit for new npm bulk advisory endpoint + # https://github.com/pnpm/pnpm/issues/11265 + # - name: Frontend deps audit + # run: pnpm audit --audit-level high + # working-directory: ./apps/codebattle - - name: Install yarn dependencies - run: yarn install --frozen-lockfile - working-directory: ./services/app/apps/codebattle + - name: Oxlint + run: pnpm lint + working-directory: ./apps/codebattle - - name: Eslint - run: yarn lint - working-directory: ./services/app/apps/codebattle + - name: Oxfmt check + run: pnpm format:check + working-directory: ./apps/codebattle - name: Run jest - run: yarn test - working-directory: ./services/app/apps/codebattle + run: pnpm test + working-directory: ./apps/codebattle + # --- end pnpm block --- - name: Setup db run: | mix ecto.create mix ecto.migrate - working-directory: ./services/app + working-directory: . - name: Mix tests run: make test @@ -108,5 +145,5 @@ jobs: uses: codecov/codecov-action@v4 with: token: ${{ secrets.CODECOV_TOKEN }} - file: ./services/app/assp/codebattle/cover/excoveralls.json + file: ./apps/codebattle/cover/excoveralls.json fail_ci_if_error: false diff --git a/.gitignore b/.gitignore index 4dda8abb7..b7a1db919 100644 --- a/.gitignore +++ b/.gitignore @@ -34,7 +34,7 @@ runner_bin # Alternatively, you may comment the line below and commit the # secrets file as long as you replace its contents by environment # variables. -services/app/config/prod.secret.exs +config/prod.secret.exs tags .vagrant *.DS_Store @@ -60,5 +60,8 @@ kubeconfig.yml stats.json *.hcl -services/app/priv/plts/*.plt -services/app/priv/plts/*.plt.hash +priv/plts/*.plt +priv/plts/*.plt.hash +*.pnpm-store + +.customization/ diff --git a/services/app/.iex.exs b/.iex.exs similarity index 100% rename from services/app/.iex.exs rename to .iex.exs diff --git a/.mcp.json b/.mcp.json new file mode 100644 index 000000000..b20ec21b3 --- /dev/null +++ b/.mcp.json @@ -0,0 +1,8 @@ +{ + "mcpServers": { + "tidewave": { + "type": "http", + "url": "http://localhost:4000/tidewave/mcp" + } + } +} diff --git a/.tool-versions b/.tool-versions deleted file mode 100644 index f672ffe4f..000000000 --- a/.tool-versions +++ /dev/null @@ -1,3 +0,0 @@ -elixir 1.18.2-otp-27 -erlang 27.2.2 -nodejs 18.15.0 diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..5ee482961 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,55 @@ +# Repository Guidelines + +## Project Structure & Module Organization +This is an Elixir umbrella app with multiple sub-apps under `apps/`. +- `apps/codebattle/`: Phoenix app with Elixir code in `apps/codebattle/lib/`, tests in `apps/codebattle/test/`, and frontend assets in `apps/codebattle/assets/`. +- `apps/runner/`: task runner service and language images under `apps/runner/images/`. +- `config/`, `priv/`, and top-level `mix.exs` provide shared configuration and releases. + +## Main Contexts & Helpers +Core domains expose context modules for public APIs: +- `Codebattle.Game.Context` (`apps/codebattle/lib/codebattle/game/context.ex`): game lifecycle, live game access, and player actions. +- `Codebattle.Tournament.Context` (`apps/codebattle/lib/codebattle/tournament/context.ex`): tournament CRUD, live supervision, and access checks. +- `Codebattle.Tournament.Round.Context` (`apps/codebattle/lib/codebattle/tournament/round/context.ex`): round construction and persistence. +- `Codebattle.Playbook.Context` (`apps/codebattle/lib/codebattle/playbook/context.ex`): game replay records and storage. +- `Codebattle.Event.Context` (`apps/codebattle/lib/codebattle/event/context.ex`): event stages and tournament bootstrapping. +- `Codebattle.Bot.Context` (`apps/codebattle/lib/codebattle/bot/context.ex`): bot selection and runtime start. + +Helper modules live alongside their domains: +- Game helpers: `apps/codebattle/lib/codebattle/game/helpers.ex`; tournament helpers: `apps/codebattle/lib/codebattle/tournament/helpers.ex`. +- Operational utilities: `apps/codebattle/lib/codebattle/utils/` (populate tasks/users/clans, release helpers). + +## Build, Test, and Development Commands +Use the Makefile targets for common workflows: +- `make format` / `make lint`: format or check Elixir formatting. +- `make credo`: run Credo static analysis. +- `make lint-js`: OXC (`oxlint`) for frontend assets. +- `make server`: start Phoenix (`iex -S mix phx.server`). +- `make test`: ExUnit + coveralls JSON. +- `make test-code-checkers`: image executor tests with `CODEBATTLE_EXECUTOR=local`. + +For frontend-only tasks in `apps/codebattle/`: +- `pnpm run dev`: Vite dev server. +- `pnpm run build`: production build. +- `pnpm run test`: Jest tests. + +## Coding Style & Naming Conventions +- Elixir formatting is enforced via `mix format` (see `.formatter.exs`). +- Credo rules live in `.credo.exs` (120-char line limit). +- JavaScript/React linting uses OXC (`oxlint`) via `pnpm run lint`. +- Naming: descriptive Elixir modules; `camelCase`/`PascalCase` for JS files and components. + +## Testing Guidelines +- Use `make test` as the canonical final repository test command; do not substitute a direct `mix test` run. +- Run `mix credo --strict` and `mix dialyzer` as part of the final repository verification. +- ExUnit tests live in `apps/*/test/`; coverage uses ExCoveralls with a 60% threshold. +- Frontend tests use Jest in `apps/codebattle/`. +- Name tests after the module/component under test (e.g., `user_stats_test.exs`, `UserStats.test.jsx`). + +## Commit & Pull Request Guidelines +- Recent commits use short, imperative summaries (e.g., "Fix editor", "Update logo"). +- Keep commits focused; include test results when relevant. +- PRs should describe the change, list test commands run, and attach screenshots for UI updates. + +## Configuration & Runtime Notes +- Releases are defined in `mix.exs` for `codebattle` and `runner`; runner images build via Makefiles in `apps/runner/images/`. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..b2c2da99a --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,77 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## What is Codebattle + +Open-source competitive programming platform where users solve coding tasks head-to-head in real-time. Built by the Hexlet community. Supports 20+ programming languages via containerized execution. + +## Tech Stack + +- **Backend:** Elixir 1.20.2 / OTP 29.0.3, Phoenix ~1.8 with LiveView +- **Frontend:** React + Redux Toolkit, Vite, Monaco Editor +- **Database:** PostgreSQL +- **Code Execution:** Docker/Podman containers per language (runner service) +- **Package Manager:** pnpm (not npm) for frontend + +## Project Structure + +Elixir umbrella project with two apps under `apps/`: +- `codebattle` — Main Phoenix web app (backend + frontend assets) +- `runner` — HTTP service that executes user code in isolated containers; language images in `apps/runner/images/` + +Frontend source lives in `apps/codebattle/assets/js/` with React widgets, Redux slices, and XState machines. + +See `AGENTS.md` for detailed module organization and core domain contexts. + +## Common Commands + +### Development +```bash +make compose # Start app + db via Docker Compose +make server # Local: iex -S mix phx.server +make console # Local: iex -S mix +cd apps/codebattle && pnpm run dev # Vite dev server with HMR (port 8080) +``` + +### Testing +```bash +make test # ExUnit + coverage (excludes image_executor) +make test-code-checkers # Image executor tests (CODEBATTLE_EXECUTOR=local) +make compose-test # Tests in Docker +cd apps/codebattle && pnpm test # Jest frontend tests + +# Single Elixir test file: +mix test apps/codebattle/test/codebattle/game/context_test.exs + +# Single frontend test: +cd apps/codebattle && pnpm test UserStats.test.jsx +``` + +### Linting & Formatting +```bash +make format # mix format +make lint # mix format --check-formatted +make credo # Credo static analysis +make dialyzer # Type checking +make lint-js # OXLint + stylelint +make lint-js-fix # Auto-fix JS lint issues +``` + +### Setup +```bash +make setup # Full first-time setup (Docker) +make setup-env-local # Local setup without Docker (requires mise) +make compose-db-setup # Create + migrate database +make compose-db-migrate # Apply pending migrations +``` + +## Code Style + +- Elixir: enforced by `mix format` and Credo (120-char line limit) +- JavaScript: OXLint (`.oxlintrc.json`), Prettier, Stylelint +- Coverage threshold: 60% minimum (ExCoveralls) + +## CI Pipeline + +GitHub Actions (`.github/workflows/master.yml`): runs ExUnit, Credo, Dialyzer, format check, frontend lint + tests, then builds and pushes container images to `ghcr.io/hexlet-codebattle/`. diff --git a/Containerfile.codebattle b/Containerfile.codebattle new file mode 100644 index 000000000..6cc039104 --- /dev/null +++ b/Containerfile.codebattle @@ -0,0 +1,87 @@ +FROM node:24.11-alpine AS assets-image +ENV MIX_ENV=prod + +WORKDIR /tmp/codebattle + +# Install the same pnpm version declared in apps/codebattle/package.json. +RUN npm install --global pnpm@11.11.0 + +COPY apps/codebattle/package.json apps/codebattle/pnpm-lock.yaml apps/codebattle/pnpm-workspace.yaml ./ +COPY apps/codebattle/patches ./patches +RUN pnpm install --frozen-lockfile + +COPY apps/codebattle/postcss.config.js apps/codebattle/vite.config.js ./ +COPY apps/codebattle/assets ./assets +COPY apps/codebattle/priv/gettext ./priv/gettext + +RUN pnpm run build + +FROM elixir:1.19.1-otp-28-alpine AS compile-image +ENV MIX_ENV=prod + +WORKDIR /opt/app + +RUN apk update && apk add --no-cache build-base git ca-certificates make curl \ + && mix local.hex --force \ + && mix local.rebar --force + +COPY mix.exs . +COPY mix.lock . +COPY config ./config +COPY apps/runner/mix.exs apps/runner/mix.exs +COPY apps/codebattle/mix.exs apps/codebattle/mix.exs + +RUN mix do deps.get --only prod, deps.compile + +COPY ./apps/codebattle/ ./apps/codebattle/ +COPY ./apps/runner/ ./apps/runner/ + +COPY --from=assets-image /tmp/codebattle/priv/static ./apps/codebattle/priv/static + +RUN mix phx.digest \ + && mix release codebattle \ + && mv _build/prod/rel/codebattle /opt/release + +FROM alpine:3.23 AS nginx-assets + +RUN apk add --no-cache nginx nginx-mod-http-brotli brotli + +COPY nginx.conf /etc/nginx/http.d/default.conf +COPY nginx-assets-entrypoint.sh /opt/nginx-assets-entrypoint.sh + +COPY --from=compile-image /opt/release/lib/codebattle-0.1.0/priv/static/assets/ /var/www/assets + +RUN nginx -t + +RUN find /var/www/assets -type f \( \ + -name "*.js" -o \ + -name "*.mjs" -o \ + -name "*.css" -o \ + -name "*.html" -o \ + -name "*.json" -o \ + -name "*.map" -o \ + -name "*.svg" -o \ + -name "*.txt" -o \ + -name "*.xml" -o \ + -name "*.csv" -o \ + -name "*.ico" \ + \) -exec sh -c 'gzip -f -k -9 "$1" && brotli -f -q 11 "$1"' _ {} \; + +RUN chmod +x /opt/nginx-assets-entrypoint.sh + +CMD ["/opt/nginx-assets-entrypoint.sh"] + +FROM elixir:1.19.1-otp-28-alpine AS runtime-image + +RUN apk add --no-cache ca-certificates chromium git make curl vim + +ARG GIT_HASH + +ENV APP_VERSION=$GIT_HASH +ENV PORT=4000 +ENV MIX_ENV=prod +EXPOSE ${PORT} +WORKDIR /opt/app +COPY --from=compile-image /opt/release . +COPY Makefile Makefile +CMD ["/opt/app/bin/codebattle", "start"] diff --git a/Containerfile.dev b/Containerfile.dev new file mode 100644 index 000000000..3c55779ea --- /dev/null +++ b/Containerfile.dev @@ -0,0 +1,45 @@ +FROM elixir:1.19-otp-28-alpine + +# Install Elixir tooling +RUN mix local.hex --force \ + && mix local.rebar --force \ + && mix archive.install hex phx_new --force + +# Install system dependencies + Node.js + npm + podman +RUN apk add --no-cache \ + inotify-tools \ + curl \ + vim \ + chromium \ + postgresql-client \ + build-base \ + git \ + nodejs \ + npm \ + podman + +# Install pnpm globally +RUN npm install --global pnpm + +# Base workdir +WORKDIR /app + +ARG GIT_HASH +ENV APP_VERSION="$GIT_HASH" \ + NODE_OPTIONS="--max-old-space-size=4096" \ + PNPM_SKIP_BUILD_SCRIPT_CHECK=1 + +# Copy repo +COPY . . + +# Go to Codebattle app where package.json is +WORKDIR /app/apps/codebattle + +# Install JS dependencies for Codebattle +RUN pnpm install --force && pnpm add regenerator-runtime + +# Build Codebattle assets (change to your real script if needed) +RUN pnpm run build + +# Return to umbrella root for further Elixir steps (mix deps.get, etc., if you add them later) +WORKDIR /app diff --git a/Containerfile.runner b/Containerfile.runner new file mode 100644 index 000000000..ab238bf44 --- /dev/null +++ b/Containerfile.runner @@ -0,0 +1,50 @@ +FROM elixir:1.19-otp-28-alpine AS compile-image +ENV MIX_ENV=prod + +WORKDIR /opt/app + +RUN apk update && apk add --no-cache build-base git ca-certificates make curl \ + && mix local.hex --force \ + && mix local.rebar --force + +COPY mix.exs . +COPY mix.lock . +COPY config ./config +COPY apps/runner/mix.exs apps/runner/mix.exs +COPY apps/codebattle/mix.exs apps/codebattle/mix.exs + +RUN mix do deps.get --only prod, deps.compile + +COPY ./apps/runner/ ./apps/runner/ + +RUN mix release runner \ + && mv _build/prod/rel/runner /opt/release + +FROM elixir:1.19-otp-28-alpine AS runtime-image + +ENV GOON_VERSION v1.1.1 + +RUN apk update && apk add --no-cache \ + podman \ + iptables \ + fuse-overlayfs \ + shadow \ + slirp4netns \ + ca-certificates \ + git \ + make \ + curl \ + vim + +RUN curl -fsSL "https://github.com/alco/goon/releases/download/${GOON_VERSION}/goon_linux_amd64.tar.gz" \ + | tar -xzC /usr/local/bin + +ARG GIT_HASH + +ENV APP_VERSION=$GIT_HASH +ENV PORT=4001 +EXPOSE ${PORT} +WORKDIR /opt/app +COPY --from=compile-image /opt/release . +COPY Makefile Makefile +CMD ["/opt/app/bin/runner", "start"] diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..0ad25db4b --- /dev/null +++ b/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/Makefile b/Makefile index 93e3f1c97..31108dafc 100644 --- a/Makefile +++ b/Makefile @@ -1,21 +1,188 @@ -include make-compose.mk +BUILDX_OUTPUT ?= --load + +compose: + docker compose up app + +compose-d: + docker compose up -d app + +compose-build: + docker compose build --build-arg GIT_HASH=$(shell git rev-parse HEAD) app + +compose-down: + docker compose down -v || true + +compose-test-code-checkers: + docker compose run --rm --name codebattle_app app mix test image_executor + +compose-test-fe: + docker compose run --rm --name codebattle_app app /bin/sh -c 'cd /app/apps/codebattle && pnpm test' + +compose-test: + docker compose run --rm --name codebattle_app app mix test --exclude image_executor + +compose-kill: + docker compose kill + +compose-bash: + docker compose run app bash + +compose-install-mix: + docker compose run --rm --name codebattle_app app mix deps.get + +compose-install-pnpm: + docker compose run --rm --name codebattle_app app /bin/sh -c 'cd /app/apps/codebattle && pnpm install && pnpm run build:mem' + +compose-install: compose-install-mix compose-install-pnpm + +compose-setup: compose-down compose-build compose-install compose-db-setup + +compose-db-setup: + docker compose run --rm --name codebattle_app app mix ecto.setup + +compose-db-migrate: + docker compose run --rm --name codebattle_app app mix ecto.migrate + +compose-lint: compose-mix-format compose-mix-credo compose-lint-js-fix + +compose-mix-format: + docker compose run --rm --name codebattle_app app mix format + +compose-mix-credo: + docker compose run app mix credo + +compose-lint-js-fix: + docker compose run --rm --name codebattle_app app /bin/sh -c 'cd /app/apps/codebattle && pnpm run lint --fix' + +compose-console: + docker compose run --rm --name codebattle_app app iex -S mix + +compose-restart: + docker compose restart + +compose-stop: + docker compose stop + +compose-logs: + docker compose logs -f --tail=100 + +compose-compile: + docker compose run --rm --name codebattle_app app mix compile + +compose-build-images: + docker compose run --rm --name codebattle_app app mix images.build ${lang} + +compose-pull-images: + docker compose run --rm --name codebattle_app app mix images.pull ${lang} + +compose-push-images: + docker compose run --rm --name codebattle_app app mix images.push ${lang} pg: docker compose up -d db-local clean: - rm -rf services/app/_build - rm -rf services/app/deps - rm -rf services/app/.elixir_ls - rm -rf services/app/priv/static + rm -rf _build + rm -rf deps + rm -rf .elixir_ls + rm -rf priv/static rm -rf node_modules - rm -rf tmp/battle_asserts + +format: + mix format + +lint: + mix format --check-formatted + +credo: + mix credo + +db-recreate: + mix cmd --app codebattle mix ecto.reset + +outdated: + mix hex.outdated + +lint-js: + cd apps/codebattle && pnpm run lint + +lint-js-fix: + cd apps/codebattle && pnpm run lint-fix + +mdl: + mix dialyzer + +start: + bin/codebattle eval "Codebattle.Utils.Release.migrate" + bin/codebattle start + +runner-start: + bin/runner start + +server: + iex -S mix phx.server + +console: + iex -S mix + +ARS_ARGS ?= +ARS_GOCACHE ?= $(CURDIR)/tmp/ars-go-build +ARS_GOPATH ?= $(CURDIR)/tmp/ars-go +ARS_BIN ?= $(CURDIR)/tmp/ars + +ars: + @command -v go >/dev/null 2>&1 || { \ + echo "go is required for ars. Install it first, for example:"; \ + echo " mise use -g go@1.26.1"; \ + exit 127; \ + } + @mkdir -p $(ARS_GOCACHE) $(ARS_GOPATH) + cd tools/ars && GOCACHE=$(ARS_GOCACHE) GOPATH=$(ARS_GOPATH) go build -o $(ARS_BIN) ./cmd/ars && exec $(ARS_BIN) $(ARS_ARGS) + +ars-200: + $(MAKE) ars ARS_ARGS="-server http://localhost:4000 -auth-key x-key \ + -type top200 \ + -users 200 -players-limit 200 \ + -rounds 8 \ + -break-seconds 30 \ + -round-timeout-seconds 180 \ + -avg-task-seconds 45 \ + -randomness 25 \ + -join-ramp-seconds 10 \ + -langs python,cpp \ + -task-provider task_pack \ + -task-pack-name 16_easy \ + -task-strategy per_round_pair \ + -ranking-type by_user \ + -score-strategy 75_percentile \ + -timeout-mode per_round_with_rematch" + +DIMA_ARGS ?= +DIMA_GOCACHE ?= $(CURDIR)/tmp/dima-go-build +DIMA_GOPATH ?= $(CURDIR)/tmp/dima-go +DIMA_BIN ?= $(CURDIR)/tmp/dima + +dima: + @command -v go >/dev/null 2>&1 || { \ + echo "go is required for dima. Install it first, for example:"; \ + echo " mise use -g go@1.26.1"; \ + exit 127; \ + } + @mkdir -p $(DIMA_GOCACHE) $(DIMA_GOPATH) + cd tools/dima && GOCACHE=$(DIMA_GOCACHE) GOPATH=$(DIMA_GOPATH) go build -o $(DIMA_BIN) ./cmd/dima + +huyach: dima + exec $(DIMA_BIN) $(DIMA_ARGS) test: - make -C ./services/app/ test + mix coveralls.json --exclude image_executor --max-failures 1 + +dialyzer: + mix dialyzer +test-code-checkers: export CODEBATTLE_EXECUTOR = local test-code-checkers: - make -C ./services/app/ test-code-checkers + mix test apps/codebattle/test/images --max-failures 10 terraform-vars-generate: docker run --rm -it -v $(CURDIR):/app -w /app williamyeh/ansible:alpine3 ansible-playbook ansible/terraform.yml -i ansible/production -vv --vault-password-file=tmp/ansible-vault-password @@ -35,94 +202,249 @@ ansible-vault-edit-production: docker run --rm -it -v $(CURDIR):/app -w /app williamyeh/ansible:alpine3 ansible-vault edit --vault-password-file tmp/ansible-vault-password ansible/production/group_vars/all/vault.yml release: - make -C services/app release + mix release -docker-build-local: - docker build --target assets-image \ - --file services/app/Dockerfile.codebattle \ - --build-arg GIT_HASH=$(GIT_HASH) \ - --tag codebattle/codebattle:assets-image services/app - docker build --target compile-image \ - --file services/app/Dockerfile.codebattle \ - --build-arg GIT_HASH=$(GIT_HASH) \ - --tag codebattle/codebattle:compile-image services/app - docker build --target nginx-assets \ - --file services/app/Dockerfile.codebattle \ - --tag codebattle/nginx-assets:latest services/app - docker build --target runtime-image \ - --file services/app/Dockerfile.codebattle \ +build-local: + DOCKER_BUILDKIT=1 docker build --target assets-image \ + --file Containerfile.codebattle \ --build-arg GIT_HASH=$(GIT_HASH) \ - --tag codebattle/codebattle:latest services/app - docker build --target compile-image \ - --file services/app/Dockerfile.runner \ - --tag codebattle/runner:compile-image services/app - docker build --target runtime-image \ - --file services/app/Dockerfile.runner \ - --tag codebattle/runner:latest services/app - -docker-build-codebattle: - # docker pull codebattle/codebattle:assets-image || true - # docker pull codebattle/codebattle:compile-image || true - # docker pull codebattle/codebattle:latest || true - docker build --target assets-image \ - --file services/app/Dockerfile.codebattle \ + --cache-from ghcr.io/hexlet-codebattle/codebattle:assets-image \ + --tag ghcr.io/hexlet-codebattle/codebattle:assets-image . + DOCKER_BUILDKIT=1 docker build --target compile-image \ + --file Containerfile.codebattle \ --build-arg GIT_HASH=$(GIT_HASH) \ - --tag codebattle/codebattle:assets-image services/app - docker build --target compile-image \ - --file services/app/Dockerfile.codebattle \ + --cache-from ghcr.io/hexlet-codebattle/codebattle:assets-image \ + --cache-from ghcr.io/hexlet-codebattle/codebattle:compile-image \ + --tag ghcr.io/hexlet-codebattle/codebattle:compile-image . + DOCKER_BUILDKIT=1 docker build --target nginx-assets \ + --file Containerfile.codebattle \ + --cache-from ghcr.io/hexlet-codebattle/codebattle:assets-image \ + --cache-from ghcr.io/hexlet-codebattle/codebattle:compile-image \ + --cache-from ghcr.io/hexlet-codebattle/nginx-assets:latest \ + --tag ghcr.io/hexlet-codebattle/nginx-assets:latest . + DOCKER_BUILDKIT=1 docker build --target runtime-image \ + --file Containerfile.codebattle \ --build-arg GIT_HASH=$(GIT_HASH) \ - --tag codebattle/codebattle:compile-image services/app - docker build --target nginx-assets \ - --file services/app/Dockerfile.codebattle \ - --tag codebattle/nginx-assets:latest services/app - docker build --target runtime-image \ - --file services/app/Dockerfile.codebattle \ + --cache-from ghcr.io/hexlet-codebattle/codebattle:compile-image \ + --cache-from ghcr.io/hexlet-codebattle/codebattle:latest \ + --tag ghcr.io/hexlet-codebattle/codebattle:latest . + DOCKER_BUILDKIT=1 docker build --target compile-image \ + --file Containerfile.runner \ + --cache-from ghcr.io/hexlet-codebattle/runner:compile-image \ + --tag ghcr.io/hexlet-codebattle/runner:compile-image . + DOCKER_BUILDKIT=1 docker build --target runtime-image \ + --file Containerfile.runner \ + --cache-from ghcr.io/hexlet-codebattle/runner:compile-image \ + --cache-from ghcr.io/hexlet-codebattle/runner:latest \ + --tag ghcr.io/hexlet-codebattle/runner:latest . + +build-codebattle: + docker pull ghcr.io/hexlet-codebattle/codebattle:assets-image || true + docker pull ghcr.io/hexlet-codebattle/codebattle:compile-image || true + docker pull ghcr.io/hexlet-codebattle/codebattle:latest || true + DOCKER_BUILDKIT=1 docker buildx build $(BUILDX_OUTPUT) --target assets-image \ + --file Containerfile.codebattle \ + --cache-from type=registry,ref=ghcr.io/hexlet-codebattle/codebattle:assets-cache \ + $(if $(DISABLE_CACHE_EXPORT),,--cache-to type=registry,ref=ghcr.io/hexlet-codebattle/codebattle:assets-cache,mode=max) \ + --cache-from ghcr.io/hexlet-codebattle/codebattle:assets-image \ + --build-arg BUILDKIT_INLINE_CACHE=1 \ + --tag ghcr.io/hexlet-codebattle/codebattle:assets-image . + DOCKER_BUILDKIT=1 docker buildx build $(BUILDX_OUTPUT) --target compile-image \ + --file Containerfile.codebattle \ + --cache-from type=registry,ref=ghcr.io/hexlet-codebattle/codebattle:assets-cache \ + --cache-from type=registry,ref=ghcr.io/hexlet-codebattle/codebattle:compile-cache \ + $(if $(DISABLE_CACHE_EXPORT),,--cache-to type=registry,ref=ghcr.io/hexlet-codebattle/codebattle:compile-cache,mode=max) \ + --cache-from ghcr.io/hexlet-codebattle/codebattle:assets-image \ + --cache-from ghcr.io/hexlet-codebattle/codebattle:compile-image \ + --build-arg BUILDKIT_INLINE_CACHE=1 \ + --tag ghcr.io/hexlet-codebattle/codebattle:compile-image . + DOCKER_BUILDKIT=1 docker buildx build $(BUILDX_OUTPUT) --target nginx-assets \ + --file Containerfile.codebattle \ + --cache-from type=registry,ref=ghcr.io/hexlet-codebattle/codebattle:assets-cache \ + --cache-from type=registry,ref=ghcr.io/hexlet-codebattle/codebattle:compile-cache \ + --cache-from type=registry,ref=ghcr.io/hexlet-codebattle/nginx-assets:buildcache \ + $(if $(DISABLE_CACHE_EXPORT),,--cache-to type=registry,ref=ghcr.io/hexlet-codebattle/nginx-assets:buildcache,mode=max) \ + --cache-from ghcr.io/hexlet-codebattle/codebattle:assets-image \ + --cache-from ghcr.io/hexlet-codebattle/codebattle:compile-image \ + --cache-from ghcr.io/hexlet-codebattle/nginx-assets:latest \ + --build-arg BUILDKIT_INLINE_CACHE=1 \ + --tag ghcr.io/hexlet-codebattle/nginx-assets:latest . + DOCKER_BUILDKIT=1 docker buildx build $(BUILDX_OUTPUT) --target runtime-image \ + --file Containerfile.codebattle \ --build-arg GIT_HASH=$(GIT_HASH) \ - --tag codebattle/codebattle:latest services/app + --cache-from type=registry,ref=ghcr.io/hexlet-codebattle/codebattle:compile-cache \ + --cache-from type=registry,ref=ghcr.io/hexlet-codebattle/codebattle:runtime-cache \ + $(if $(DISABLE_CACHE_EXPORT),,--cache-to type=registry,ref=ghcr.io/hexlet-codebattle/codebattle:runtime-cache,mode=max) \ + --cache-from ghcr.io/hexlet-codebattle/codebattle:compile-image \ + --cache-from ghcr.io/hexlet-codebattle/codebattle:latest \ + --build-arg BUILDKIT_INLINE_CACHE=1 \ + --tag ghcr.io/hexlet-codebattle/codebattle:latest . -docker-build-arm: - docker build --platform linux/arm64 \ +build-arm: + DOCKER_BUILDKIT=1 docker build --platform linux/arm64 \ --target assets-image \ - --file services/app/Dockerfile.codebattle \ + --file Containerfile.codebattle \ --build-arg GIT_HASH=$(GIT_HASH) \ - --tag codebattle/codebattle:assets-image-arm services/app - docker build --platform linux/arm64 \ + --cache-from ghcr.io/hexlet-codebattle/codebattle:assets-image-arm \ + --build-arg BUILDKIT_INLINE_CACHE=1 \ + --tag ghcr.io/hexlet-codebattle/codebattle:assets-image-arm . + DOCKER_BUILDKIT=1 docker build --platform linux/arm64 \ --target compile-image \ - --file services/app/Dockerfile.codebattle \ + --file Containerfile.codebattle \ --build-arg GIT_HASH=$(GIT_HASH) \ - --tag codebattle/codebattle:compile-image-arm services/app - docker build --platform linux/arm64 \ + --cache-from ghcr.io/hexlet-codebattle/codebattle:assets-image-arm \ + --cache-from ghcr.io/hexlet-codebattle/codebattle:compile-image-arm \ + --build-arg BUILDKIT_INLINE_CACHE=1 \ + --tag ghcr.io/hexlet-codebattle/codebattle:compile-image-arm . + DOCKER_BUILDKIT=1 docker build --platform linux/arm64 \ --target nginx-assets \ - --file services/app/Dockerfile.codebattle \ - --tag codebattle/nginx-assets:arm services/app - docker build --platform linux/arm64 \ + --file Containerfile.codebattle \ + --cache-from ghcr.io/hexlet-codebattle/codebattle:assets-image-arm \ + --cache-from ghcr.io/hexlet-codebattle/codebattle:compile-image-arm \ + --cache-from ghcr.io/hexlet-codebattle/nginx-assets:arm \ + --build-arg BUILDKIT_INLINE_CACHE=1 \ + --tag ghcr.io/hexlet-codebattle/nginx-assets:arm . + DOCKER_BUILDKIT=1 docker build --platform linux/arm64 \ --target runtime-image \ - --file services/app/Dockerfile.codebattle \ + --file Containerfile.codebattle \ + --build-arg GIT_HASH=$(GIT_HASH) \ + --cache-from ghcr.io/hexlet-codebattle/codebattle:compile-image-arm \ + --cache-from ghcr.io/hexlet-codebattle/codebattle:arm \ + --build-arg BUILDKIT_INLINE_CACHE=1 \ + --tag ghcr.io/hexlet-codebattle/codebattle:arm . + +push-codeabttle-arm: + docker push ghcr.io/hexlet-codebattle/codebattle:assets-image-arm + docker push ghcr.io/hexlet-codebattle/codebattle:compile-image-arm + docker push ghcr.io/hexlet-codebattle/codebattle:arm + docker push ghcr.io/hexlet-codebattle/nginx-assets:arm + +push-codebattle: + docker push ghcr.io/hexlet-codebattle/codebattle:assets-image + docker push ghcr.io/hexlet-codebattle/codebattle:compile-image + docker push ghcr.io/hexlet-codebattle/codebattle:latest + docker push ghcr.io/hexlet-codebattle/nginx-assets:latest + +build-runner: + docker pull ghcr.io/hexlet-codebattle/runner:compile-image || true + docker pull ghcr.io/hexlet-codebattle/runner:latest || true + DOCKER_BUILDKIT=1 docker buildx build $(BUILDX_OUTPUT) --target compile-image \ + --file Containerfile.runner \ + --cache-from type=registry,ref=ghcr.io/hexlet-codebattle/runner:compile-cache \ + $(if $(DISABLE_CACHE_EXPORT),,--cache-to type=registry,ref=ghcr.io/hexlet-codebattle/runner:compile-cache,mode=max) \ + --cache-from ghcr.io/hexlet-codebattle/runner:compile-image \ + --build-arg BUILDKIT_INLINE_CACHE=1 \ + --tag ghcr.io/hexlet-codebattle/runner:compile-image . + DOCKER_BUILDKIT=1 docker buildx build $(BUILDX_OUTPUT) --target runtime-image \ + --file Containerfile.runner \ --build-arg GIT_HASH=$(GIT_HASH) \ - --tag codebattle/codebattle:arm services/app - -docker-push-codeabttle-arm: - docker push codebattle/codebattle:assets-image-arm - docker push codebattle/codebattle:compile-image-arm - docker push codebattle/codebattle:arm - docker push codebattle/nginx-assets:arm - -docker-push-codebattle: - docker push codebattle/codebattle:assets-image - docker push codebattle/codebattle:compile-image - docker push codebattle/codebattle:latest - docker push codebattle/nginx-assets:latest - -docker-build-runner: - # docker pull codebattle/runner:compile-image || true - # docker pull codebattle/runner:latest || true - docker build --target compile-image \ - --file services/app/Dockerfile.runner \ - --tag codebattle/runner:compile-image services/app - docker build --target runtime-image \ - --file services/app/Dockerfile.runner \ - --tag codebattle/runner:latest services/app - -docker-push-runner: - docker push codebattle/runner:compile-image - docker push codebattle/runner:latest + --cache-from type=registry,ref=ghcr.io/hexlet-codebattle/runner:compile-cache \ + --cache-from type=registry,ref=ghcr.io/hexlet-codebattle/runner:runtime-cache \ + $(if $(DISABLE_CACHE_EXPORT),,--cache-to type=registry,ref=ghcr.io/hexlet-codebattle/runner:runtime-cache,mode=max) \ + --cache-from ghcr.io/hexlet-codebattle/runner:compile-image \ + --cache-from ghcr.io/hexlet-codebattle/runner:latest \ + --build-arg BUILDKIT_INLINE_CACHE=1 \ + --tag ghcr.io/hexlet-codebattle/runner:latest . + +push-runner: + docker push ghcr.io/hexlet-codebattle/runner:compile-image + docker push ghcr.io/hexlet-codebattle/runner:latest + + +runner-ruby: + docker run --rm -p 4040:4040 \ + --cap-add=SYS_ADMIN \ + --cap-add=SYS_CHROOT \ + --security-opt=no-new-privileges=false \ + ghcr.io/hexlet-codebattle/ruby:4.0.1 + +runner-cpp: + docker run --rm -p 4040:4040 \ + --cap-add=SYS_ADMIN \ + --cap-add=SYS_CHROOT \ + --security-opt=no-new-privileges=false \ + ghcr.io/hexlet-codebattle/cpp:23 + +runner-swift: + docker run --rm -p 4040:4040 \ + --cap-add=SYS_ADMIN \ + --cap-add=SYS_CHROOT \ + --security-opt=no-new-privileges=false \ + ghcr.io/hexlet-codebattle/swift:6.2.3 + +runner-kotlin: + docker run --rm -p 4040:4040 \ + --cap-add=SYS_ADMIN \ + --cap-add=SYS_CHROOT \ + --security-opt=no-new-privileges=false \ + ghcr.io/hexlet-codebattle/kotlin:2.3.0 + +runner-js: + docker run --rm -p 4040:4040 \ + --cap-add=SYS_ADMIN \ + --cap-add=SYS_CHROOT \ + --security-opt=no-new-privileges=false \ + ghcr.io/hexlet-codebattle/js:25.4.0 + +runner-dart: + docker run --rm -p 4040:4040 \ + --cap-add=SYS_ADMIN \ + --cap-add=SYS_CHROOT \ + --security-opt=no-new-privileges=false \ + ghcr.io/hexlet-codebattle/dart:3.10.0 + +runner-csharp: + docker run --rm -p 4040:4040 \ + --cap-add=SYS_ADMIN \ + --cap-add=SYS_CHROOT \ + --security-opt=no-new-privileges=false \ + ghcr.io/hexlet-codebattle/csharp:10.0.102 + +runner-clojure: + docker run --rm -p 4040:4040 \ + --cap-add=SYS_ADMIN \ + --cap-add=SYS_CHROOT \ + --security-opt=no-new-privileges=false \ + ghcr.io/hexlet-codebattle/clojure:1.12.4 + +runner-elixir: + docker run --rm -p 4040:4040 \ + --cap-add=SYS_ADMIN \ + --cap-add=SYS_CHROOT \ + --security-opt=no-new-privileges=false \ + ghcr.io/hexlet-codebattle/elixir:1.19.5 + +runner-golang: + docker run --rm -p 4040:4040 \ + --cap-add=SYS_ADMIN \ + --cap-add=SYS_CHROOT \ + --security-opt=no-new-privileges=false \ + ghcr.io/hexlet-codebattle/golang:1.25.6 + +runner-php: + docker run --rm -p 4040:4040 \ + --cap-add=SYS_ADMIN \ + --cap-add=SYS_CHROOT \ + --security-opt=no-new-privileges=false \ + ghcr.io/hexlet-codebattle/php:8.5.2 + +runner-java: + docker run --rm -p 4040:4040 \ + --cap-add=SYS_ADMIN \ + --cap-add=SYS_CHROOT \ + --security-opt=no-new-privileges=false \ + ghcr.io/hexlet-codebattle/java:25.0.2 + +runner-zig: + docker run --rm -p 4040:4040 \ + --cap-add=SYS_ADMIN \ + --cap-add=SYS_CHROOT \ + --security-opt=no-new-privileges=false \ + ghcr.io/hexlet-codebattle/zig:0.15.2 + +runner-rust: + docker run --rm -p 4040:4040 \ + --cap-add=SYS_ADMIN \ + --cap-add=SYS_CHROOT \ + --security-opt=no-new-privileges=false \ + ghcr.io/hexlet-codebattle/rust:1.93.0 diff --git a/README.md b/README.md index e38d8086b..30f2f0441 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,9 @@ [![Actions Status](https://github.com/hexlet-codebattle/codebattle/workflows/Build%20master/badge.svg)](https://github.com/hexlet-codebattle/codebattle/actions) [![codecov](https://codecov.io/gh/hexlet-codebattle/codebattle/branch/master/graph/badge.svg)](https://codecov.io/gh/hexlet-codebattle/codebattle) -[![Maintainability](https://api.codeclimate.com/v1/badges/a99a88d28ad37a79dbf6/maintainability)](https://codeclimate.com/github/hexlet-codebattle/codebattle/maintainability) -[![codebeat badge](https://codebeat.co/badges/7557979e-74a7-45a6-b9ab-dcd44bab7e5b)](https://codebeat.co/projects/github-com-hexlet-codebattle-codebattle-master) -[![Hits](https://hits.seeyoufarm.com/api/count/incr/badge.svg?url=https%3A%2F%2Fgithub.com%2Fhexlet-codebattle%2Fcodebattle&count_bg=%2379C83D&title_bg=%23555555&icon=&icon_color=%23E7E7E7&title=hits&edge_flat=false)](https://hits.seeyoufarm.com) Codebattle - is an open source game being developed by the Hexlet community. The current version of the application is available at [codebattle.hexlet.io](https://codebattle.hexlet.io). -We also have [chrome extension](https://chrome.google.com/webstore/detail/codebattle-web-extension/embfhnfkfobkdohleknckodkmhgmpdli). Which allow to subscribe on last game updates. This project exists thanks to all the people who contribute. [Contribute guideline.](CONTRIBUTING.md) @@ -19,7 +15,7 @@ This project exists thanks to all the people who contribute. [Contribute guideli ### Requirements - Mac / Linux -- docker +- Docker ### Install @@ -59,26 +55,19 @@ $ make compose-lint-js-fix ```bash $ mix upload_langs -$ mix dockers.push # all -$ mix dockers.push elixir +$ mix images.push # all +$ mix images.push elixir -$ mix dockers.build # all -$ mix dockers.build elixir +$ mix images.build # all +$ mix images.build elixir -$ mix dockers.pull # all -$ mix dockers.pull elixir +$ mix images.pull # all +$ mix images.pull elixir -$ mix asserts.upload # Pulls from battle_asserts all issues and upserts into DB - -#If you use docker in dev env, run commands in make compose-bash +#If you use images in dev env, run commands in make compose-bash ``` ### Profile js bundle -To build stat.json and see details in browser run: -``` -yarn profile:build -yarn profile:visualize -``` ### Support @@ -87,45 +76,61 @@ yarn profile:visualize ### Troubleshooting -- Install and run docker - -Make sure you have installed `docker` for your OS. +#### macOS -https://docs.docker.com/install/ +- Install Docker -Make sure your docker daemon is running. You can run it manually by typing: +Make sure you have installed Docker Desktop for macOS. -``` -sudo dockerd +```bash +brew install --cask docker ``` -or you can add it to startup by typing: +Or download Docker Desktop directly from: https://www.docker.com/products/docker-desktop -``` -sudo systemctl enable docker -``` +- Start Docker Desktop -Close and open your terminal if docker daemon didn't start immediately. +Launch Docker Desktop from your Applications folder. The Docker icon will appear in your menu bar when it's running. -- Manage Docker as a non-root user +If you encounter issues, try restarting Docker Desktop from the menu bar icon or your Applications folder. -https://docs.docker.com/install/linux/linux-postinstall/ +Docker Desktop will start automatically on boot by default. You can change this in Docker Desktop preferences if needed. -Create the docker group. +#### Linux -``` -sudo groupadd docker +- Install Docker + +Make sure you have installed Docker Engine for your Linux distribution. + +Follow the official installation guide: https://docs.docker.com/engine/install/ + +- Start Docker service + +Make sure Docker is running. You can start the Docker service manually by typing: + +```bash +sudo systemctl start docker ``` -Add your user to the docker group. +or you can add it to startup by typing: +```bash +sudo systemctl enable docker ``` + +- Add your user to the docker group + +To run Docker without sudo, add your user to the docker group: + +```bash sudo usermod -aG docker $USER ``` -## Star History +Then log out and log back in for the changes to take effect, or run: -[![Star History Chart](https://api.star-history.com/svg?repos=hexlet-codebattle/codebattle&type=Date)](https://star-history.com/#hexlet-codebattle/codebattle&Date) +```bash +newgrp docker +``` --- diff --git a/TOURNAMENTS_EN.md b/TOURNAMENTS_EN.md deleted file mode 100644 index 7cee1da37..000000000 --- a/TOURNAMENTS_EN.md +++ /dev/null @@ -1,56 +0,0 @@ -# Tournaments - -## 1. What are tournaments in Codebattle? - -A tournament in Codebattle is a true arena for programmers, where the passion for coding meets the thrill of competition. Each match is a race against time between two players solving the same task. Imagine this: not only are you writing code, but you can also see how your opponent is doing it. You can peek at their ideas, but they can do the same to you! This creates a unique tension as both players see the results of their checks and the timer mercilessly counting down the remaining time. The winner is the one who solves the task faster and more accurately, but one wrong move can cost you the victory. - -## 2. General Settings - -Each tournament is a unique event with its own settings, but there are general parameters that make the game fair and interesting: - -- **Supported programming languages**: Ruby, JavaScript (Node.js), TypeScript, Dart, C++, Java, Kotlin, C#, Go, Elixir, Python, PHP, Clojure, Haskell, Rust. -- **Task difficulty**: Tasks of various difficulty levels are possible — Elementary, Easy, Medium, Hard. You can choose the difficulty of the tasks for the entire tournament or for individual rounds, allowing you to adapt the tournament to the level of participants. -- **Match timeout**: If no one wins within the set time, the match is counted as a draw. This adds an element of urgency, making every minute precious. -- **Chat**: The ability to discuss strategies and communicate with other participants. -- **Live leaderboard**: Results are displayed in real-time, so you can immediately see who is leading. -- **Individual and team scoring**: In each type of tournament, you can choose individual scoring or pre-group participants into teams to display an overall team score. -- **Match history**: Each match is recorded on the server, and you can always review the entire game history. The recording shows who wrote the code, how quickly the tasks were completed, and what decisions were made. This is a great way to analyze the game and improve your skills. -- **Bots**: Virtual players, or bots, are used to maintain balance in the tournament. They are trained to solve tasks and adjust to the level of real participants, ensuring equal conditions for everyone. Bots can participate in matches when there aren’t enough real players or to create additional competition. -- **Player statistics**: Detailed statistics are collected for each player, including the average time to solve tasks, the number of wins and losses. This allows players to track their progress and compare themselves with other participants. - -## 3. Types of Tournaments - -### Individual - -- **Description**: A knockout tournament where each match is a duel, and the winner advances. -- **How it works**: A bracket is created at the start of the tournament, with players paired off. In each round, participants face off one-on-one, and the winners move on to the next stage. The tournament continues until the final, where the absolute champion is determined. -- **How we supplement participants**: Only 2, 4, 8, 16, 32, 64, or 128 players are supported. If there are fewer participants, we add bots to ensure full competition. -- **Who it's for**: For those who want to feel like a gladiator in the coding world, advancing from round to round toward the coveted victory. - -### Team - -- **Description**: A battle between two teams, where each player is an important part of the overall success. -- **How it works**: Two teams battle through several rounds, aiming to score a certain number of points. In each round, team members conduct individual matches. A win in a round earns the team 1 point, a draw gives each team 0.5 points. The tournament ends when one of the teams reaches the set number of points. -- **How we supplement participants**: If there aren't enough teams for fair competition, we add bots. -- **Who it's for**: For those who value teamwork and strategic thinking, ready to achieve victory together with the team. - -### Arena - -- **Description**: A dynamic, endless tournament where players can join and leave at any time. -- **How it works**: In an arena tournament, you can specify the number of rounds, round timeout, and match time in advance. Players start battling in the initial rounds, and as the tournament progresses, the system tries to match winners with winners and losers with losers. This allows each player to face an opponent of their level after a few rounds. Consolation points can also be awarded — if a player loses the match but managed to partially solve the task (e.g., solved 90% of the task), they will receive 90% of the winner's points. If the solution covers only 10% of the task, they will receive 10% of the winner's points. The difficulty level of the tasks and the time allotted to solve them may change from round to round, adding an additional element of strategy. -- **How we supplement participants**: If there aren’t enough participants to ensure fair play, we add bots to maintain balance. -- **Who it's for**: For those who love dynamic competitions with the opportunity to test their skills at different levels. - -### Swiss - -- **Description**: A Swiss-system tournament where participants play several rounds, meeting opponents with similar levels of success in each round. -- **How it works**: In each round, participants are matched with those who have a similar number of wins, creating equal conditions for all players. The winner is determined after several rounds. -- **How we supplement participants**: If the number of players is odd, we add bots to ensure an equal number of matches. -- **Who it's for**: For those who want to test their strength in a tournament where each round brings new challenges, and the results of previous games affect future matches. - -### Versus - -- **Description**: A tournament where each participant competes one-on-one with a randomly determined opponent. -- **How it works**: Participants face off in duels, where the winner advances, and the loser is eliminated. The tournament continues until there is one champion. -- **How we supplement participants**: If there aren't enough participants for fair competition, we add bots. -- **Who it's for**: For those who love intense duels and are ready to fight for the champion title. diff --git a/TOURNAMENTS_RU.md b/TOURNAMENTS_RU.md deleted file mode 100644 index 659cf8460..000000000 --- a/TOURNAMENTS_RU.md +++ /dev/null @@ -1,56 +0,0 @@ -# Турниры - -## 1. Что такое турниры в Codebattle? - -Турнир в Codebattle — это настоящая арена для программистов, где страсть к кодированию встречается с азартом соревнования. Здесь каждый поединок — это гонка на скорость между двумя игроками, решающими одну и ту же задачу. Представьте себе: вы не только пишете код, но и видите, как это делает ваш соперник. Вы можете подсмотреть его идеи, но и он может сделать то же самое с вами! Это создает уникальное напряжение, когда оба игрока видят результаты своих проверок и таймер, неумолимо отсчитывающий оставшееся время. Побеждает тот, кто быстрее и точнее решит задачу, но один неверный шаг может стоить вам победы. - -## 2. Общие настройки - -Каждый турнир — это уникальное событие со своими настройками, но есть общие параметры, которые делают игру честной и интересной: - -- **Поддерживаемые языки программирования**: Ruby, JavaScript (Node.js), TypeScript, Dart, C++, Java, Kotlin, C#, Go, Elixir, Python, PHP, Clojure, Haskell, Rust. -- **Сложность задач**: Возможны задачи различных уровней сложности — Elementary, Easy, Medium, Hard. Можно выбрать сложность задач на весь турнир или на отдельные раунды, что позволяет адаптировать турнир под уровень участников. -- **Таймаут матча**: Если никто не достиг победы в установленное время, матч засчитывается как ничья. Это добавляет элемент срочности и делает каждую минуту на вес золота. -- **Чат**: Возможность обсудить стратегии и пообщаться с другими участниками. -- **Живая таблица с рейтингом**: В реальном времени отображаются результаты, и вы сразу видите, кто идет впереди. -- **Индивидуальный и командный зачет**: В каждом типе турниров можно выбрать индивидуальный зачет или заранее объединить участников в команды, чтобы показать общий командный зачет. -- **История матчей**: Каждый матч-поединок записывается на сервер, и вы всегда можете пересмотреть всю историю игр. В записи видно, кто и как писал код, с какой скоростью выполнялись задачи и какие решения принимались. Это отличный способ проанализировать игру и улучшить свои навыки. -- **Боты**: Для поддержания баланса в турнире используются виртуальные игроки, или боты. Они обучены решать задачи и подстраиваются под уровень реальных участников, обеспечивая равные условия для всех. Боты могут участвовать в матчах, когда не хватает реальных игроков, или чтобы создать дополнительную конкуренцию. -- **Статистика игроков**: По каждому игроку собирается подробная статистика, включая среднее время решения задач, количество побед и поражений. Это позволяет игрокам отслеживать свой прогресс и сравнивать себя с другими участниками. - -## 3. Типы турниров - -### Individual - -- **Описание**: Турнир на выбывание, где каждый матч — это дуэль, а победитель идет дальше. -- **Как это работает**: В начале турнира создается сетка, где игроки распределяются по парам. В каждом раунде участники сражаются один на один, и победители проходят в следующий этап. Турнир продолжается до финала, где определится абсолютный чемпион. -- **Как мы дополняем участников**: Поддерживаются только 2, 4, 8, 16, 32, 64 или 128 игроков. Если участников меньше, мы добавляем ботов, чтобы обеспечить полноценную конкуренцию. -- **Кому это подходит**: Для тех, кто хочет почувствовать себя гладиатором в мире кода, проходя от раунда к раунду к заветной победе. - -### Team - -- **Описание**: Это сражение двух команд, где каждый игрок — важная часть общего успеха. -- **Как это работает**: Две команды сражаются в нескольких раундах, стремясь набрать определенное количество баллов. В каждом раунде игроки команд проводят одиночные матчи. Победа в раунде приносит команде 1 балл, ничья — по 0,5 балла каждой команде. Турнир завершается, когда одна из команд достигает заданного числа баллов. -- **Как мы дополняем участников**: Если команд недостаточно для создания равных условий, мы добавляем ботов. -- **Кому это подходит**: Для тех, кто ценит командную работу и стратегическое мышление, кто готов идти к победе вместе с командой. - -### Arena - -- **Описание**: Динамичный, бесконечный турнир, где игроки могут входить и выходить в любое время. -- **Как это работает**: В турнире арена заранее можно указать количество раундов, таймаут на раунд и время матча. Игроки начинают сражаться в первых раундах, и по мере прохождения турнира система старается матчить победителей с победителями, а проигравших с проигравшими. Это позволяет каждому игроку через несколько раундов встретиться с соперником своего уровня. Также возможно начисление утешительных баллов — если игрок проиграл матч, но сумел частично решить задачу (например, решил 90% задачи), он получит 90% от баллов победителя. Если же решение покрывает только 10% задачи, то он получит 10% очков победителя. Уровень сложности задач и время на их решение могут меняться от раунда к раунду, добавляя дополнительный элемент стратегии. -- **Как мы дополняем участников**: Если участников недостаточно, чтобы обеспечить честную игру, мы добавляем ботов, чтобы сохранить баланс. -- **Кому это подходит**: Для тех, кто любит динамичные соревнования с возможностью тестировать свои навыки на разных уровнях. - -### Swiss - -- **Описание**: Турнир по швейцарской системе, где участники играют несколько раундов, и каждый раунд они встречаются с соперниками, имеющими схожий уровень успеха. -- **Как это работает**: В каждом раунде участники матчатся с теми, кто имеет аналогичное количество побед, что создает равные условия для всех игроков. По итогам нескольких раундов определяется победитель. -- **Как мы дополняем участников**: Если количество игроков нечетное, мы добавляем ботов, чтобы обеспечить равное количество матчей. -- **Кому это подходит**: Для тех, кто хочет испытать свои силы в турнире, где каждый раунд приносит новые вызовы, а результаты предыдущих игр влияют на будущие матчи. - -### Versus - -- **Описание**: Турнир, где каждый участник сражается один на один с соперником, определяемым в случайном порядке. -- **Как это работает**: Участники встречаются в дуэлях, где победитель продвигается дальше, а проигравший выбывает. Турнир продолжается, пока не останется один чемпион. -- **Как мы дополняем участников**: Если участников недостаточно для честной конкуренции, мы добавляем ботов. -- **Кому это подходит**: Для тех, кто любит напряженные дуэли и готов к битве за титул чемпиона. diff --git a/ansible/development/group_vars/all/vars.yml b/ansible/development/group_vars/all/vars.yml index 7d0532b5f..35fb705f4 100644 --- a/ansible/development/group_vars/all/vars.yml +++ b/ansible/development/group_vars/all/vars.yml @@ -14,4 +14,3 @@ codebattle_onesignal_app_id: "5857921a-703b-4231-9e0a-bc3e0bb385bb" codebattle_onesignal_api_key: "NWFkNDczNGUtYTUwZC00ZWI5LWFjNDUtNzlkYzU3YjVlYzA2" codebattle_firebase_api_key: "0" codebattle_firebase_messaging_sender_id: "1" -codebattle_rollbar_api_key: "2" diff --git a/ansible/production/group_vars/all/vars.yml b/ansible/production/group_vars/all/vars.yml index 1a57bea3d..b95c47476 100644 --- a/ansible/production/group_vars/all/vars.yml +++ b/ansible/production/group_vars/all/vars.yml @@ -19,4 +19,3 @@ codebattle_onesignal_app_id: "{{ vault_codebattle_onesignal_app_id }}" codebattle_onesignal_api_key: "{{ vault_codebattle_onesignal_api_key }}" codebattle_firebase_api_key: "{{ vault_codebattle_firebase_api_key }}" codebattle_firebase_messaging_sender_id: "{{ vault_codebattle_firebase_messaging_sender_id }}" -codebattle_rollbar_api_key: "{{ vault_codebattle_rollbar_api_key }}" diff --git a/ansible/templates/environment.j2 b/ansible/templates/environment.j2 index 804dc4847..0ae85a138 100644 --- a/ansible/templates/environment.j2 +++ b/ansible/templates/environment.j2 @@ -14,4 +14,3 @@ ONESIGNAL_APP_ID={{ codebattle_onesignal_app_id }} ONESIGNAL_API_KEY={{ codebattle_onesignal_api_key }} FIREBASE_API_KEY={{ codebattle_firebase_api_key }} FIREBASE_SENDER_ID={{ codebattle_firebase_messaging_sender_id }} -ROLLBAR_API_KEY={{ codebattle_rollbar_api_key }} diff --git a/ansible/templates/secrets.auto.tfvars.j2 b/ansible/templates/secrets.auto.tfvars.j2 index 9a1a39231..71f7f9230 100644 --- a/ansible/templates/secrets.auto.tfvars.j2 +++ b/ansible/templates/secrets.auto.tfvars.j2 @@ -19,4 +19,3 @@ onesignal_api_key = "{{ codebattle_onesignal_api_key }}" onesignal_app_id = "{{ codebattle_onesignal_app_id }}" firebase_api_key = "{{ codebattle_firebase_api_key }}" firebase_sender_id = "{{ codebattle_firebase_messaging_sender_id }}" -rollbar_api_key = "{{ codebattle_rollbar_api_key }}" diff --git a/services/app/apps/codebattle/.formatter.exs b/apps/codebattle/.formatter.exs similarity index 100% rename from services/app/apps/codebattle/.formatter.exs rename to apps/codebattle/.formatter.exs diff --git a/apps/codebattle/.gitignore b/apps/codebattle/.gitignore new file mode 100644 index 000000000..fcb300e4b --- /dev/null +++ b/apps/codebattle/.gitignore @@ -0,0 +1,64 @@ +# App artifacts +_build +deps +db +.idea +*.ez +*.retry +*.log +tmp +*.elixir_ls/ +*deployment.retry +*~ +*.swp +*.swo +.vscode +**/__pycache__ +# Generated on crash by the VM +erl_crash.dump + +# Static artifacts +node_modules + +# KaTeX fonts (copied from node_modules) +/assets/static/fonts/katex + +# Since we are building assets from web/static, +# we ignore priv/static. You may want to comment +# this depending on your deployment strategy. +/priv/static + +# The config/prod.secret.exs file by default contains sensitive +# data and you should not commit it into version control. +# +# Alternatively, you may comment the line below and commit the +# secrets file as long as you replace its contents by environment +# variables. +config/prod.secret.exs +tags +.vagrant +*.DS_Store +.env +.deliver/config + +# Generated reports +cover +.deliver/releases/ +.tern-port +*.backup +.terraform +secrets.auto.tfvars +.cache-loader +*.tfstate +*.secret.yml +.elixir_ls +google.key.json +.iml + +.kube/ +kubeconfig.yml + +stats.json +*.hcl +priv/plts/*.plt +priv/plts/*.plt.hash diff --git a/apps/codebattle/.oxlintrc.json b/apps/codebattle/.oxlintrc.json new file mode 100644 index 000000000..d1d67d949 --- /dev/null +++ b/apps/codebattle/.oxlintrc.json @@ -0,0 +1,34 @@ +{ + "$schema": "./node_modules/oxlint/configuration_schema.json", + "plugins": [ + "react", + "jsx-a11y", + "jest" + ], + "categories": { + "correctness": "error", + "suspicious": "error" + }, + "rules": { + "no-console": "off", + "no-unused-vars": "off", + "preserve-caught-error": "off", + "react-hooks/exhaustive-deps": "warn", + "react/jsx-key": "off", + "react/iframe-missing-sandbox": "off", + "jsx-a11y/no-autofocus": "off", + "jsx-a11y/prefer-tag-over-role": "off", + "jsx-a11y/role-has-required-aria-props": "off" + }, + "settings": {}, + "env": { + "builtin": true, + "browser": true, + "node": true, + "jest": true + }, + "globals": {}, + "ignorePatterns": [ + "assets/js/monaco-workers/*.js" + ] +} diff --git a/apps/codebattle/.stylelintrc.json b/apps/codebattle/.stylelintrc.json new file mode 100644 index 000000000..01cc3a585 --- /dev/null +++ b/apps/codebattle/.stylelintrc.json @@ -0,0 +1,15 @@ +{ + "customSyntax": "postcss-scss", + "rules": { + "at-rule-no-unknown": null, + "declaration-block-no-duplicate-properties": [ + true, + { + "ignore": [ + "consecutive-duplicates-with-different-values" + ] + } + ], + "no-duplicate-selectors": true + } +} diff --git a/apps/codebattle/assets/css/_fonts.scss b/apps/codebattle/assets/css/_fonts.scss new file mode 100644 index 000000000..20e8d8e50 --- /dev/null +++ b/apps/codebattle/assets/css/_fonts.scss @@ -0,0 +1,28 @@ +// Source Code Pro + Montserrat are loaded non-render-blocking from the document +// via CodebattleWeb.LayoutView.google_fonts_head/0 (preconnect + async +// stylesheet). Importing them here would put them back on the critical path. + +@font-face { + font-family: 'pixy'; + src: url('../static/fonts/pixy.otf'); /* IE9 Compat Modes */ + src: + url('../static/fonts/pixy.ttf') format('truetype'), + /* Safari, Android, iOS */ url('../static/fonts/pixy.woff') format('woff'); /* Modern Browsers */ +} + +@font-face { + font-family: 'IBM Plex Mono'; + font-style: normal; + font-weight: 400; + src: url(https://fonts.gstatic.com/s/ibmplexmono/v19/-F63fjptAgt5VM-kVkqdyU8n1i8q131nj-o.woff2) + format('woff2'); + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, + U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, + U+2212, U+2215, U+FEFF, U+FFFD; +} + +@font-face { + font-family: 'cb-display-bold'; + src: url('../static/fonts/CBDisplayBold.ttf'); +} diff --git a/apps/codebattle/assets/css/_katex-fonts.scss b/apps/codebattle/assets/css/_katex-fonts.scss new file mode 100644 index 000000000..73d51f128 --- /dev/null +++ b/apps/codebattle/assets/css/_katex-fonts.scss @@ -0,0 +1,202 @@ +// Override KaTeX font paths to use fonts served from our static directory +// This file should be imported AFTER katex.min.css to override the @font-face declarations + +@font-face { + font-family: KaTeX_AMS; + font-style: normal; + font-weight: 400; + src: + url('/fonts/katex/KaTeX_AMS-Regular.woff2') format('woff2'), + url('/fonts/katex/KaTeX_AMS-Regular.woff') format('woff'), + url('/fonts/katex/KaTeX_AMS-Regular.ttf') format('truetype'); +} + +@font-face { + font-family: KaTeX_Caligraphic; + font-style: normal; + font-weight: 700; + src: + url('/fonts/katex/KaTeX_Caligraphic-Bold.woff2') format('woff2'), + url('/fonts/katex/KaTeX_Caligraphic-Bold.woff') format('woff'), + url('/fonts/katex/KaTeX_Caligraphic-Bold.ttf') format('truetype'); +} + +@font-face { + font-family: KaTeX_Caligraphic; + font-style: normal; + font-weight: 400; + src: + url('/fonts/katex/KaTeX_Caligraphic-Regular.woff2') format('woff2'), + url('/fonts/katex/KaTeX_Caligraphic-Regular.woff') format('woff'), + url('/fonts/katex/KaTeX_Caligraphic-Regular.ttf') format('truetype'); +} + +@font-face { + font-family: KaTeX_Fraktur; + font-style: normal; + font-weight: 700; + src: + url('/fonts/katex/KaTeX_Fraktur-Bold.woff2') format('woff2'), + url('/fonts/katex/KaTeX_Fraktur-Bold.woff') format('woff'), + url('/fonts/katex/KaTeX_Fraktur-Bold.ttf') format('truetype'); +} + +@font-face { + font-family: KaTeX_Fraktur; + font-style: normal; + font-weight: 400; + src: + url('/fonts/katex/KaTeX_Fraktur-Regular.woff2') format('woff2'), + url('/fonts/katex/KaTeX_Fraktur-Regular.woff') format('woff'), + url('/fonts/katex/KaTeX_Fraktur-Regular.ttf') format('truetype'); +} + +@font-face { + font-family: KaTeX_Main; + font-style: normal; + font-weight: 700; + src: + url('/fonts/katex/KaTeX_Main-Bold.woff2') format('woff2'), + url('/fonts/katex/KaTeX_Main-Bold.woff') format('woff'), + url('/fonts/katex/KaTeX_Main-Bold.ttf') format('truetype'); +} + +@font-face { + font-family: KaTeX_Main; + font-style: italic; + font-weight: 700; + src: + url('/fonts/katex/KaTeX_Main-BoldItalic.woff2') format('woff2'), + url('/fonts/katex/KaTeX_Main-BoldItalic.woff') format('woff'), + url('/fonts/katex/KaTeX_Main-BoldItalic.ttf') format('truetype'); +} + +@font-face { + font-family: KaTeX_Main; + font-style: italic; + font-weight: 400; + src: + url('/fonts/katex/KaTeX_Main-Italic.woff2') format('woff2'), + url('/fonts/katex/KaTeX_Main-Italic.woff') format('woff'), + url('/fonts/katex/KaTeX_Main-Italic.ttf') format('truetype'); +} + +@font-face { + font-family: KaTeX_Main; + font-style: normal; + font-weight: 400; + src: + url('/fonts/katex/KaTeX_Main-Regular.woff2') format('woff2'), + url('/fonts/katex/KaTeX_Main-Regular.woff') format('woff'), + url('/fonts/katex/KaTeX_Main-Regular.ttf') format('truetype'); +} + +@font-face { + font-family: KaTeX_Math; + font-style: italic; + font-weight: 700; + src: + url('/fonts/katex/KaTeX_Math-BoldItalic.woff2') format('woff2'), + url('/fonts/katex/KaTeX_Math-BoldItalic.woff') format('woff'), + url('/fonts/katex/KaTeX_Math-BoldItalic.ttf') format('truetype'); +} + +@font-face { + font-family: KaTeX_Math; + font-style: italic; + font-weight: 400; + src: + url('/fonts/katex/KaTeX_Math-Italic.woff2') format('woff2'), + url('/fonts/katex/KaTeX_Math-Italic.woff') format('woff'), + url('/fonts/katex/KaTeX_Math-Italic.ttf') format('truetype'); +} + +@font-face { + font-family: KaTeX_SansSerif; + font-style: normal; + font-weight: 700; + src: + url('/fonts/katex/KaTeX_SansSerif-Bold.woff2') format('woff2'), + url('/fonts/katex/KaTeX_SansSerif-Bold.woff') format('woff'), + url('/fonts/katex/KaTeX_SansSerif-Bold.ttf') format('truetype'); +} + +@font-face { + font-family: KaTeX_SansSerif; + font-style: italic; + font-weight: 400; + src: + url('/fonts/katex/KaTeX_SansSerif-Italic.woff2') format('woff2'), + url('/fonts/katex/KaTeX_SansSerif-Italic.woff') format('woff'), + url('/fonts/katex/KaTeX_SansSerif-Italic.ttf') format('truetype'); +} + +@font-face { + font-family: KaTeX_SansSerif; + font-style: normal; + font-weight: 400; + src: + url('/fonts/katex/KaTeX_SansSerif-Regular.woff2') format('woff2'), + url('/fonts/katex/KaTeX_SansSerif-Regular.woff') format('woff'), + url('/fonts/katex/KaTeX_SansSerif-Regular.ttf') format('truetype'); +} + +@font-face { + font-family: KaTeX_Script; + font-style: normal; + font-weight: 400; + src: + url('/fonts/katex/KaTeX_Script-Regular.woff2') format('woff2'), + url('/fonts/katex/KaTeX_Script-Regular.woff') format('woff'), + url('/fonts/katex/KaTeX_Script-Regular.ttf') format('truetype'); +} + +@font-face { + font-family: KaTeX_Size1; + font-style: normal; + font-weight: 400; + src: + url('/fonts/katex/KaTeX_Size1-Regular.woff2') format('woff2'), + url('/fonts/katex/KaTeX_Size1-Regular.woff') format('woff'), + url('/fonts/katex/KaTeX_Size1-Regular.ttf') format('truetype'); +} + +@font-face { + font-family: KaTeX_Size2; + font-style: normal; + font-weight: 400; + src: + url('/fonts/katex/KaTeX_Size2-Regular.woff2') format('woff2'), + url('/fonts/katex/KaTeX_Size2-Regular.woff') format('woff'), + url('/fonts/katex/KaTeX_Size2-Regular.ttf') format('truetype'); +} + +@font-face { + font-family: KaTeX_Size3; + font-style: normal; + font-weight: 400; + src: + url('/fonts/katex/KaTeX_Size3-Regular.woff2') format('woff2'), + url('/fonts/katex/KaTeX_Size3-Regular.woff') format('woff'), + url('/fonts/katex/KaTeX_Size3-Regular.ttf') format('truetype'); +} + +@font-face { + font-family: KaTeX_Size4; + font-style: normal; + font-weight: 400; + src: + url('/fonts/katex/KaTeX_Size4-Regular.woff2') format('woff2'), + url('/fonts/katex/KaTeX_Size4-Regular.woff') format('woff'), + url('/fonts/katex/KaTeX_Size4-Regular.ttf') format('truetype'); +} + +@font-face { + font-family: KaTeX_Typewriter; + font-style: normal; + font-weight: 400; + src: + url('/fonts/katex/KaTeX_Typewriter-Regular.woff2') format('woff2'), + url('/fonts/katex/KaTeX_Typewriter-Regular.woff') format('woff'), + url('/fonts/katex/KaTeX_Typewriter-Regular.ttf') format('truetype'); +} diff --git a/apps/codebattle/assets/css/_monaco-fonts.scss b/apps/codebattle/assets/css/_monaco-fonts.scss new file mode 100644 index 000000000..6b4229a9e --- /dev/null +++ b/apps/codebattle/assets/css/_monaco-fonts.scss @@ -0,0 +1,8 @@ +// Override Monaco Editor codicon font path +// The font is served from /codicon.ttf in both dev and production + +@font-face { + font-family: 'codicon'; + font-display: block; + src: url('/codicon.ttf') format('truetype'); +} diff --git a/services/app/apps/codebattle/assets/css/_variables.scss b/apps/codebattle/assets/css/_variables.scss similarity index 88% rename from services/app/apps/codebattle/assets/css/_variables.scss rename to apps/codebattle/assets/css/_variables.scss index 834cce4a2..9a6dbd156 100644 --- a/services/app/apps/codebattle/assets/css/_variables.scss +++ b/apps/codebattle/assets/css/_variables.scss @@ -1,4 +1,4 @@ -$font-family-base: "Source Code Pro", sans-serif; +$font-family-base: 'Source Code Pro', sans-serif; $sm: 575px; $md: 676px; diff --git a/apps/codebattle/assets/css/custom.scss b/apps/codebattle/assets/css/custom.scss new file mode 100644 index 000000000..e902680d3 --- /dev/null +++ b/apps/codebattle/assets/css/custom.scss @@ -0,0 +1,1292 @@ +.cb-custom-event-tr-border { + outline: none; + box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.06); + border-radius: 0.5rem; +} + +.cb-custom-event-tr-brown-border { + outline: none; + box-shadow: inset 0 0 0 1px rgba(255, 98, 30, 0.22); + border-radius: 0.5rem; +} + +.cb-custom-event-table .cb-custom-event-td:first-child { + border-top-left-radius: 0.6rem; + border-bottom-left-radius: 0.6rem; +} + +.cb-custom-event-table .cb-custom-event-td:last-child { + border-top-right-radius: 0.6rem; + border-bottom-right-radius: 0.6rem; +} + +.cb-custom-event-tr.selected { + color: #ec9d7c !important; +} + +.cb-custom-event-common-leaderboard-bg { + background-color: #d9d9d9; +} + +.cb-custom-event-tournaments-item:nth-child(odd) { + background-color: #f3f4f4; +} + +.cb-custom-event-name { + /* Adjust according to your needs */ + white-space: nowrap; + /* Prevent text from wrapping */ + overflow: hidden; + /* Hide the overflow text */ + text-overflow: ellipsis; + /* Display ellipsis for overflow text */ +} + +.cb-custom-event-td:not(:last-child)::after, +.cb-custom-event-nav-item:not(:first-child)::after { + content: ''; + position: absolute; + height: 40%; + width: 0.5px; + background-color: rgba(255, 255, 255, 0.02); +} + +.cb-custom-event-td:not(:last-child)::after { + right: 0; + top: 50%; + transform: translateY(-50%); +} + +.cb-custom-event-nav-item:not(:first-child):not(.active)::after { + left: 0; + top: 13px; +} + +.cb-custom-event-nav-item.active + .cb-custom-event-nav-item::after { + width: 0px; +} + +.cb-custom-event-badge-danger { + color: #fff; + background-color: #ff621e; +} + +.cb-custom-event-badge-success { + color: #212529; + background-color: #2ae881; +} + +.cb-custom-event-badge-secondary { + color: #fff; + background-color: #b6a4ff; +} + +.cb-custom-event-badge-warning { + color: #212529; + background-color: #ffe500; +} + +.cb-custom-event-bg { + background-color: #0c0f1e; +} + +.cb-custom-event-bg-success { + background-color: #203527; +} + +.cb-custom-event-bg-muted-success { + background-color: #18261d; +} + +.cb-custom-event-bg-purple { + background-color: #2a213a; +} + +.cb-custom-event-bg-muted-purple { + background-color: #201a2b; +} + +.cb-custom-event-bg-orange { + background-color: #3a2417; +} + +.cb-custom-event-bg-blue { + background-color: #1f2f3f; +} + +.cb-custom-event-bg-brown { + background-color: #3b2618; +} + +.cb-custom-event-pagination-page-item .cb-custom-event-pagination-page-link { + border: 1px solid transparent; + border-radius: 0.25rem; +} + +.cb-custom-event-pagination-page-link { + position: relative; + display: block; + margin-left: -1px; + line-height: 1.25; + color: white; +} + +.cb-task-advanced-panel { + gap: 0.75rem; +} + +.cb-task-advanced-card { + background: #121826; + border: 1px solid rgba(148, 163, 184, 0.12); + border-radius: 0.75rem; + padding: 0.75rem; + height: 100%; +} + +.cb-task-advanced-chart { + min-height: 180px; + max-height: 240px; +} + +.cb-task-advanced-card-title { + color: #cbd5e1; + font-size: 0.85rem; + font-weight: 600; + margin-bottom: 0.5rem; + text-transform: uppercase; + letter-spacing: 0.04em; +} + +.cb-task-advanced-task-name { + color: #e2e8f0; + font-weight: 600; +} + +.cb-task-advanced-table thead th { + color: #94a3b8; +} + +.cb-task-advanced-table tbody tr + tr td { + border-top: 1px solid rgba(148, 163, 184, 0.08); +} + +.cb-task-advanced-table .cb-custom-event-td { + background-color: transparent !important; +} + +.cb-task-advanced-link { + color: #93c5fd; +} + +.cb-task-advanced-link:hover { + color: #bfdbfe; +} + +.text-gold { + color: #c9a56c !important; +} + +.btn-gold { + color: #151823; + background-color: #c9a56c; + border-color: #c9a56c; +} + +.btn-gold:hover, +.btn-gold:focus { + color: #11131b; + background-color: #b89460; + border-color: #b89460; +} + +.btn-outline-gold { + color: #c9a56c; + border-color: #c9a56c; +} + +.btn-outline-gold:hover, +.btn-outline-gold:focus { + color: #11131b; + background-color: #c9a56c; + border-color: #c9a56c; +} + +.cb-hof-podium-card { + position: relative; + color: #e5e7eb; + overflow: hidden; +} + +.cb-hof-podium-card .card-title, +.cb-hof-podium-card .text-white, +.cb-hof-podium-card .fw-bold { + color: #f1f5f9 !important; +} + +.cb-hof-podium-card::before { + content: ''; + position: absolute; + inset: 0; + background: linear-gradient( + 180deg, + rgba(4, 6, 10, 0.35) 0%, + rgba(4, 6, 10, 0.75) 100% + ); + z-index: 0; +} + +.cb-hof-podium-card .card-body { + position: relative; + z-index: 1; +} + +.cb-hof-podium-card .text-info { + color: #cbd5e1 !important; +} + +.cb-season-leaderboard-filters { + background: linear-gradient( + 180deg, + rgba(16, 22, 34, 0.82) 0%, + rgba(14, 19, 29, 0.94) 100% + ); +} + +.cb-season-leaderboard-filters .cb-season-filter-label { + color: #a8b2c2 !important; + font-size: 0.72rem; + font-weight: 600; + letter-spacing: 0.04em; + text-transform: uppercase; +} + +.cb-seasons-hero { + background: + radial-gradient(circle at top, rgba(201, 165, 108, 0.12), transparent 42%), + linear-gradient( + 135deg, + rgba(42, 42, 53, 0.96) 0%, + rgba(23, 23, 32, 0.98) 100% + ); + border: 1px solid rgba(201, 165, 108, 0.12); +} + +.cb-seasons-eyebrow { + letter-spacing: 0.12em; +} + +.cb-seasons-title { + font-size: clamp(2.1rem, 4vw, 3.25rem); + line-height: 1.05; +} + +.cb-seasons-subtitle { + max-width: 36rem; +} + +.cb-seasons-hero-action, +.cb-seasons-action { + min-width: 148px; + justify-content: center; + white-space: nowrap; +} + +.cb-seasons-card { + background: + radial-gradient(circle at top, rgba(201, 165, 108, 0.08), transparent 35%), + linear-gradient( + 135deg, + rgba(26, 26, 26, 0.98) 0%, + rgba(10, 10, 10, 0.98) 100% + ); + min-height: 100%; +} + +.cb-seasons-card-header { + gap: 12px; +} + +.cb-seasons-card-kicker { + letter-spacing: 0.08em; +} + +.cb-seasons-card-title { + font-size: 2rem; + line-height: 1.05; +} + +.cb-seasons-card-dates { + font-size: 1rem; +} + +.cb-seasons-card-body { + padding-top: 1.5rem; +} + +.cb-seasons-podium-row { + min-height: 212px; + margin-bottom: 0; +} + +.cb-seasons-podium-offset-second { + margin-top: 1.5rem; +} + +.cb-seasons-podium-offset-third { + margin-top: 2rem; +} + +.cb-seasons-podium-card { + min-height: 172px; +} + +.cb-seasons-podium-card .card-body { + display: flex; + min-width: 0; + flex-direction: column; + align-items: center; + justify-content: center; +} + +.cb-seasons-podium-card-large { + min-height: 196px; +} + +.cb-seasons-podium-medal { + line-height: 1; +} + +.cb-seasons-podium-name, +.cb-seasons-podium-clan { + max-width: 100%; + overflow-wrap: anywhere; +} + +.cb-seasons-podium-name { + display: -webkit-box; + min-height: 2.4em; + overflow: hidden; + line-height: 1.2; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; +} + +.cb-seasons-podium-clan-wrap { + display: flex; + min-height: 2.6em; + align-items: center; +} + +.cb-seasons-podium-clan { + display: -webkit-box; + overflow: hidden; + line-height: 1.3; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; +} + +.cb-seasons-podium-points { + line-height: 1.2; +} + +.cb-seasons-empty { + background: linear-gradient( + 135deg, + rgba(42, 42, 53, 0.92) 0%, + rgba(23, 23, 32, 0.98) 100% + ); +} + +.cb-profile-heatmap-heading { + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + min-width: 0; +} + +.cb-profile-heatmap-title { + display: flex; + align-items: center; + justify-content: center; + flex-wrap: wrap; + gap: 0.35rem; + font-size: 0.78rem; + font-weight: 600; + color: #8f98a8; +} + +.cb-profile-heatmap-range { + font-size: 0.78rem; + font-weight: 500; + letter-spacing: 0.02em; + color: #8f98a8; +} + +.cb-profile-heatmap-separator { + font-size: 0.78rem; + opacity: 0.6; + flex: 0 0 auto; +} + +.cb-profile-heatmap-controls { + min-width: 176px; + margin-right: 0.75rem; +} + +.cb-profile-heatmap-select { + min-width: 176px; + height: 30px; + padding-top: 0.2rem; + padding-bottom: 0.2rem; + font-size: 0.76rem; + color: #aeb8c8 !important; + border-color: rgba(148, 163, 184, 0.24) !important; + background-color: rgba(26, 30, 42, 0.82) !important; +} + +.cb-profile-heatmap-grid-wrapper { + position: relative; +} + +.cb-profile-heatmap-grid { + width: 100%; + overflow-x: auto; + overflow-y: visible; + padding: 0.75rem 14px 0.25rem 6px; +} + +.cb-profile-heatmap-grid svg { + display: block; + width: 100%; + min-width: 0; + max-width: 100%; + height: auto; + overflow: visible; +} + +.cb-profile-heatmap-overlay { + position: absolute; + inset: 0; + display: flex; + align-items: center; + justify-content: center; + background: rgba(18, 21, 30, 0.38); + z-index: 1; +} + +.cb-profile-heatmap-tooltip { + position: absolute; + transform: translate(-50%, -100%); + padding: 0.3rem 0.55rem; + border-radius: 6px; + background-color: rgba(12, 15, 24, 0.96); + border: 1px solid rgba(148, 163, 184, 0.24); + color: #d6deeb; + font-size: 0.74rem; + line-height: 1.2; + pointer-events: none; + white-space: nowrap; + z-index: 2; + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.28); +} + +.cb-profile-heatmap .react-calendar-heatmap text { + font-size: 6px; +} + +.cb-profile-heatmap + .react-calendar-heatmap + .react-calendar-heatmap-month-label { + font-size: 7px; + font-weight: 600; +} + +.cb-profile-heatmap + .react-calendar-heatmap + .react-calendar-heatmap-weekday-label { + font-size: 7px; + font-weight: 500; +} + +.cb-profile-heatmap .react-calendar-heatmap rect { + width: 9px; + height: 9px; + rx: 2px; + ry: 2px; +} + +@media (max-width: 575.98px) { + .cb-seasons-hero { + padding-left: 1rem !important; + padding-right: 1rem !important; + } + + .cb-seasons-title { + font-size: 2rem; + } + + .cb-seasons-card-title { + font-size: 1.5rem; + } + + .cb-seasons-hero-action, + .cb-seasons-action { + width: 100%; + } + + .cb-seasons-card-body { + padding-top: 1rem; + } + + .cb-seasons-podium-row { + min-height: 178px; + margin-left: -0.25rem; + margin-right: -0.25rem; + } + + .cb-seasons-podium-row > [class*='col-'] { + padding-left: 0.25rem; + padding-right: 0.25rem; + } + + .cb-seasons-podium-card { + min-height: 154px; + } + + .cb-seasons-podium-card-large { + min-height: 166px; + } + + .cb-seasons-podium-card .card-body { + padding-left: 0.5rem; + padding-right: 0.5rem; + } + + .cb-seasons-podium-name { + font-size: 0.88rem; + } + + .cb-seasons-podium-clan { + font-size: 0.75rem; + } + + .cb-seasons-podium-clan-wrap { + min-height: 2.4em; + } + + .cb-seasons-podium-points { + font-size: 1rem !important; + } + + .cb-seasons-podium-offset-second { + margin-top: 0.75rem; + } + + .cb-seasons-podium-offset-third { + margin-top: 1rem; + } + + .cb-profile-heatmap-controls { + width: 100%; + margin-left: 0; + margin-right: 0; + } + + .cb-profile-heatmap-heading { + width: 100%; + } + + .cb-profile-heatmap-title { + font-size: 0.68rem; + } + + .cb-profile-heatmap-range { + font-size: 0.68rem; + } +} + +.cb-season-leaderboard-filters .cb-season-filter-input-group { + border-radius: 999px; + overflow: hidden; + box-shadow: inset 0 0 0 1px rgba(148, 163, 184, 0.28); + transition: box-shadow 0.2s ease; +} + +.cb-season-leaderboard-filters .cb-season-filter-input-group:focus-within { + box-shadow: + 0 0 0 0.2rem rgba(52, 180, 254, 0.2), + inset 0 0 0 1px rgba(52, 180, 254, 0.45); +} + +.cb-season-leaderboard-filters .cb-season-filter-prefix { + border: 0 !important; + background-color: rgba(32, 42, 60, 0.9) !important; + color: #8ea2be !important; + padding: 0 0.8rem; +} + +.cb-season-leaderboard-filters .cb-season-filter-control { + min-height: 2.25rem; + padding: 0.45rem 0.85rem; + border-radius: 999px !important; + border-color: rgba(148, 163, 184, 0.3) !important; + background-color: rgba(22, 29, 43, 0.94) !important; + color: #f1f5f9 !important; + font-size: 0.86rem; + transition: + border-color 0.2s ease, + box-shadow 0.2s ease, + background-color 0.2s ease; +} + +.cb-season-leaderboard-filters select.cb-season-filter-control { + padding-left: 1rem !important; + padding-inline-start: 1rem !important; + padding-right: 2.25rem !important; + background-position: right 0.8rem center; + text-indent: 0.1rem; +} + +.cb-season-leaderboard-filters .cb-season-filter-control::placeholder { + color: #7f8ea3; +} + +.cb-season-leaderboard-filters .cb-season-filter-control:hover { + border-color: rgba(148, 163, 184, 0.5) !important; + background-color: rgba(28, 36, 52, 0.96) !important; +} + +.cb-season-leaderboard-filters .cb-season-filter-control:focus { + border-color: rgba(52, 180, 254, 0.65) !important; + box-shadow: 0 0 0 0.2rem rgba(52, 180, 254, 0.18); + background-color: rgba(28, 36, 52, 0.98) !important; +} + +.cb-season-leaderboard-filters + .cb-season-filter-input-group + .cb-season-filter-control { + padding: 0.45rem 0.85rem; + border: 0 !important; + border-radius: 0 !important; +} + +.cb-season-leaderboard-filters .cb-season-filter-clear-btn { + border: 0; + background-color: rgba(32, 42, 60, 0.9); + color: #cbd5e1; + padding: 0 0.8rem; + display: inline-flex; + align-items: center; +} + +.cb-season-leaderboard-filters .cb-season-filter-clear-btn:hover, +.cb-season-leaderboard-filters .cb-season-filter-clear-btn:focus { + color: #fff; + background-color: rgba(52, 180, 254, 0.36); +} + +.cb-season-leaderboard-filters .cb-season-filter-reset-btn { + min-height: 2.25rem; + border-radius: 999px; + border-color: rgba(148, 163, 184, 0.36); + color: #c8d3e2; + background-color: rgba(22, 29, 43, 0.9); +} + +.cb-season-leaderboard-filters .cb-season-filter-reset-btn:hover, +.cb-season-leaderboard-filters .cb-season-filter-reset-btn:focus { + border-color: rgba(52, 180, 254, 0.64); + color: #fff; + background-color: rgba(52, 180, 254, 0.26); +} + +@media (max-width: 767.98px) { + .cb-season-leaderboard-filters { + padding-top: 1rem !important; + padding-bottom: 1rem !important; + } +} + +.cb-custom-event-pagination-page-item:first-child + .cb-custom-event-pagination-page-link, +.cb-custom-event-pagination-page-item:nth-child(2) + .cb-custom-event-pagination-page-link, +.cb-custom-event-pagination-page-item:nth-last-child(2) + .cb-custom-event-pagination-page-link, +.cb-custom-event-pagination-page-item:last-child + .cb-custom-event-pagination-page-link { + color: white; + background-color: #8c64ff; + border: 1px solid #8c64ff; +} + +.cb-custom-event-pagination-page-item.disabled + .cb-custom-event-pagination-page-link { + pointer-events: none; + cursor: auto; + background-color: #9f8ed4; + border-color: #9f8ed4; +} + +.cb-custom-event-pagination-page-item.active + .cb-custom-event-pagination-page-link { + z-index: 3; + color: white; + background-color: #8c64ff; + border: 1px solid #8c64ff; +} + +.cb-custom-event-pagination-page-item:not(.active):not(.disabled):hover + .cb-custom-event-pagination-page-link { + z-index: 3; + color: white; + background-color: #8c64ff; + border: 1px solid #8c64ff; +} + +.cb-ranking-page-btn { + width: 2rem; + height: 2rem; + padding: 0; + display: inline-flex; + align-items: center; + justify-content: center; +} + +.cb-ranking-pagination { + gap: 0.5rem; +} + +.cb-ranking-pagination .cb-ranking-page-btn { + margin: 0; +} + +.cb-ranking-pagination .cb-ranking-page-btn + .cb-ranking-page-btn { + margin-left: 0.4rem; +} + +.cb-custom-event-content { + position: relative; + z-index: 1; + max-width: 1180px; +} + +.cb-run-item-tooltip { + position: fixed; + transform: translateY(-50%); + white-space: nowrap; + background-color: #0c0f1e; + color: #ffffff; + border: 1px solid rgba(255, 255, 255, 0.15); + padding: 4px 8px; + border-radius: 6px; + font-size: 0.75rem; + pointer-events: none; + z-index: 1050; +} + +@keyframes cb-run-pending-pulse { + 0%, + 100% { + box-shadow: 0 0 0 0 rgba(245, 158, 11, 0.5); + } + + 50% { + box-shadow: 0 0 0 4px rgba(245, 158, 11, 0); + } +} + +.cb-run-pending { + animation: cb-run-pending-pulse 1.6s ease-in-out infinite; +} + +.btn-yellow { + background-color: #fffb47; + color: black; + border-radius: 999px; + font-weight: bold; + padding: 12px 24px; + transition: background-color 0.3s ease; + border: none; + + &:hover { + background-color: #e6e02b; + color: black; + } + + &:disabled { + opacity: 0.6; + } +} + +.cb-custom-event-stage-section { + background-color: #30333f; + border-radius: 25px; +} + +.cb-custom-event-stage-section:nth-child(even) { + background-color: #505360; +} + +.cb-custom-event-title { + font-family: 'External'; + font-weight: 700; + font-size: 74px; + line-height: 100%; + letter-spacing: -1%; + + max-width: 740px; +} + +.cb-custom-event-profile-data { + color: #f7f717; + + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + max-width: 70%; +} + +.cb-custom-event-table-action-button { + width: 20%; + + @media (max-width: $md) { + & { + width: 80%; + } + } +} + +.cb-custom-event-profile { + background-color: #30333f; + border-radius: 60px; + + padding-left: 30px; + padding-right: 30px; + padding-top: 16px; + padding-bottom: 16px; +} + +.cb-custom-event-text-success { + color: #2ae881; +} + +.cb-custom-event-text-danger { + color: #ff621e; +} + +.cb-custom-event-border-success { + border-color: #2a7053 !important; +} + +.cb-custom-event-border-info { + border-color: #34b4fe !important; +} + +.cb-custom-event-btn-success { + color: #212529; + background-color: #23bd6a; + border-color: #23bd6a; + + &:hover:not(:disabled) { + color: #ffffff; + background-color: #1c9755; + border-color: #1c9755; + } +} + +.cb-custom-event-btn-info { + color: #ffffff; + background-color: #34b4fe; + border-color: #34b4fe; + + &:hover:not(:disabled) { + color: #ffffff; + background-color: #0191e4; + border-color: #0191e4; + } +} + +.cb-custom-event-btn-primary, +.cb-custom-event-btn-secondary { + color: #ffffff; + background-color: #8566ff; + border-color: #8566ff; + + &:hover:not(:disabled) { + color: #ffffff; + background-color: #704dff; + border-color: #704dff; + } +} + +.cb-custom-event-btn-warning { + color: #212529; + background-color: #ff621e; + border-color: #ff621e; + + &:hover:not(:disabled) { + color: #212529; + background-color: #e64500; + border-color: #e64500; + } +} + +.cb-custom-event-btn-outline-success { + color: #2ae881; + border-color: #2ae881; + + &:hover:not(:disabled) { + color: #ffffff; + background-color: #2ae881; + border-color: #2ae881; + } +} + +.cb-custom-event-btn-outline-info { + color: #73ccfe; + border-color: #73ccfe; + + &:hover:not(:disabled) { + color: #ffffff; + background-color: #73ccfe; + border-color: #73ccfe; + } +} + +.cb-custom-event-btn-outline-primary, +.cb-custom-event-btn-outline-secondary { + color: #8566ff; + border-color: #8566ff; + + &:hover:not(:disabled) { + color: #ffffff; + background-color: #8566ff; + border-color: #8566ff; + } +} + +.cb-custom-event-btn-outline-warning { + color: #ffe500; + border-color: #ffe500; + + &:hover:not(:disabled) { + color: #ffffff; + background-color: #ffe500; + border-color: #ffe500; + } +} + +.cb-custom-event-btn-outline-danger { + color: #ff621e; + border-color: #ff621e; + + &:hover:not(:disabled) { + color: #ffffff; + background-color: #ff621e; + border-color: #ff621e; + } +} + +.cb-custom-event-btn-outline-success:disabled, +.cb-custom-event-btn-outline-secondary:disabled, +.cb-custom-event-btn-outline-primary:disabled, +.cb-custom-event-btn-outline-danger:disabled, +.cb-custom-event-btn-outline-warning:disabled { + color: #c3c2bc; + border-color: #c3c2bc; +} + +.cb-custom-event-badge-success, +.cb-custom-event-badge-warning, +.cb-custom-event-badge-danger, +.cb-custom-event-badge-primary, +.cb-custom-event-badge-light, +.cb-custom-event-active-status, +.cb-custom-event-draw-status, +.cb-custom-event-win-status, +.cb-custom-event-lose-status { + border-radius: 0.5rem; +} + +.cb-custom-event-badge-primary { + color: #ffffff; + background-color: #34b4fe; +} + +.cb-custom-event-badge-light { + background-color: var(--light); +} + +.cb-custom-event-badge-warning, +.cb-custom-event-draw-status, +.cb-custom-event-active-status { + background-color: #ffe500; +} + +.cb-custom-event-win-status { + background-color: #2ae881; +} + +.cb-custom-event-lose-status { + background-color: #ff621e; +} + +.cup { + position: absolute; + top: 60%; + left: 50%; + z-index: 0; + pointer-events: none; + background-image: var(--cup-background-url); + background-repeat: no-repeat; + background-position: center; + background-size: cover; + transform: translate(-50%, -50%) rotate(17.47deg); + width: 90vmax; + height: 90vmax; +} + +.cup-aside { + top: auto; + left: auto; + transform: rotate(8deg); + background-size: contain; + width: 600px; + height: 745px; + bottom: -15%; + right: -5%; +} + +@keyframes ticker { + 0% { + transform: translateX(0); + } + + 100% { + transform: translateX(-50%); + } +} + +.cb-ticker-line-wrap { + overflow: hidden; + width: 100%; + background: url('../static/images/eventStripesPink.svg'); + background-size: 200px 43px; + background-position: bottom 0px right 25%; + background-repeat: no-repeat; + background-color: #8c64ff; + padding: 10px 0; +} + +.cb-ticker-content { + display: inline-block; + white-space: nowrap; + animation: ticker 60s linear infinite; + will-change: transform; + width: 200%; +} + +.cb-ticker-line { + display: inline-block; + font-size: 18px; + color: white; + padding-right: 25px; +} + +.cb-evolution-panel-header { + min-height: 64px; + background-color: #30333f; + border-radius: 60px; + + padding-left: 30px; + padding-right: 30px; + padding-top: 16px; + padding-bottom: 16px; +} + +.cb-evolution-panel-main { + height: 80vh; + overflow-y: auto; + background-color: #30333f; + border-radius: 25px; +} + +.cb-evolution-panel-inner { + padding-right: 4px; + overflow-x: hidden; + scrollbar-gutter: stable; +} + +.cb-group-tournament-leaderboard-container { + min-height: 80vh; + max-height: 80vh; + background-color: #30333f; + border-radius: 25px; +} + +.cb-evolution-panel-add-solution { + padding: 12px; +} + +.cb-timeline { + position: relative; + padding-left: 0; +} + +.cb-timeline::before { + display: none; +} + +.cb-run-item { + display: flex; + flex-direction: column; + align-items: flex-start; + position: relative; + background-color: #2d3748; + border-radius: 0.5rem; + padding: 0.75rem 1rem 0.75rem 2.5rem; + margin-bottom: 0; // Use wrapper's mb-2 instead + color: #fff; + border: 1px solid transparent; + width: 100%; + text-align: left; + z-index: auto; +} + +.cb-run-item::before { + content: ''; + position: absolute; + left: 1rem; + top: 50%; + transform: translateY(-50%); + width: 12px; + height: 12px; + border-radius: 50%; + z-index: 3; +} + +/* Line segments that connect to form the timeline */ +.cb-run-item::after { + content: ''; + position: absolute; + left: calc(1rem + 5px); + top: -1rem; + /* Overlap with previous item */ + bottom: -1rem; + /* Overlap with next item */ + width: 2px; + background-color: #4a5568; + z-index: 2; + pointer-events: none; +} + +.cb-timeline > div:first-child .cb-run-item::after { + top: 50%; + /* Start at the center of the first dot */ +} + +.cb-timeline > div:last-child .cb-run-item::after { + bottom: 50%; + /* End at the center of the last dot */ +} + +.cb-run-item--group { + background-color: rgba(245, 158, 11, 0.1); +} + +.cb-run-item--group::before { + background-color: rgb(250, 204, 21); // Fully opaque +} + +.cb-run-item--test::before { + background-color: rgb(59, 130, 246); // Fully opaque +} + +.cb-run-item--error { + background-color: rgba(239, 68, 68, 0.15); // Dark red background +} + +.cb-run-item--error::before { + background-color: #ef4444; // Bright red dot +} + +.cb-run-item--timeout { + background-color: rgba(160, 174, 192, 0.1); // Subtle gray background +} + +.cb-run-item--timeout::before { + background-color: #a0aec0; // Gray dot +} + +.cb-run-item--pending::before { + background-color: #3b82f6; + animation: cb-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; +} + +@keyframes cb-pulse { + 0%, + 100% { + opacity: 1; + transform: translateY(-50%) scale(1); + } + + 50% { + opacity: 0.5; + transform: translateY(-50%) scale(1.1); + } +} + +.cb-run-item:hover { + background-color: #4a5568; +} + +.cb-run-item--error:hover { + background-color: rgba(239, 68, 68, 0.25); +} + +.cb-run-item--timeout:hover { + background-color: rgba(160, 174, 192, 0.2); +} + +.cb-run-item--disabled, +.cb-run-item:disabled { + pointer-events: none; + cursor: default; +} + +.cb-run-item--active { + border-color: rgba(59, 130, 246, 0.95); +} + +.cb-run-item--error.cb-run-item--active { + border-color: rgba(239, 68, 68, 0.95); +} + +.cb-run-item--timeout.cb-run-item--active { + border-color: rgba(160, 174, 192, 0.95); +} + +.cb-run-item--group.cb-run-item--active { + border-color: rgba(245, 158, 11, 0.95); +} + +.cb-run-item__content { + flex-grow: 1; + width: 100%; +} + +.cb-tab-btn { + background-color: rgba(255, 255, 255, 0.03) !important; +} + +.cb-tab-btn:hover { + background-color: rgba(255, 255, 255, 0.1) !important; + color: #fff !important; +} + +.cb-tab-btn--active { + background-color: rgba(255, 255, 255, 0.12) !important; + color: #fff !important; +} diff --git a/apps/codebattle/assets/css/external.scss b/apps/codebattle/assets/css/external.scss new file mode 100644 index 000000000..3ba962b1c --- /dev/null +++ b/apps/codebattle/assets/css/external.scss @@ -0,0 +1,725 @@ +/* --------------------------------------------------*/ +/* IMPORTS & VARIABLES*/ +/* --------------------------------------------------*/ + +@use 'variables' as *; + +@font-face { + font-family: 'External'; + src: url('https://yastatic.net/s3/lpc-ext/Young%20Con%202025/YangoHeadline-Black.ttf') + format('truetype'); + font-weight: 900; + font-style: normal; + font-display: swap; +} + +@import 'fonts'; + +$primary: #7642e8; +$secondary: #0a0b13; +$success: #4cd964; +$danger: #ff3b30; +$warning: #faff0f; +$info: #5ac8fa; +$light: #ebeff5; +$dark: #0c0f1e; + +$gray: #8b8b8b; +$gray-dark: #3e3e3e; +$orange: #ff9500; +$dark-red: #b00020; + +/* Bootstrap override must come *after* variables*/ + +@import 'bootstrap/scss/bootstrap'; + +/* --------------------------------------------------*/ +/* CUSTOM STYLES*/ +/* --------------------------------------------------*/ + +.bg-dark { + background-color: #0c0f1e !important; +} + +.cb-bg-dark { + background-color: #0c0f1e !important; +} + +.navbar-brand img { + max-height: 32px; + height: auto; + width: auto; +} + +@media screen and (min-width: $md) { + .navbar-brand img { + max-height: clamp(28px, 5vw, 36px); + height: auto; + width: auto; + } +} + +/* Example custom classes for your text*/ +.battle-title { + color: $warning; /* or #fffb47 if you want a brighter yellow*/ + font-family: 'External'; + font-size: 32px; + font-weight: 700; + text-transform: uppercase; +} + +.main-title { + font-size: 70px; + font-family: 'External'; + font-weight: 800; /* Adjust weight as desired*/ + /* You already have .text-purple in your HTML, which sets color: #a78bfa*/ +} + +.login-description { + font-size: 17px; + line-height: 1.4; + color: $light; /* Matches your text-light class*/ +} + +/* Style the button the way it appears in your mock*/ +.btn-yellow { + background-color: #fffb47; + color: black; + border-radius: 999px; + font-weight: bold; + font-size: 24px; + padding: 12px 24px; + transition: background-color 0.3s ease; + border: none; + + &:hover { + background-color: #e6e02b; + color: black; + } +} + +.btn-gray { + background-color: $gray; + color: white; + border-radius: 999px; + font-weight: bold; + padding: 12px 24px; + transition: background-color 0.3s ease; + border: none; + + &:hover { + background-color: $gray-dark; + color: white; + } +} + +/* --------------------------------------------------*/ +/* AUTH COMPONENT*/ +/* --------------------------------------------------*/ +.auth-container { + position: relative; + overflow: hidden; + background-color: #353754; + background-size: cover; + padding: 2rem; +} + +.auth-card { + background-color: $dark; /* #0a0b13*/ + border-radius: 24px; + max-width: 480px; /* adjust to your design*/ + width: 100%; + box-shadow: 0 0 32px rgba(0, 0, 0, 0.4); + color: white; + z-index: 2; + /* Position behind the content */ +} + +/* The .text-purple class is already defined:*/ +.text-purple { + color: $primary; /* #a78bfa*/ +} + +.hidden { + display: none; +} + +.cb-custom-event-table .cb-custom-event-td:first-child { + border-top-left-radius: 0.6rem; + border-bottom-left-radius: 0.6rem; +} + +.cb-custom-event-table .cb-custom-event-td:last-child { + border-top-right-radius: 0.6rem; + border-bottom-right-radius: 0.6rem; +} + +.cb-custom-event-empty-space-tr { + height: 4px; +} + +.cb-custom-event-dots-space-tr { + height: 4px; + border-top: dashed #d9d9d5; +} + +.cb-custom-event-tr.selected { + color: #ec9d7c !important; +} + +.cb-custom-event-tr-brown-border { + outline: 1px solid #ff621e; + border-radius: 0.5rem; +} + +.cb-custom-event-common-leaderboard-bg { + background-color: #d9d9d9; +} + +.cb-custom-event-tournaments-item:nth-child(odd) { + background-color: #f3f4f4; +} + +.cb-custom-event-name { + /* Adjust according to your needs */ + white-space: nowrap; + /* Prevent text from wrapping */ + overflow: hidden; + /* Hide the overflow text */ + text-overflow: ellipsis; + /* Display ellipsis for overflow text */ +} + +.cb-custom-event-td:not(:last-child)::after, +.cb-custom-event-nav-item:not(:first-child)::after { + content: ''; + position: absolute; + height: 40%; + width: 1.5px; +} + +.cb-custom-event-td:not(:last-child)::after { + background-color: black; + right: 0; + top: 8px; +} + +.cb-custom-event-nav-item:not(:first-child):not(.active)::after { + background-color: white; + left: 0; + top: 13px; +} + +.cb-custom-event-nav-item.active + .cb-custom-event-nav-item::after { + width: 0px; +} + +.cb-custom-event-badge-danger { + color: #fff; + background-color: #ff621e; +} + +.cb-custom-event-badge-success { + color: #212529; + background-color: #2ae881; +} + +.cb-custom-event-badge-secondary { + color: #fff; + background-color: #b6a4ff; +} + +.cb-custom-event-badge-warning { + color: #212529; + background-color: #ffe500; +} + +.cb-custom-event-bg { + background-color: #0c0f1e; +} + +.cb-custom-event-bg-success { + background-color: #2ae881; +} + +.cb-custom-event-bg-muted-success { + background-color: #d4fae6; +} + +.cb-custom-event-bg-purple { + background-color: #b6a4ff; +} + +.cb-custom-event-bg-muted-purple { + background-color: #f0edff; +} + +.cb-custom-event-bg-orange { + background-color: #ff621e; +} + +.cb-custom-event-bg-blue { + background-color: #73ccfe; +} + +.cb-custom-event-bg-brown { + background-color: #ff9c41; +} + +.cb-custom-event-pagination-page-item .cb-custom-event-pagination-page-link { + border: 1px solid transparent; + border-radius: 0.25rem; +} + +.cb-custom-event-pagination-page-link { + position: relative; + display: block; + margin-left: -1px; + line-height: 1.25; + color: black; +} + +.cb-custom-event-pagination-page-item:first-child + .cb-custom-event-pagination-page-link, +.cb-custom-event-pagination-page-item:nth-child(2) + .cb-custom-event-pagination-page-link, +.cb-custom-event-pagination-page-item:nth-last-child(2) + .cb-custom-event-pagination-page-link, +.cb-custom-event-pagination-page-item:last-child + .cb-custom-event-pagination-page-link { + color: white; + background-color: #8c64ff; + border: 1px solid #8c64ff; +} + +.cb-custom-event-pagination-page-item.disabled + .cb-custom-event-pagination-page-link { + pointer-events: none; + cursor: auto; + background-color: #9f8ed4; + border-color: #9f8ed4; +} + +.cb-custom-event-pagination-page-item.active + .cb-custom-event-pagination-page-link { + z-index: 3; + color: white; + background-color: #8c64ff; + border: 1px solid #8c64ff; +} + +.cb-custom-event-pagination-page-item:not(.active):not(.disabled):hover + .cb-custom-event-pagination-page-link { + z-index: 3; + color: white; + background-color: #8c64ff; + border: 1px solid #8c64ff; +} + +.cb-ranking-page-btn { + width: 2rem; + height: 2rem; + padding: 0; + display: inline-flex; + align-items: center; + justify-content: center; +} + +.cb-ranking-pagination { + gap: 0.5rem; +} + +.cb-ranking-pagination .cb-ranking-page-btn { + margin: 0; +} + +.cb-ranking-pagination .cb-ranking-page-btn + .cb-ranking-page-btn { + margin-left: 0.4rem; +} + +.cb-custom-event-stage-section { + background-color: #30333f; + border-radius: 25px; +} + +.cb-custom-event-stage-header { +} + +.cb-custom-event-stage-section:nth-child(even) { + background-color: #505360; +} + +.cb-custom-event-title { + font-family: 'External'; + font-weight: 700; + font-size: 74px; + line-height: 100%; + letter-spacing: -1%; + + max-width: 740px; +} + +.cb-custom-event-profile-data { + color: #f7f717; + + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + max-width: 70%; +} + +.cb-custom-event-table-action-button { + width: 20%; + + @media (max-width: $md) { + & { + width: 80%; + } + } +} + +.cb-custom-event-profile { + background-color: #30333f; + border-radius: 60px; + + padding-left: 30px; + padding-right: 30px; + padding-top: 16px; + padding-bottom: 16px; +} + +.cb-custom-event-content { + position: relative; + z-index: 1; + max-width: 1180px; +} + +.cb-custom-event-stage-grid { + display: grid; + grid-template-columns: minmax(170px, 1.05fr) minmax(110px, 0.7fr) repeat( + 4, + minmax(80px, 0.9fr) + ); + align-items: center; + column-gap: 1rem; +} + +.cb-custom-event-stage-grid-header { + font-size: 0.95rem; + column-gap: 2rem; +} + +.cb-custom-event-stage-grid-header > div { + white-space: nowrap; + justify-self: center; +} + +.cb-custom-event-stage-name { + min-width: 0; +} + +.cb-custom-event-stage-action { + min-width: 0; +} + +.cb-custom-event-stage-cell { + min-width: 0; +} + +@media (max-width: $lg) { + .cb-custom-event-stage-grid { + grid-template-columns: minmax(180px, 1.3fr) minmax(140px, 1fr); + row-gap: 0.75rem; + } + + .cb-custom-event-stage-action { + justify-content: flex-end !important; + } + + .cb-custom-event-stage-cell { + justify-content: flex-start !important; + text-align: left !important; + } +} + +@media (max-width: $md) { + .cb-custom-event-stage-grid { + grid-template-columns: 1fr; + row-gap: 0.75rem; + } + + .cb-custom-event-stage-name, + .cb-custom-event-stage-action, + .cb-custom-event-stage-cell { + justify-content: flex-start !important; + text-align: left !important; + } +} + +.cb-custom-event-text-success { + color: #2ae881; +} + +.cb-custom-event-text-danger { + color: #ff621e; +} + +.cb-custom-event-border-success { + border-color: #2ae881 !important; +} + +.cb-custom-event-border-info { + border-color: #34b4fe !important; +} + +.cb-custom-event-btn-success { + color: #212529; + background-color: #23bd6a; + border-color: #23bd6a; + + &:hover:not(:disabled) { + color: #ffffff; + background-color: #1c9755; + border-color: #1c9755; + } +} + +.cb-custom-event-btn-info { + color: #ffffff; + background-color: #34b4fe; + border-color: #34b4fe; + + &:hover:not(:disabled) { + color: #ffffff; + background-color: #0191e4; + border-color: #0191e4; + } +} + +.cb-custom-event-btn-primary, +.cb-custom-event-btn-secondary { + color: #ffffff; + background-color: #8566ff; + border-color: #8566ff; + + &:hover:not(:disabled) { + color: #ffffff; + background-color: #704dff; + border-color: #704dff; + } +} + +.cb-custom-event-btn-warning { + color: #212529; + background-color: #ff621e; + border-color: #ff621e; + + &:hover:not(:disabled) { + color: #212529; + background-color: #e64500; + border-color: #e64500; + } +} + +.cb-custom-event-btn-outline-success { + color: #2ae881; + border-color: #2ae881; + + &:hover:not(:disabled) { + color: #ffffff; + background-color: #2ae881; + border-color: #2ae881; + } +} + +.cb-custom-event-btn-outline-info { + color: #73ccfe; + border-color: #73ccfe; + + &:hover:not(:disabled) { + color: #ffffff; + background-color: #73ccfe; + border-color: #73ccfe; + } +} + +.cb-custom-event-btn-outline-primary, +.cb-custom-event-btn-outline-secondary { + color: #8566ff; + border-color: #8566ff; + + &:hover:not(:disabled) { + color: #ffffff; + background-color: #8566ff; + border-color: #8566ff; + } +} + +.cb-custom-event-btn-outline-warning { + color: #ffe500; + border-color: #ffe500; + + &:hover:not(:disabled) { + color: #ffffff; + background-color: #ffe500; + border-color: #ffe500; + } +} + +.cb-custom-event-btn-outline-danger { + color: #ff621e; + border-color: #ff621e; + + &:hover:not(:disabled) { + color: #ffffff; + background-color: #ff621e; + border-color: #ff621e; + } +} + +.cb-custom-event-btn-outline-success:disabled, +.cb-custom-event-btn-outline-secondary:disabled, +.cb-custom-event-btn-outline-primary:disabled, +.cb-custom-event-btn-outline-danger:disabled, +.cb-custom-event-btn-outline-warning:disabled { + color: #c3c2bc; + border-color: #c3c2bc; +} + +.cb-custom-event-badge-success, +.cb-custom-event-badge-warning, +.cb-custom-event-badge-danger, +.cb-custom-event-badge-primary, +.cb-custom-event-badge-light, +.cb-custom-event-active-status, +.cb-custom-event-draw-status, +.cb-custom-event-win-status, +.cb-custom-event-lose-status { + border-radius: 0.5rem; +} + +.cb-custom-event-badge-primary { + color: #ffffff; + background-color: #34b4fe; +} + +.cb-custom-event-badge-light { + background-color: var(--light); +} + +.cb-custom-event-badge-warning, +.cb-custom-event-draw-status, +.cb-custom-event-active-status { + background-color: #ffe500; +} + +.cb-custom-event-win-status { + background-color: #2ae881; +} + +.cb-custom-event-lose-status { + background-color: #ff621e; +} + +.cup { + position: absolute; + top: 60%; + left: 50%; + z-index: 0; + pointer-events: none; + background-image: var(--cup-background-url); + background-repeat: no-repeat; + background-position: center; + background-size: cover; + transform: translate(-50%, -50%) rotate(17.47deg); + width: 90vmax; + height: 90vmax; +} + +.cup-aside { + top: auto; + left: auto; + transform: rotate(8deg); + background-size: contain; + width: 600px; + height: 745px; + bottom: -18%; + right: -12%; +} + +@keyframes ticker { + 0% { + transform: translateX(0); + } + + 100% { + transform: translateX(-50%); + } +} + +.cb-ticker-line-wrap { + overflow: hidden; + width: 100%; + background: url('../static/images/eventStripesPink.svg'); + background-size: 200px 43px; + background-position: bottom 0px right 25%; + background-repeat: no-repeat; + background-color: #8c64ff; + padding: 10px 0; +} + +.cb-ticker-content { + display: inline-block; + white-space: nowrap; + animation: ticker 60s linear infinite; + will-change: transform; + width: 200%; +} + +.cb-ticker-line { + display: inline-block; + font-size: 18px; + color: white; + padding-right: 25px; +} + +.cb-bg-panel { + background-color: #2a2a35; + background: linear-gradient(135deg, #2a2a35 0%, #171720 100%); +} + +.cb-text { + color: #ebeff5; +} + +.cb-bg-panel.modal-content, +.cb-bg-panel .modal-header, +.cb-bg-panel .modal-body, +.cb-bg-panel .modal-footer { + color: #ebeff5; + border-color: rgba(255, 255, 255, 0.08); + background-color: transparent; +} + +.cb-bg-panel .modal-title { + color: #ffffff; +} + +.cb-bg-panel .close, +.cb-bg-panel .btn-close { + color: #ebeff5; + text-shadow: none; + opacity: 0.8; +} + +.cb-bg-panel .close:hover, +.cb-bg-panel .btn-close:hover { + color: #ffffff; + opacity: 1; +} + +.e-title { + font-family: 'External'; + font-size: 32px; + padding-top: 4px; +} diff --git a/services/app/apps/codebattle/assets/css/gamePreview.scss b/apps/codebattle/assets/css/gamePreview.scss similarity index 100% rename from services/app/apps/codebattle/assets/css/gamePreview.scss rename to apps/codebattle/assets/css/gamePreview.scss diff --git a/apps/codebattle/assets/css/grades.scss b/apps/codebattle/assets/css/grades.scss new file mode 100644 index 000000000..84498026b --- /dev/null +++ b/apps/codebattle/assets/css/grades.scss @@ -0,0 +1,120 @@ +/* --- ANIMATION KEYFRAMES --- */ + +/* 1. Flicker (Rookie) */ +@keyframes flicker { + 0%, + 19%, + 21%, + 23%, + 25%, + 54%, + 56%, + 100% { + opacity: 1; + } + + 20%, + 24%, + 55% { + opacity: 0.2; + } +} + +.flicker-animation { + animation: flicker 2s step-end infinite; +} + +/* 2. Rotate (Challenger) */ +@keyframes rotate { + from { + transform: rotate(0deg); + } + + to { + transform: rotate(360deg); + } +} + +.rotate-animation { + transform-origin: 50% 50%; + animation: rotate 3s linear infinite; +} + +/* 3. Blink (Pro) - Applied to individual lines */ +@keyframes line-blink { + 0%, + 100% { + stroke-opacity: 1; + } + + 50% { + stroke-opacity: 0.3; + } +} + +.blink-line-1 { + animation: line-blink 1.5s step-end infinite; +} + +.blink-line-2 { + animation: line-blink 1.5s step-end infinite 0.5s; +} + +.blink-line-3 { + animation: line-blink 1.5s step-end infinite 1s; +} + +/* 4. Glow (Elite) & 6. Aura (Grand Slam) */ +@keyframes aura { + 0%, + 100% { + filter: drop-shadow(0 0 5px currentColor); + } + + 50% { + filter: drop-shadow(0 0 15px currentColor) + drop-shadow(0 0 30px rgba(255, 255, 255, 0.4)); + } +} + +.aura-animation { + animation: aura 3s ease-in-out infinite; +} + +/* 5. Pulsating (Masters) */ +@keyframes pulse { + 0%, + 100% { + transform: scale(1); + opacity: 0.8; + } + + 50% { + transform: scale(1.05); + opacity: 1; + } +} + +.pulse-animation { + transform-origin: 50% 50%; + animation: pulse 1.5s ease-in-out infinite; +} + +/* Base Container Styling */ +.rank-icon-container { + display: flex; + flex-direction: column; + align-items: center; + margin-left: -10px; +} + +.rank-caption { + font-size: 0.7em; + margin-top: 5px; + font-weight: bold; +} + +.rank-svg-icon { + overflow: visible; + transition: filter 0.3s; +} diff --git a/apps/codebattle/assets/css/landing.scss b/apps/codebattle/assets/css/landing.scss new file mode 100644 index 000000000..6cdbd5164 --- /dev/null +++ b/apps/codebattle/assets/css/landing.scss @@ -0,0 +1,814 @@ +@use 'variables' as *; +@import 'fonts'; +@import 'bootstrap/scss/bootstrap'; + +.landing { + --bg: #0b0f1a; + --bg-2: #0f1626; + --surface: rgba(19, 28, 45, 0.9); + --surface-strong: #141f33; + --border: rgba(123, 145, 183, 0.22); + --text: #e7ecf3; + --muted: #93a4bf; + --accent: #43e6c7; + --accent-2: #ff9b50; + --accent-3: #6ac2ff; + --danger: #ff5c7b; + background: + radial-gradient(circle at 10% 10%, #1a2238, transparent 55%), + radial-gradient( + circle at 85% 15%, + rgba(67, 230, 199, 0.2), + transparent 48% + ), + var(--bg); + color: var(--text); + font-family: 'Montserrat', sans-serif; + position: relative; + overflow: hidden; + padding-bottom: 0; +} + +.landing-shell { + position: relative; + z-index: 1; +} + +.landing-noise { + position: absolute; + inset: 0; + background-image: url("data:image/svg+xml,%3Csvg width='400' height='400' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='400' height='400' filter='url(%23n)' opacity='0.18'/%3E%3C/svg%3E"); + mix-blend-mode: soft-light; + opacity: 0.2; + pointer-events: none; + z-index: 0; +} + +.landing-orb { + position: absolute; + width: 420px; + height: 420px; + border-radius: 999px; + filter: blur(40px); + opacity: 0.55; + animation: float 16s ease-in-out infinite; +} + +.orb-a { + top: -120px; + right: -80px; + background: radial-gradient( + circle at 30% 30%, + rgba(67, 230, 199, 0.9), + rgba(67, 230, 199, 0) + ); +} + +.landing-nav { + position: relative; + z-index: 2; +} + +.header-txt { + font-size: 15px; + line-height: 18px; +} + +.landing-nav-actions .btn-primary { + background: linear-gradient(120deg, var(--accent), var(--accent-3)); + border: none; + color: #051019; + font-weight: 700; +} + +.landing-nav-actions .btn-outline-success { + border-color: rgba(255, 255, 255, 0.2); + color: var(--text); +} + +.landing-nav-actions .btn-outline-success:hover { + background: rgba(255, 255, 255, 0.08); +} + +.hero { + padding: 5rem 0 4rem; +} + +.hero-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 3rem; + align-items: center; +} + +.eyebrow { + display: inline-flex; + align-items: center; + gap: 0.4rem; + padding: 0.3rem 0.9rem; + border: 1px solid var(--border); + border-radius: 999px; + font-size: 0.85rem; + text-transform: uppercase; + letter-spacing: 0.12em; + color: var(--muted); + background: rgba(17, 26, 43, 0.8); +} + +.hero-title { + font-family: 'Source Code Pro', monospace; + font-size: clamp(2.6rem, 3.8vw, 4.1rem); + font-weight: 800; + margin: 1.5rem 0 1rem; +} + +.hero-lead { + font-size: 1.1rem; + color: var(--muted); + max-width: 520px; +} + +.hero-cta { + margin-top: 2rem; +} + +.btn-try { + border: none; + color: #07111d; + background: linear-gradient(120deg, #3fd6c3 0%, #58aef0 55%, #4b8fcf 100%); + font-weight: 700; + letter-spacing: 0.08em; + box-shadow: 0 16px 30px rgba(63, 214, 195, 0.28); +} + +.btn-try:hover { + transform: translateY(-1px); + color: #050d17; + box-shadow: 0 20px 36px rgba(88, 174, 240, 0.35); +} + +.hero-pills { + display: flex; + flex-wrap: wrap; + gap: 0.8rem; + margin-top: 2.5rem; +} + +.pill { + padding: 0.5rem 1rem; + border-radius: 999px; + border: 1px solid var(--border); + color: var(--text); + background: rgba(15, 22, 38, 0.7); + font-size: 0.95rem; +} + +.hero-visual { + position: relative; +} + +.hero-panel { + background: var(--surface); + border: 1px solid var(--border); + border-radius: 24px; + padding: 1.2rem 1.5rem 1.6rem; + box-shadow: 0 30px 70px rgba(5, 10, 20, 0.45); + backdrop-filter: blur(12px); +} + +.hero-panel-header { + display: flex; + align-items: center; + gap: 0.5rem; + margin-bottom: 1rem; + color: var(--muted); + font-size: 0.9rem; +} + +.panel-title { + margin-left: 0.6rem; + text-transform: uppercase; + letter-spacing: 0.1em; + font-size: 0.75rem; +} + +.panel-status { + margin-left: auto; + color: var(--accent); + font-weight: 600; +} + +.hero-panel-body { + display: grid; + gap: 1.5rem; +} + +.leaderboard-list { + display: grid; + gap: 0.8rem; +} + +.leaderboard-row { + display: grid; + grid-template-columns: auto 1fr auto; + align-items: center; + gap: 0.8rem; + padding: 0.6rem 0.8rem; + border-radius: 14px; + background: rgba(10, 18, 30, 0.6); + border: 1px solid rgba(117, 144, 182, 0.12); +} + +.leaderboard-rank { + width: 32px; + height: 32px; + border-radius: 50%; + background: rgba(67, 230, 199, 0.2); + color: var(--accent); + display: grid; + place-items: center; + font-weight: 700; + font-family: 'Source Code Pro', monospace; +} + +.leaderboard-player { + display: flex; + align-items: center; + gap: 0.8rem; + min-width: 0; +} + +.leaderboard-avatar { + width: 36px; + height: 36px; + border-radius: 50%; + object-fit: cover; + border: 1px solid rgba(255, 255, 255, 0.1); +} + +.leaderboard-avatar.placeholder { + background: rgba(255, 255, 255, 0.08); +} + +.leaderboard-name { + margin: 0; + font-weight: 600; + color: var(--text); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 160px; +} + +.leaderboard-meta { + font-size: 0.8rem; + color: var(--muted); +} + +.leaderboard-points { + font-weight: 700; + color: var(--accent-2); + font-family: 'Source Code Pro', monospace; + white-space: nowrap; +} + +.hero-badge { + position: absolute; + right: -20px; + bottom: -18px; + background: linear-gradient( + 120deg, + rgba(67, 230, 199, 0.2), + rgba(106, 194, 255, 0.2) + ); + border: 1px solid var(--border); + padding: 0.6rem 1.3rem; + border-radius: 999px; + font-size: 0.85rem; + color: var(--text); + backdrop-filter: blur(8px); +} + +.section { + padding: 4.5rem 0; +} + +.section-alt { + background: var(--bg-2); +} + +.section-alt .section-head h2, +.section-alt .section-head .section-lead, +.section-alt .section-head .eyebrow { + color: var(--text); +} + +.section-languages { + background: + radial-gradient( + circle at 20% 20%, + rgba(67, 230, 199, 0.08), + transparent 55% + ), + radial-gradient( + circle at 80% 10%, + rgba(106, 194, 255, 0.12), + transparent 45% + ), + #10182a; +} + +.section-head { + max-width: 720px; +} + +.section h2 { + font-size: clamp(2rem, 3vw, 3.2rem); + font-weight: 700; + margin: 1rem 0 0.6rem; +} + +.section-lead { + color: var(--muted); + font-size: 1.05rem; +} + +.cards-grid { + margin-top: 2.5rem; + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 1.5rem; +} + +.feature-card { + background: var(--surface); + border: 1px solid var(--border); + border-radius: 20px; + padding: 1.6rem; + box-shadow: 0 18px 40px rgba(4, 10, 18, 0.3); +} + +.feature-card h3 { + font-family: 'Source Code Pro', monospace; + font-size: 1.2rem; + margin-bottom: 0.6rem; +} + +.feature-card p { + color: var(--muted); +} + +.chip-row { + display: flex; + flex-wrap: wrap; + gap: 0.6rem; + margin-top: 1.2rem; + color: var(--text); +} + +.chip-row span { + border: 1px solid var(--border); + padding: 0.25rem 0.7rem; + border-radius: 999px; + font-size: 0.85rem; +} + +.landing-langs { + margin-top: 2.5rem; + gap: 24px; +} + +.how-steps { + margin-top: 2.5rem; + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 1.5rem; + position: relative; +} + +.how-steps::before { + content: ''; + position: absolute; + top: 30px; + left: 32px; + right: 32px; + height: 1px; + background: linear-gradient( + 90deg, + rgba(67, 230, 199, 0.2), + rgba(106, 194, 255, 0.9), + rgba(67, 230, 199, 0.2) + ); + opacity: 0.8; +} + +.how-steps::after { + content: ''; + position: absolute; + inset: -10px; + border-radius: 32px; + background: linear-gradient( + 120deg, + rgba(67, 230, 199, 0.08), + rgba(106, 194, 255, 0.12), + rgba(255, 155, 80, 0.08) + ); + opacity: 0.6; + filter: blur(12px); + animation: shimmer 8s ease-in-out infinite; + pointer-events: none; +} + +.how-step { + background: rgba(24, 36, 58, 0.95); + border: 1px solid rgba(120, 160, 220, 0.35); + border-radius: 20px; + padding: 1.5rem; + display: grid; + gap: 0.8rem; + position: relative; + z-index: 1; + min-height: 220px; + transition: + transform 0.6s ease, + box-shadow 0.6s ease; + box-shadow: 0 20px 40px rgba(6, 12, 22, 0.35); +} + +.how-step h3 { + font-family: 'Source Code Pro', monospace; + font-size: 1.2rem; + margin-bottom: 0.4rem; + color: #f5f8ff; +} + +.how-step p { + color: #c6d4ea; + margin: 0; +} + +.how-step-index { + width: 56px; + height: 56px; + border-radius: 16px; + background: rgba(67, 230, 199, 0.28); + color: #e8fff8; + font-weight: 700; + font-size: 1.1rem; + display: grid; + place-items: center; + font-family: 'Source Code Pro', monospace; + position: relative; + box-shadow: 0 0 18px rgba(67, 230, 199, 0.35); +} + +.how-step-index::after { + content: ''; + position: absolute; + inset: -8px; + border-radius: 20px; + border: 1px solid rgba(67, 230, 199, 0.25); + opacity: 0; + animation: ring 3s ease-in-out infinite; +} + +.how-step::after { + content: ''; + position: absolute; + inset: 0; + border-radius: 20px; + background: radial-gradient( + circle at top left, + rgba(106, 194, 255, 0.25), + transparent 55% + ); + opacity: 0.2; + transition: opacity 0.6s ease; +} + +.how-step:hover { + transform: translateY(-6px); + box-shadow: 0 28px 60px rgba(6, 12, 22, 0.5); +} + +.how-step:hover::after { + opacity: 1; +} + +.landing-langs img { + width: 80px; + height: 80px; + object-fit: contain; + filter: brightness(1.25) drop-shadow(0 0 16px rgba(106, 194, 255, 0.45)); + opacity: 0.95; +} + +.lang-highlight { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 2px; +} + +.lang-highlight--elixir img { + filter: brightness(4.6) saturate(1.7) + drop-shadow(0 0 18px rgba(147, 112, 219, 0.75)); +} + +.lang-tooltip { + position: relative; + display: inline-flex; + align-items: center; + justify-content: center; +} + +.lang-tooltip::after { + content: attr(data-tooltip); + position: absolute; + bottom: calc(100% + 8px); + left: 50%; + transform: translateX(-50%) translateY(4px); + background: rgba(12, 18, 32, 0.95); + color: var(--text); + padding: 0.35rem 0.6rem; + border-radius: 8px; + font-size: 0.75rem; + letter-spacing: 0.08em; + text-transform: uppercase; + white-space: nowrap; + opacity: 0; + pointer-events: none; + transition: + opacity 0.2s ease, + transform 0.2s ease; + border: 1px solid rgba(67, 230, 199, 0.35); + box-shadow: 0 10px 20px rgba(5, 10, 20, 0.4); + z-index: 5; +} + +.lang-tooltip::before { + content: ''; + position: absolute; + bottom: calc(100% + 2px); + left: 50%; + transform: translateX(-50%); + border-width: 6px 6px 0 6px; + border-style: solid; + border-color: rgba(12, 18, 32, 0.95) transparent transparent transparent; + opacity: 0; + transition: opacity 0.2s ease; + z-index: 4; +} + +.lang-tooltip:hover::after, +.lang-tooltip:hover::before { + opacity: 1; + transform: translateX(-50%) translateY(0); +} + +.lang-icons { + display: grid; + grid-template-columns: repeat(8, minmax(0, 1fr)); + gap: 20px; + place-items: center; +} + +.community { + background: var(--surface); + border: 1px solid var(--border); + border-radius: 22px; + padding: 2rem; + margin-top: 2.5rem; +} + +.community-head { + display: flex; + align-items: center; +} + +.github-logo { + filter: brightness(2.6) saturate(1.2); +} + +.github-stars-badge { + box-shadow: 0 10px 24px rgba(10, 14, 30, 0.2); +} + +.contributors img { + width: 40px; + height: 40px; + object-fit: cover; + margin-right: 0.4rem; +} + +.contributors img:hover { + transform: scale(1.15); +} + +.tag-row { + display: flex; + flex-wrap: wrap; + gap: 0.6rem; + color: var(--muted); +} + +.tag-row span { + border: 1px solid var(--border); + padding: 0.25rem 0.7rem; + border-radius: 999px; + font-size: 0.8rem; +} + +.cta { + padding: 4rem 0 2rem; + background: + radial-gradient( + circle at 15% 20%, + rgba(67, 230, 199, 0.08), + transparent 55% + ), + radial-gradient( + circle at 85% 10%, + rgba(106, 194, 255, 0.12), + transparent 45% + ), + var(--bg-2); +} + +.cta-card { + background: rgba(20, 30, 48, 0.92); + border: 1px solid rgba(120, 160, 220, 0.25); + border-radius: 24px; + padding: 2rem 2.5rem; + display: flex; + align-items: center; + justify-content: space-between; + gap: 2rem; + box-shadow: 0 26px 60px rgba(6, 12, 22, 0.45); +} + +.footer { + background-color: rgba(8, 12, 20, 0.96); + font-size: 0.95rem; +} + +.text-gray { + color: var(--muted) !important; +} + +.text-muted { + color: var(--muted) !important; +} + +.fw-500 { + font-weight: 500; +} + +.btn:hover { + @if $link-hover-decoration == underline { + text-decoration: none; + } +} + +[data-reveal] { + opacity: 0; + transform: translateY(24px); + transition: + opacity 0.7s ease, + transform 0.7s ease; + transition-delay: var(--reveal-delay, 0ms); +} + +[data-reveal].is-visible { + opacity: 1; + transform: translateY(0); +} + +@keyframes float { + 0%, + 100% { + transform: translateY(0px); + } + 50% { + transform: translateY(18px); + } +} + +@keyframes shimmer { + 0%, + 100% { + transform: translateY(0) translateX(0); + } + 50% { + transform: translateY(8px) translateX(18px); + } +} + +@keyframes ring { + 0% { + opacity: 0; + transform: scale(0.9); + } + 40% { + opacity: 1; + } + 100% { + opacity: 0; + transform: scale(1.15); + } +} + +@media (max-width: $lg) { + .hero-grid { + grid-template-columns: 1fr; + } + + .hero-visual { + order: -1; + } + + .cta-card { + flex-direction: column; + align-items: flex-start; + } + + .lang-icons { + grid-template-columns: repeat(5, minmax(0, 1fr)); + } + + .how-steps { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .how-steps::before { + display: none; + } +} + +@media (max-width: $md) { + .hero { + padding-top: 3rem; + } + + .cards-grid { + grid-template-columns: 1fr; + } + + .landing-nav-actions { + flex-wrap: wrap; + } + + .hero-badge { + position: static; + display: inline-block; + margin-top: 1rem; + } + + .lang-icons { + grid-template-columns: repeat(4, minmax(0, 1fr)); + } + + .how-steps { + grid-template-columns: 1fr; + } +} + +@media (max-width: $sm) { + .hero-title { + font-size: 2.2rem; + } + + .cta-card { + padding: 1.6rem; + } + + .landing-orb { + width: 260px; + height: 260px; + } + + .lang-icons { + grid-template-columns: repeat(3, minmax(0, 1fr)); + } +} + +@media (prefers-reduced-motion: reduce) { + [data-reveal] { + opacity: 1; + transform: none; + transition: none; + } + + .landing-orb { + animation: none; + } + + .how-steps::before, + .how-steps::after { + animation: none; + } + + .how-step { + transform: none !important; + } +} diff --git a/apps/codebattle/assets/css/monaco-codicon-fix.css b/apps/codebattle/assets/css/monaco-codicon-fix.css new file mode 100644 index 000000000..37c69e560 --- /dev/null +++ b/apps/codebattle/assets/css/monaco-codicon-fix.css @@ -0,0 +1,9 @@ +/* Override Monaco's codicon font path to use our local copy */ +/* This needs to be loaded AFTER monaco's CSS to override it */ +@font-face { + font-display: block; + font-family: codicon; + font-weight: 400; + font-style: normal; + src: url('/codicon.ttf') format('truetype'); +} diff --git a/apps/codebattle/assets/css/skeleton.scss b/apps/codebattle/assets/css/skeleton.scss new file mode 100644 index 000000000..30e4b675f --- /dev/null +++ b/apps/codebattle/assets/css/skeleton.scss @@ -0,0 +1,264 @@ +@use 'sass:color'; + +$item-bg: #15202b; + +.cb-text-skeleton { + animation: skeleton-loading 1s linear infinite alternate; + + height: 1.2rem; + border-radius: 0.25rem; + background-color: color.adjust($item-bg, $lightness: 7%); +} + +@keyframes skeleton-loading { + 0% { + opacity: 0.2; + } + + 80%, + 100% { + opacity: 1; + } +} + +.cb-lobby-loading { + position: relative; + width: 100%; + padding-top: 1.25rem; + padding-bottom: 2rem; + pointer-events: none; + + .cb-lobby-loading-main, + .cb-lobby-loading-profile, + .cb-lobby-loading-secondary { + position: relative; + overflow: hidden; + border: 1px solid rgba(115, 204, 254, 0.08); + background: linear-gradient( + 145deg, + rgba(42, 42, 53, 0.96), + rgba(23, 23, 32, 0.96) + ); + box-shadow: 0 1rem 2.5rem rgba(0, 0, 0, 0.12); + } + + .cb-lobby-loading-main, + .cb-lobby-loading-profile { + min-height: 16rem; + } + + .cb-lobby-loading-secondary { + min-height: 14rem; + } + + .cb-lobby-loading-avatar { + width: 4.5rem; + height: 4.5rem; + border-radius: 50%; + } + + .cb-text-skeleton { + animation: none; + overflow: hidden; + background: rgba(115, 204, 254, 0.07); + + &::after { + position: absolute; + inset: 0; + transform: translateX(-100%); + animation: lobby-skeleton-shimmer 1.8s ease-in-out infinite; + background: linear-gradient( + 90deg, + transparent, + rgba(115, 204, 254, 0.13), + transparent + ); + content: ''; + } + } +} + +.cb-lobby-loading-frame { + width: 100%; + + > #app { + width: 100%; + } +} + +.cb-lobby-loading-hero { + position: relative; + display: flex; + align-items: center; + justify-content: center; + width: min(100%, 46rem); + min-height: 9rem; + margin: 0 auto 1.25rem; + padding: 1.5rem 2rem; + overflow: hidden; + border: 1px solid rgba(42, 232, 129, 0.18); + border-radius: 1rem; + background: + radial-gradient( + circle at 15% 50%, + rgba(42, 232, 129, 0.12), + transparent 30% + ), + linear-gradient(135deg, rgba(42, 42, 53, 0.92), rgba(23, 23, 32, 0.96)); + box-shadow: + 0 1.5rem 4rem rgba(0, 0, 0, 0.2), + inset 0 1px rgba(255, 255, 255, 0.03); +} + +.cb-lobby-loading-emblem { + position: relative; + display: grid; + flex: 0 0 4.75rem; + width: 4.75rem; + height: 4.75rem; + margin-right: 1.5rem; + place-items: center; + border: 1px solid rgba(42, 232, 129, 0.45); + border-radius: 1.25rem; + transform: rotate(45deg); + background: rgba(42, 232, 129, 0.07); + box-shadow: + 0 0 2.5rem rgba(42, 232, 129, 0.12), + inset 0 0 1.5rem rgba(42, 232, 129, 0.06); + + &::before { + position: absolute; + inset: 0.45rem; + border: 1px solid rgba(42, 232, 129, 0.14); + border-radius: 0.9rem; + content: ''; + } + + span { + transform: rotate(-45deg); + color: #2ae881; + font-size: 1.15rem; + font-weight: 800; + letter-spacing: -0.1em; + text-shadow: 0 0 1rem rgba(42, 232, 129, 0.5); + } +} + +.cb-lobby-loading-copy { + flex: 1 1 auto; + max-width: 31rem; + + h1 { + margin: 0.35rem 0 0.3rem; + color: #fff; + font-size: clamp(1.35rem, 3vw, 2rem); + font-weight: 700; + letter-spacing: 0.01em; + } + + p { + margin: 0 0 1rem; + color: rgba(255, 255, 255, 0.5); + font-size: 0.9rem; + } +} + +.cb-lobby-loading-kicker { + display: flex; + align-items: center; + color: #2ae881; + font-size: 0.7rem; + font-weight: 700; + letter-spacing: 0.16em; + text-transform: uppercase; +} + +.cb-lobby-loading-status-dot { + width: 0.45rem; + height: 0.45rem; + margin-right: 0.55rem; + border-radius: 50%; + animation: lobby-status-pulse 1.5s ease-out infinite; + background: #2ae881; + box-shadow: 0 0 0.75rem rgba(42, 232, 129, 0.8); +} + +.cb-lobby-loading-progress { + width: 100%; + height: 0.2rem; + overflow: hidden; + border-radius: 999px; + background: rgba(255, 255, 255, 0.06); + + span { + display: block; + width: 42%; + height: 100%; + animation: lobby-progress 1.8s ease-in-out infinite; + border-radius: inherit; + background: linear-gradient( + 90deg, + transparent, + #2ae881, + #73ccfe, + transparent + ); + box-shadow: 0 0 1rem rgba(42, 232, 129, 0.5); + } +} + +#app:not(:empty) + #lobby-loading-shell { + display: none; +} + +@keyframes lobby-skeleton-shimmer { + 100% { + transform: translateX(100%); + } +} + +@keyframes lobby-progress { + 0% { + transform: translateX(-110%); + } + + 100% { + transform: translateX(340%); + } +} + +@keyframes lobby-status-pulse { + 0% { + box-shadow: 0 0 0 0 rgba(42, 232, 129, 0.5); + } + + 70%, + 100% { + box-shadow: 0 0 0 0.55rem rgba(42, 232, 129, 0); + } +} + +@media (max-width: 575.98px) { + .cb-lobby-loading-hero { + flex-direction: column; + padding: 1.5rem; + text-align: center; + } + + .cb-lobby-loading-emblem { + margin: 0 0 1.5rem; + } + + .cb-lobby-loading-kicker { + justify-content: center; + } +} + +@media (prefers-reduced-motion: reduce) { + .cb-text-skeleton, + .cb-text-skeleton::after, + .cb-lobby-loading-status-dot, + .cb-lobby-loading-progress span { + animation: none; + } +} diff --git a/apps/codebattle/assets/css/style.scss b/apps/codebattle/assets/css/style.scss new file mode 100644 index 000000000..dd29de173 --- /dev/null +++ b/apps/codebattle/assets/css/style.scss @@ -0,0 +1,4688 @@ +@use 'variables' as *; + +$body-bg: #e5e5e5; +$cb-text-color: #999; +$cb-text-light-color: #ddd; +$cb-border-radius: 0.5rem; +$cb-success: #46a077; +$cb-hovered-success: #398862; +$cb-border-radius: 0.5rem; + +$cb-secondary: #3a3f50; +$cb-secondary-focus-background: #3a3f50; +$cb-secondary-focus-border: #a4b2d6; +$cb-secondary-hover-background: #4c5369; +$cb-secondary-hover-border: #7d89a6; +$cb-secondary-disabled-background: #7c808f; +$cb-secondary-disabled-border: #7c808f; +$cb-secondary-disabled-color: #c0c4d2; +/* $cb-secondary: #7a1f1f;*/ +/* $cb-secondary-focus-background: #7a1f1f;*/ +/* $cb-secondary-focus-border: #ffcc66;*/ +/* $cb-secondary-hover-background: #9f2828;*/ +/* $cb-secondary-hover-border: #e6b8b8;*/ +/* $cb-secondary-disabled-background: #c09090;*/ +/* $cb-secondary-disabled-border: #c09090;*/ +/* $cb-secondary-disabled-color: #e8e8e8;*/ +/* $cb-secondary: #23497a;*/ +/* $cb-secondary-focus-background: #23497a;*/ +/* $cb-secondary-focus-border: #f0ad4e;*/ +/* $cb-secondary-hover-background: #1a365c;*/ +/* $cb-secondary-hover-border: #356ca6;*/ +/* $cb-secondary-disabled-background: #aec4dc;*/ +/* $cb-secondary-disabled-border: #aec4dc;*/ +/* $cb-secondary-disabled-color: #59799B;*/ + +$cb-border-color: #4c4c5a; +/* $cb-border-color: #402d2d;*/ +/* $cb-border-color: rgba(255, 255, 255, 0.15);*/ + +$cb-bg-panel: #2a2a35; +$cb-bg-panel-background: linear-gradient(135deg, #2a2a35 0%, #171720 100%); +/* $cb-bg-panel: #291c1c;*/ +/* $cb-bg-panel: #1c2129;*/ + +$cb-bg-highlight-panel: #1c1c24; +/* $cb-bg-highlight-panel: #1f1313;*/ +/* $cb-bg-highlight-panel: #13181f;*/ + +$secondary: #477591; +$link-color: white; +$error: #dc3545; +$bg-orange: rgba(238, 55, 55); +$orange: rgba(238, 55, 55, 0.76); +$link-hover-color: $orange; +$border-radius-sm: 0%; +$btn-border-width: 2px; +/* +$gold: #c9a56c; // Grand Slam – polished gold highlight +$silver: #a3acb9; // Masters – brighter brushed silver (more readable) +$bronze: #b07a4a; // Elite – copper bronze highlight +$platinum: #8b919a; // Pro – cooler, slightly darker than silver (clear separation) +$steel: #6f7680; // Challenger – neutral steel (a touch lighter than iron) +$iron: #59606a; // Rookie – darker iron (avoids “disabled outline” look) +*/ + +$gold: #e0bf7a; /* Grand Slam – brighter polished gold*/ +$silver: #c2c9d6; /* Masters – cleaner, lighter brushed silver*/ +$bronze: #c48a57; /* Elite – brighter copper bronze*/ +$platinum: #a4aab3; /* Pro – lighter cool platinum, still distinct from silver*/ +$steel: #8a919c; /* Challenger – brighter neutral steel*/ +$iron: #6f7782; /* Rookie – lifted iron, no “disabled” vibes*/ + +$cb-grand-slam-bg: $gold; +$cb-masters-bg: $silver; +$cb-elite-bg: $bronze; +$cb-pro-bg: $platinum; +$cb-challenger-bg: $steel; +$cb-rookie-bg: $iron; + +:root { + --cb-grade-grand_slam: #{$cb-grand-slam-bg}; + --cb-grade-masters: #{$cb-masters-bg}; + --cb-grade-elite: #{$cb-elite-bg}; + --cb-grade-pro: #{$cb-pro-bg}; + --cb-grade-challenger: #{$cb-challenger-bg}; + --cb-grade-rookie: #{$cb-rookie-bg}; +} + +@import 'bootstrap/scss/bootstrap'; +@import 'nprogress/nprogress.css'; +@import 'gamePreview'; +@import 'skeleton'; +@import 'custom'; +@import 'react-contexify/dist/ReactContexify.css'; +@import 'react-big-calendar/lib/css/react-big-calendar.css'; + +@font-face { + font-family: 'External'; + src: url('https://yastatic.net/s3/lpc-ext/Young%20Con%202025/YangoHeadline-Black.ttf') + format('truetype'); + font-weight: 900; + font-style: normal; + font-display: swap; +} + +$fa-font-path: '/fonts'; + +@import 'fonts'; +@import 'monaco-fonts'; +@import 'tournaments'; +@import 'grades'; + +.katex .rlap > .inner { + position: relative !important; +} + +em-emoji-picker { + position: absolute; + bottom: 52px; + right: 10px; + height: 254px; + + border-radius: 10px; + --shadow: 0px 0px 15px var(--gray); +} + +.phx-connected, +.phx-loading { + width: 100%; + padding-right: 15px; + padding-left: 15px; + margin-right: auto; + margin-left: auto; +} + +.xstate { + height: 1000px; +} + +@keyframes checking_fade { + from { + opacity: 1; + } + + 50% { + opacity: 0.6; + } + + to { + opacity: 1; + } +} + +@-webkit-keyframes checking_fade { + from { + opacity: 1; + } + + 50% { + opacity: 0.6; + } + + to { + opacity: 1; + } +} + +[data-editor-state='checking'] { + animation: checking_fade 1000ms infinite; + -webkit-animation: checking_fade 1000ms infinite; +} + +[data-editor-state='banned'] { + opacity: 0.6; + color: var(--red); + background: var(--red); + + a { + color: red; + } +} + +input[type='range'] { + -webkit-appearance: none; + /* For WebKit browsers (Chrome, Safari, Edge) */ + appearance: none; + background: transparent; + /* Remove default background */ + cursor: pointer; + border: none; + /* Remove default border */ + + &::-webkit-slider-runnable-track, + &::-moz-range-track { + height: 8px; + background: $cb-bg-panel; + border-radius: 16px; + } + + &:focus-visible { + outline: none; + } + + &:focus-visible::-webkit-slider-runnable-track { + outline-offset: 15px; + outline: 1px solid #c56fff; + } + + &:focus-visible::-moz-range-track { + outline-offset: 15px; + outline: 1px solid #c56fff; + } +} + +input[type='range'].cb-range { + --range-progress: 50%; + --cb-range-track-bg: linear-gradient( + 90deg, + #ff6a3d 0%, + $orange 50%, + #d63a3a 100% + ); + --cb-range-track-rest: linear-gradient( + 180deg, + rgba(58, 58, 74, 0.95) 0%, + rgba(33, 33, 43, 0.98) 100% + ); + height: 22px; + + &::-webkit-slider-runnable-track { + height: 10px; + border-radius: 999px; + background: + linear-gradient(90deg, #dc3545 0%, #ff5a5a 100%) 0 / var(--range-progress) + 100% no-repeat, + var(--cb-range-track-rest); + border: 1px solid rgba(255, 255, 255, 0.08); + box-shadow: + inset 0 1px 0 rgba(255, 255, 255, 0.12), + inset 0 -1px 0 rgba(0, 0, 0, 0.35), + 0 0 0 1px rgba(238, 55, 55, 0.08); + transition: box-shadow 0.2s ease; + } + + &::-moz-range-track { + height: 10px; + border-radius: 999px; + background: + linear-gradient(90deg, #dc3545 0%, #ff5a5a 100%) 0 / var(--range-progress) + 100% no-repeat, + var(--cb-range-track-rest); + border: 1px solid rgba(255, 255, 255, 0.08); + box-shadow: + inset 0 1px 0 rgba(255, 255, 255, 0.12), + inset 0 -1px 0 rgba(0, 0, 0, 0.35), + 0 0 0 1px rgba(238, 55, 55, 0.08); + transition: box-shadow 0.2s ease; + } + + &::-webkit-slider-thumb { + -webkit-appearance: none; + width: 22px; + height: 22px; + margin-top: -7px; + border-radius: 50%; + background: radial-gradient( + circle at 30% 30%, + #fff2e8 0%, + #ff955e 35%, + $orange 65%, + #cf2626 100% + ); + border: 2px solid rgba(255, 255, 255, 0.75); + box-shadow: + 0 2px 8px rgba(0, 0, 0, 0.55), + 0 0 0 3px rgba(238, 55, 55, 0.2); + transition: + transform 0.15s ease, + box-shadow 0.2s ease; + } + + &::-moz-range-thumb { + width: 22px; + height: 22px; + border-radius: 50%; + background: radial-gradient( + circle at 30% 30%, + #fff2e8 0%, + #ff955e 35%, + $orange 65%, + #cf2626 100% + ); + border: 2px solid rgba(255, 255, 255, 0.75); + box-shadow: + 0 2px 8px rgba(0, 0, 0, 0.55), + 0 0 0 3px rgba(238, 55, 55, 0.2); + transition: + transform 0.15s ease, + box-shadow 0.2s ease; + } + + &:hover::-webkit-slider-runnable-track, + &:hover::-moz-range-track { + box-shadow: + inset 0 1px 0 rgba(255, 255, 255, 0.15), + inset 0 -1px 0 rgba(0, 0, 0, 0.4), + 0 0 0 1px rgba(238, 55, 55, 0.18), + 0 0 12px rgba(238, 55, 55, 0.2); + } + + &:hover::-webkit-slider-thumb, + &:hover::-moz-range-thumb { + transform: scale(1.06); + } + + &:focus-visible::-webkit-slider-thumb { + box-shadow: + 0 2px 8px rgba(0, 0, 0, 0.55), + 0 0 0 5px rgba(238, 55, 55, 0.35); + } + + &:focus-visible::-moz-range-thumb { + box-shadow: + 0 2px 8px rgba(0, 0, 0, 0.55), + 0 0 0 5px rgba(238, 55, 55, 0.35); + } +} + +.dark-bg { + background-color: $dark; +} + +.cb-bg-dark { + background-color: #1a1a1a; +} + +.bg-winner { + background: $gold; +} + +[data-player-type] { + --flag-color: $cb-bg-panel; + background: linear-gradient(to top, var(--flag-color), $cb-bg-panel 15%); +} + +[data-player-type='current_user'] { + --flag-color: var(--success); +} + +[data-player-type='player'] { + --flag-color: var(--gray); +} + +[data-player-type='opponent'] { + --flag-color: var(--danger); +} + +.alert { + border-radius: unset; +} + +.alert-dark-theme { + border: none; + backdrop-filter: blur(10px); + + &.alert-info { + background: linear-gradient( + 135deg, + rgba(25, 135, 84, 0.9), + rgba(25, 135, 84, 0.7) + ); + color: #ffffff; + border-left: 4px solid #198754; + } + + &.alert-success { + background: linear-gradient( + 135deg, + rgba(25, 135, 84, 0.9), + rgba(25, 135, 84, 0.7) + ); + color: #ffffff; + border-left: 4px solid #198754; + } + + &.alert-danger { + background: linear-gradient( + 135deg, + rgba(220, 53, 69, 0.9), + rgba(220, 53, 69, 0.7) + ); + color: #ffffff; + border-left: 4px solid #dc3545; + } + + &.alert-warning { + background: linear-gradient( + 135deg, + rgba(255, 193, 7, 0.9), + rgba(255, 193, 7, 0.7) + ); + color: #000000; + border-left: 4px solid #ffc107; + } + + .close { + text-shadow: 0 1px 0 rgba(0, 0, 0, 0.5); + opacity: 0.8; + + &:hover { + opacity: 1; + } + } +} + +.alert-dark-theme.cb-game-win-alert.alert-success { + background: linear-gradient( + 135deg, + rgba(25, 135, 84, 0.95), + rgba(240, 199, 94, 0.75) + ); + color: #ffffff; + border-left: 4px solid #f0c75e; + box-shadow: + 0 0 0 1px rgba(240, 199, 94, 0.25), + 0 10px 24px rgba(0, 0, 0, 0.35); +} + +.gutter-vertical { + background-image: url('../static/images/verticalGutter.svg'); + cursor: col-resize; + background-repeat: no-repeat; + background-position: 50%; +} + +.header-txt { + font-size: 18px; + line-height: 18px; +} + +.text-black { + color: black !important; +} + +.text-orange { + color: $orange !important; +} + +.cb-text-transparent { + color: transparent; +} + +.bg-gray { + background-color: rgba(128, 128, 128, 1); +} + +.bg-orange { + background-color: $orange; +} + +.border-gray { + border: 2px solid #d9d9d9; +} + +.border-winner { + border: 2px solid !important; + border-color: $gold !important; +} + +.min-h-100 { + min-height: 100%; +} + +.basis-0 { + flex-basis: 0; +} + +.mvh-100 { + max-height: 100vh; +} + +.top-0 { + top: 0; +} + +.start-0 { + left: 0; +} + +.end-0 { + right: 0; +} + +.z-3 { + z-index: 3; +} + +.btn { + border-radius: unset; +} + +.btn-orange { + border-color: $orange; + background: $orange; + color: var(--white); +} + +.btn-orange:hover { + background: var(--red); + color: var(--white); +} + +.btn-outline-orange { + border-color: $orange; + color: $orange; + @include button-outline-variant($orange); +} + +.btn-check:hover { + color: #ffffff; +} + +.btn-hover { + visibility: hidden; +} + +@media (max-width: $sm) { + .btn-hover { + visibility: visible; + } +} + +tr.game-item th, +tr.game-item td { + border-color: $cb-border-color; +} + +.game-item:hover .btn-hover { + visibility: visible; +} + +a { + transition: color ease-in 0.1s; +} + +.cb-heatmap-background { + background: $cb-bg-panel-background; +} + +.react-calendar-heatmap { + & .react-calendar-heatmap-month-label { + color: #b8c0d0; + fill: #b8c0d0; + } + + & .react-calendar-heatmap-weekday-label { + color: #b8c0d0; + fill: #b8c0d0; + } + + .color-huge { + background-color: #f2cf78; + fill: #f2cf78; + } + + .color-huge:hover { + background-color: #f7da98; + fill: #f7da98; + } + + .color-large { + background-color: #e2e8f0; + fill: #e2e8f0; + } + + .color-large:hover { + background-color: #edf2f7; + fill: #edf2f7; + } + + .color-small { + background-color: #b8c3d6; + fill: #b8c3d6; + } + + .color-small:hover { + background-color: #cbd5e1; + fill: #cbd5e1; + } + + .color-empty { + background-color: #363d4e; + fill: #363d4e; + } + + .color-empty:hover { + fill: #475063; + } +} + +.react-calendar-heatmap rect { + stroke: rgba(12, 16, 24, 0.65); + stroke-width: 1px; +} + +.react-calendar-heatmap rect:hover { + stroke: #dbe3f2; + stroke-width: 1px; +} + +.cb-builder-argument-input { + min-width: 150px; +} + +.cb-builder-type-selector { + min-width: 150px; +} + +.cb-game-score-won { + color: var(--green) !important; +} + +.cb-game-score-lost { + color: var(--red) !important; +} + +.cb-game-score-draw { + color: var(--gray) !important; +} + +.cb-user-online { + color: var(--green) !important; +} + +.cb-user-dark-offline { + border-color: var(--gray); + border-radius: 50%; +} + +.cb-timer-progress { + position: absolute; + top: 0; + left: 0; + opacity: 0.3; + height: 100%; +} + +.cb-slider { + height: 32px; + + &:hover { + cursor: pointer; + + .cb-slider-timeline { + transform: translateY(-50%) scale(1, 1.095); + } + + .cb-slider-handle { + opacity: 1; + } + } +} + +.cb-slider-timeline { + height: 7px; + left: 0; + top: 50%; + transform: translateY(-50%); + transition: transform 0.1s; +} + +.cb-slider-action { + width: 5px; + height: 20px; + left: 0; + top: 50%; + transform: translate(0, -50%); + z-index: 15; +} + +.cb-slider-action:hover { + display: block; + height: 28px; +} + +.cb-slider-handle { + width: 32px; + height: 32px; + transform: translate(-50%, -50%); + top: 50%; + left: 50%; + opacity: 0; + transition: opacity 0.28s; +} + +.cb-slider-handle-button { + width: 15px; + height: 15px; + transform: translate(-50%, -50%); + top: 50%; + left: 50%; +} + +.cb-slider-bar { + top: 0; + bottom: 0; + left: 0; +} + +.cb-replayer-controls-spacer { + height: 76px; +} + +.cb-replayer-controls-shell { + z-index: 1030; + padding: 0 0.6rem 0.6rem; + pointer-events: none; +} + +.cb-replayer-controls { + position: relative; + max-width: 1440px; + margin: 0 auto; + padding: 0.45rem 0.6rem; + color: #f2f3f8; + background: rgba(18, 18, 25, 0.97); + border: 1px solid #414252; + border-radius: 0.65rem; + box-shadow: 0 10px 34px rgba(0, 0, 0, 0.5); + pointer-events: auto; +} + +.cb-replayer-controls__main, +.cb-replayer-controls__timeline { + display: flex; + align-items: center; +} + +.cb-replayer-controls__main { + gap: 0.65rem; +} + +.cb-replayer-controls__play { + display: inline-flex; + flex: 0 0 38px; + align-items: center; + justify-content: center; + width: 38px; + height: 38px; + padding: 0; + color: #fff; + background: #ee3737; + border: 1px solid #ff6868; + border-radius: 50%; + box-shadow: 0 3px 12px rgba(238, 55, 55, 0.25); + + &:hover, + &:focus-visible { + color: #fff; + background: #fa4848; + border-color: #ff9292; + outline: none; + } +} + +.cb-replayer-controls__timeline { + flex: 1 1 auto; + gap: 0.65rem; + min-width: 0; +} + +.cb-replayer-controls__scrubber { + flex: 1 1 auto; + min-width: 120px; +} + +.cb-replayer-controls__time { + flex: 0 0 auto; + color: #d7d8e2; + font-size: 0.74rem; + font-weight: 700; +} + +.cb-replayer-controls__settings-button { + display: inline-flex; + flex: 0 0 38px; + align-items: center; + justify-content: center; + width: 38px; + height: 38px; + padding: 0; + color: #d7d8e2; + background: transparent; + border: 0; + border-radius: 50%; + + &:hover, + &:focus-visible, + &.active { + color: #fff; + background: #3a3f50; + outline: none; + } +} + +.cb-replayer-settings { + position: absolute; + right: 0; + bottom: calc(100% + 0.55rem); + width: min(410px, calc(100vw - 1.2rem)); + overflow: hidden; + color: #f2f3f8; + background: rgba(24, 24, 31, 0.98); + border: 1px solid #4a4c5d; + border-radius: 0.8rem; + box-shadow: 0 18px 48px rgba(0, 0, 0, 0.58); +} + +.cb-replayer-settings__header { + padding: 0.8rem 1rem; + font-size: 0.84rem; + font-weight: 700; + border-bottom: 1px solid #3a3b48; +} + +.cb-replayer-settings__header--back { + display: flex; + align-items: center; + gap: 0.5rem; + + button { + display: inline-flex; + align-items: center; + justify-content: center; + width: 30px; + height: 30px; + padding: 0; + color: #f2f3f8; + background: transparent; + border: 0; + border-radius: 50%; + + &:hover, + &:focus-visible { + background: #3a3f50; + outline: none; + } + } +} + +.cb-replayer-settings__menu-item { + display: grid; + grid-template-columns: 22px minmax(0, 1fr) auto; + gap: 0.7rem; + align-items: center; + width: 100%; + padding: 0.75rem 1rem; + color: #f2f3f8; + text-align: left; + background: transparent; + border: 0; + + &:hover, + &:focus-visible { + color: #fff; + background: #30313d; + outline: none; + } + + strong, + small { + display: block; + } + + strong { + font-size: 0.8rem; + } + + small { + margin-top: 0.1rem; + color: #9699a8; + font-size: 0.66rem; + } +} + +.cb-replayer-settings__menu-value { + display: flex; + align-items: center; + gap: 0.35rem; + color: #c8cad4; + font-size: 0.75rem; + font-weight: 700; +} + +.cb-replayer-settings__timing { + padding: 0.75rem 1rem; + border-top: 1px solid #32333f; + border-bottom: 1px solid #32333f; +} + +.cb-replayer-settings__timing-title { + display: grid; + grid-template-columns: 22px minmax(0, 1fr); + gap: 0.7rem; + align-items: center; + margin-bottom: 0.65rem; + + strong, + small { + display: block; + } + + strong { + font-size: 0.8rem; + } + + small { + margin-top: 0.1rem; + color: #9699a8; + font-size: 0.66rem; + } +} + +.cb-replayer-settings__segmented { + display: grid; + grid-template-columns: 1fr 1fr; + padding: 3px; + background: #101016; + border: 1px solid #3d3e4d; + border-radius: 0.5rem; + + button { + padding: 0.42rem 0.6rem; + color: #aeb1c0; + font-size: 0.72rem; + font-weight: 600; + background: transparent; + border: 0; + border-radius: 0.35rem; + + &:hover, + &:focus-visible { + color: #fff; + outline: none; + } + + &.active { + color: #fff; + background: #3a3f50; + box-shadow: inset 0 0 0 1px #60657a; + } + } +} + +.cb-replayer-settings__speed-value { + display: block; + padding: 1.15rem 1rem 0.65rem; + color: #fff; + font-size: 1.55rem; + font-weight: 700; +} + +.cb-replayer-settings__speed-slider-row { + display: grid; + grid-template-columns: 40px minmax(120px, 1fr) 40px; + gap: 0.7rem; + align-items: center; + padding: 0 1rem 0.8rem; + + > button { + display: inline-flex; + align-items: center; + justify-content: center; + width: 40px; + height: 40px; + padding: 0; + color: #fff; + background: #3a3b47; + border: 0; + border-radius: 50%; + + &:hover:not(:disabled), + &:focus-visible:not(:disabled) { + background: #505261; + outline: none; + } + + &:disabled { + color: #6d6f7d; + cursor: not-allowed; + opacity: 0.55; + } + } +} + +.cb-replayer-settings__speed-slider { + appearance: none; + width: 100%; + height: 24px; + margin: 0; + background: linear-gradient( + to right, + #ee3737 0, + #ee3737 var(--speed-progress), + #565864 var(--speed-progress), + #565864 100% + ) + no-repeat center / 100% 5px; + cursor: grab; + + &:active { + cursor: grabbing; + } + + &::-webkit-slider-runnable-track { + height: 5px; + background: transparent; + border-radius: 999px; + } + + &::-webkit-slider-thumb { + appearance: none; + width: 18px; + height: 18px; + margin-top: -6.5px; + background: #fff; + border: 0; + border-radius: 50%; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.55); + } + + &::-moz-range-track { + height: 5px; + background: transparent; + border: 0; + } + + &::-moz-range-thumb { + width: 18px; + height: 18px; + background: #fff; + border: 0; + border-radius: 50%; + } + + &:focus-visible { + outline: 2px solid #a4b2d6; + outline-offset: 3px; + } +} + +.cb-replayer-settings__speed-presets { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 0.45rem; + padding: 0 1rem 1rem; + + button { + padding: 0.45rem 0.25rem; + color: #d7d8e2; + font-size: 0.72rem; + font-weight: 600; + background: #343540; + border: 1px solid transparent; + border-radius: 999px; + + &:hover, + &:focus-visible { + color: #fff; + background: #484a58; + outline: none; + } + + &.active { + color: #fff; + background: #565968; + border-color: #85899d; + } + } +} + +@media screen and (max-width: 575px) { + .cb-replayer-controls-spacer { + height: 70px; + } + + .cb-replayer-controls-shell { + padding: 0 0.3rem 0.3rem; + } + + .cb-replayer-controls { + padding: 0.35rem 0.45rem; + } + + .cb-replayer-controls__main { + gap: 0.45rem; + } + + .cb-replayer-controls__time { + font-size: 0.64rem; + } + + .cb-replayer-settings { + right: -0.15rem; + width: min(360px, calc(100vw - 0.6rem)); + } +} + +.cb-langs-dropdown { + height: 300px; + overflow-y: auto; +} + +.cb-username-td { + max-width: 350px; +} + +.cb-check-result-bar { + width: 72px; + height: 4px; + background: white; + position: relative; + border-radius: 0.25rem; + + @media (max-width: $sm) { + & { + border-width: 1px; + } + } + + & > .cb-asserts-progress { + position: absolute; + height: 100%; + border-radius: 0.25rem; + background: #809b88; + } + + &.ok { + & > .cb-asserts-progress { + background: $gold; + } + } + + &.failure { + & > .cb-asserts-progress { + background: $error; + } + } + + &.error { + & > .cb-asserts-progress { + background: $error; + width: 100% !important; + } + } + + &.started { + background: #bebebe; + } +} + +.cb-player-loading { + position: absolute; + left: 55px; +} + +.cb-polyglot { + width: 65px; + height: 65px; + background: url('../static/images/achievements/polyglot.png'); + background-size: cover; + padding: 5px; +} + +.cb-polyglot-icons { + max-height: 45px; + overflow: hidden; +} + +.cb-achievement-badge { + width: 86px; + min-height: 50px; + border-radius: 8px; + border: 1px solid rgba(255, 255, 255, 0.15); + padding: 5px 6px; + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: center; + color: #171720; + font-size: 9px; + line-height: 1.1; + text-align: center; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18); +} + +.cb-achievement-badge__label { + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.02em; + font-size: 8px; + white-space: nowrap; + overflow: hidden; + width: 100%; +} + +.cb-achievement-badge__value { + font-weight: 900; + font-size: 15px; + line-height: 1; + display: flex; + align-items: center; + justify-content: center; + min-height: 15px; +} + +.cb-achievement-badge__icons { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 3px; + min-height: 12px; +} + +.cb-achievement-badge__grade-icon { + display: flex; + align-items: center; + justify-content: center; + width: 100%; + margin: auto 0; +} + +.cb-achievements-grid { + display: grid; + grid-template-columns: repeat(3, max-content); + gap: 4px; + justify-content: center; +} + +.cb-achievement-badge--gold { + background: linear-gradient( + 145deg, + color-mix(in srgb, var(--cb-grade-grand_slam), #fff 12%), + var(--cb-grade-grand_slam) + ); +} + +.cb-achievement-badge--silver { + background: linear-gradient( + 145deg, + color-mix(in srgb, var(--cb-grade-masters), #fff 12%), + var(--cb-grade-masters) + ); +} + +.cb-achievement-badge--bronze { + background: linear-gradient( + 145deg, + color-mix(in srgb, var(--cb-grade-elite), #fff 12%), + var(--cb-grade-elite) + ); +} + +.cb-achievement-badge--steel { + background: linear-gradient( + 145deg, + color-mix(in srgb, var(--cb-grade-challenger), #fff 12%), + var(--cb-grade-challenger) + ); +} + +.cb-achievement-badge--iron { + background: linear-gradient( + 145deg, + color-mix(in srgb, var(--cb-grade-rookie), #fff 12%), + var(--cb-grade-rookie) + ); +} + +.cb-achievement-badge--grade-rookie { + background: linear-gradient( + 145deg, + color-mix(in srgb, var(--cb-grade-rookie), #fff 12%), + var(--cb-grade-rookie) + ); +} + +.cb-achievement-badge--grade-challenger { + background: linear-gradient( + 145deg, + color-mix(in srgb, var(--cb-grade-challenger), #fff 12%), + var(--cb-grade-challenger) + ); +} + +.cb-achievement-badge--grade-pro { + background: linear-gradient( + 145deg, + color-mix(in srgb, var(--cb-grade-pro), #fff 12%), + var(--cb-grade-pro) + ); +} + +.cb-achievement-badge--grade-elite { + background: linear-gradient( + 145deg, + color-mix(in srgb, var(--cb-grade-elite), #fff 12%), + var(--cb-grade-elite) + ); +} + +.cb-achievement-badge--grade-masters { + background: linear-gradient( + 145deg, + color-mix(in srgb, var(--cb-grade-masters), #fff 12%), + var(--cb-grade-masters) + ); +} + +.cb-achievement-badge--grade-grand-slam { + background: linear-gradient( + 145deg, + color-mix(in srgb, var(--cb-grade-grand_slam), #fff 12%), + var(--cb-grade-grand_slam) + ); +} + +.cb-username { + font-size: 27px; +} + +.cb-heading { + font-size: 27px; +} + +.cb-profile-avatar { + width: min(100%, 180px); +} + +.cb-tournament-profile-avatar { + width: min(100%, 82px); +} + +.cb-user-avatar { + width: 25px; +} + +.cb-private-text { + color: var(--indigo); +} + +.cb-toast-close { + top: 5px; + right: 10px; +} + +.cb-messages-list { + top: 5px; + + @media (max-width: $sm) { + height: 240px; + max-height: 80%; + } +} + +.cb-lobby-widget-container { + min-height: 400px; + max-height: 500px; +} + +.cb-messages-container { + height: 400px; + + @media (max-width: $sm) { + height: auto; + max-height: 400px; + } +} + +.cb-players-container { + max-height: 500px; +} + +.cb-mute-icon { + position: fixed; + bottom: 32px; + right: 190px; + z-index: 5000; +} + +.cursor-pointer { + cursor: pointer; +} + +.x-bottom-0 { + bottom: 0; +} + +.x-bottom-75 { + bottom: 75%; +} + +.x-outline-none { + outline: none; +} + +.x-intent-background { + background-color: rgba($black, 0.25); +} + +.x-opacity-0 { + opacity: 0; +} + +.cb-opacity-05 { + opacity: 0.05; +} + +.cb-opacity-10 { + opacity: 0.1; +} + +.cb-opacity-25 { + opacity: 0.25; +} + +.cb-opacity-50 { + opacity: 0.5; +} + +.cb-opacity-75 { + opacity: 0.75; +} + +.cb-opacity-100 { + opacity: 1; +} + +.x-bg-gray { + background-color: $gray-300 !important; +} + +.x-rounded-bottom-right { + border-bottom-right-radius: $border-radius !important; +} + +.x-rounded-bottom-left { + border-bottom-left-radius: $border-radius !important; +} + +.x-username-truncated { + max-width: 180px; +} + +.bind-social { + padding: 0; + border: 0; + background: none; + + &:disabled { + color: gray; + } + + &:not([disabled]) { + color: $primary; + } + + &:hover:not([disabled]) { + color: $orange; + text-decoration: none; + box-shadow: 0 1px 0 0 currentColor; + transition-property: box-shadow, color; + transition-duration: 0.33s; + transition-timing-function: ease-out; + } +} + +.tournament-info-ratingMode-enter, +.game-room-preview-enter, +.game-room-builder-enter, +.game-room-builder-exit-active { + opacity: 0; + transform: translateX(100%); +} + +.tournament-info-playerMode-exit-active, +.tournament-info-playerMode-enter { + opacity: 0; + transform: translateX(-100%); +} + +.tournament-info-ratingMode-enter-active, +.tournament-info-playerMode-enter-active, +.game-room-preview-enter-active, +.game-room-builder-enter-active { + opacity: 1; + transform: translateX(0%); +} + +.tournament-info-ratingMode-exit, +.tournament-info-playerMode-exit, +.game-room-preview-exit, +.game-room-builder-exit { + opacity: 1; + transform: translateX(0%); +} + +.tournament-info-ratingMode-exit-active, +.game-room-preview-exit-active { + opacity: 0; + transform: translateX(100%); +} + +.tournament-info-ratingMode-enter-active, +.tournament-info-ratingMode-exit-active, +.tournament-info-playerMode-enter-active, +.tournament-info-playerMode-exit-active, +.game-room-preview-enter-active, +.game-room-preview-exit-active, +.game-room-builder-enter-active, +.game-room-builder-exit-active { + transition: + opacity 200ms, + transform 200ms; +} + +@keyframes ticker_1 { + 0% { + transform: translateX(100%); + } + + 100% { + transform: translateX(-100%); + } +} + +@keyframes ticker_2 { + 0% { + transform: translateX(0); + } + + 100% { + transform: translateX(-200%); + } +} + +@keyframes scale { + 0% { + transform: scale(0.5); + } + + 100% { + transform: scale(1); + } +} + +.animate { + animation-name: scale; + animation-duration: 0.7s; +} + +.popover { + max-width: 100%; + /* Max Width of the popover (depending on the container!) */ +} + +.cb-row-avatars { + direction: rtl; + list-style-type: none; + margin: 0; + padding: 0; +} + +.cb-row-avatar { + display: inline-block; + position: relative; + -webkit-transition: 0.2s ease; + transition: 0.2s ease; +} + +.cb-row-avatar:nth-child(n + 2) { + margin-right: -15px; +} + +.cb-row-avatars:hover .cb-row-avatar:nth-child(n + 2) { + margin-right: 3px; +} + +p, +td { + font-family: 'Montserrat', sans-serif; +} + +main { + flex: 1 1 auto; +} + +// Inertia inserts an extra root between the flex main and each page. Unlike the +// legacy page containers, that root has no Bootstrap width utility of its own. +main > #app { + min-width: 0; + width: 100%; +} + +.navbar-brand img { + max-height: 32px; + height: auto; + width: auto; +} + +.github-stars-badge { + display: inline-flex; + align-items: center; + gap: 0.3rem; + color: #dce2ea; + line-height: 1; + white-space: nowrap; +} + +.github-stars-badge__main, +.github-stars-badge__count { + display: inline-flex; + align-items: center; + min-height: 28px; + padding: 0.34rem 0.74rem; + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 0.5rem; + background: linear-gradient(180deg, #2d3138 0%, #24282e 100%); + box-shadow: 0 10px 18px rgba(0, 0, 0, 0.2); +} + +.github-stars-badge__main { + gap: 0.1rem; +} + +.github-stars-badge__icon { + width: 1rem; + height: 1rem; + margin-right: 0.32rem; + filter: brightness(0) invert(0.92); +} + +.github-stars-badge__label, +.github-stars-badge__count { + font-size: 0.85rem; + font-weight: 600; + letter-spacing: 0.01em; +} + +.github-stars-badge__count { + justify-content: center; + min-width: 3rem; + padding-left: 0.62rem; + padding-right: 0.62rem; + color: #ffffff; + background: linear-gradient(180deg, #343a42 0%, #2b3037 100%); +} + +.create-game-btn:hover { + background: linear-gradient(to bottom, #f5f5f5 0%, #ededed 100%); + text-shadow: 0 1px 0 #fff; +} + +.react-monaco-editor-container { + flex-grow: 1; +} + +.cb-game-control-container { + width: 250px; + min-width: 250px; +} + +.cb-game > [class*='col-'] { + min-width: 0; +} + +.cb-game-chat-layout, +.cb-game-chat-container { + min-width: 0; +} + +@media screen and (min-width: $md) { + .main-nav { + padding-left: clamp(0.25rem, 1vw, 0.5rem); + padding-right: clamp(0.25rem, 1vw, 0.5rem); + } + + .main-nav .btn { + padding: clamp(0.2rem, 0.5vw, 0.5rem) clamp(0.4rem, 1vw, 0.75rem); + font-size: clamp(0.75rem, 1vw, 0.875rem); + } + + .main-nav .github-stars-badge { + gap: 0.28rem; + } + + .main-nav .github-stars-badge__main, + .main-nav .github-stars-badge__count { + min-height: 26px; + padding-top: 0.28rem; + padding-bottom: 0.28rem; + } + + .main-nav .github-stars-badge__count { + min-width: clamp(2.6rem, 4vw, 3.2rem); + } + + .navbar-brand img { + max-height: clamp(28px, 5vw, 36px); + height: auto; + width: auto; + } + + .navbar-brand span { + font-size: clamp(13px, 1.5vw, 18px); + } +} + +@media (max-width: $xl) { + .cb-heading { + font-size: 21px; + } +} + +@media (max-width: $lg) { + .cb-heading { + font-size: 18px; + } + + .cb-stats-number { + font-size: 22px; + } + + .lead { + font-size: 14px; + } +} + +@media screen and (min-width: $md) { + .modal-dialog { + min-width: 700px; + /* New width for default modal */ + + & button.close { + color: white; + } + } +} + +@media (max-width: $sm) { + .navbar-brand img { + max-height: 28px !important; + height: auto !important; + width: auto !important; + } + + .cb-heading { + font-size: 20px; + } + + .cb-stats-number { + font-size: 30px; + } + + .lead { + font-size: 16px; + } + + .cb-game-control-container { + width: 100%; + min-width: 0; + flex-shrink: 0; + } + + .cb-game-chat-layout { + flex-direction: column; + } + + .cb-game-chat-container { + width: 100%; + min-height: 0; + height: auto !important; + } + + .main-nav { + margin-right: 0; + margin-left: 0; + padding-left: 0.5rem; + padding-right: 0.5rem; + } + + #navbarResponsive { + padding-top: 0.5rem; + } +} + +.invites-counter { + top: 0px; + left: 0px; +} + +.tag-btn-outline-orange { + border-color: $orange; + color: $orange; + @include button-outline-variant($orange); +} + +.cb-game-chat-container { + min-width: 250px; +} + +.hidden { + display: none; +} + +.footer-container { + display: flex; + justify-content: space-between; + text-align: center; + margin-top: 2em; + margin-bottom: 2em; +} + +.invalid-feedback { + color: red; + display: block; +} + +a:hover { + color: rgb(49, 47, 47); + text-decoration: none; +} + +.back-link { + padding: 0.375rem 0.75rem; + border: 2px solid transparent; + background-color: #5389aa; + margin-bottom: 0.5rem; +} + +.back-link:hover { + /* background-color: #3b637c;*/ + border: 2px solid #4b809e; + color: #fff; +} + +.cb-editor-remote-selection { + pointer-events: auto; + opacity: 0.3; +} + +.cb-editor-remote-cursor { + border: 1px solid; +} + +.cb-remote-opponent { + background-color: $orange; + border-color: red; +} + +.cb-remote-player { + background-color: var(--gray); + border-color: var(--secondary); +} + +.cb-loading-background { + background: rgba(255, 255, 255, 0.3); +} + +.cb-vw-75 { + width: 75vw; +} + +.cb-right-scroll-control { + background: linear-gradient( + to right, + transparent 0, + var(--light) 12px, + var(--light) 100% + ); +} + +.cb-left-scroll-control { + background: linear-gradient( + to left, + transparent 0, + var(--light) 12px, + var(--light) 100% + ); +} + +/* adapted styles from bootstrap 5.3*/ + +.cb-overflow-x-auto { + overflow-x: auto; +} + +.cb-overflow-x-hidden { + overflow-x: hidden; +} + +.cb-overflow-x-visible { + overflow-x: visible; +} + +.cb-overflow-x-scroll { + overflow-x: scroll; +} + +.cb-overflow-y-auto { + overflow-y: auto; +} + +.cb-overflow-y-hidden { + overflow-y: hidden; +} + +.cb-overflow-y-visible { + overflow-y: visible; +} + +.cb-overflow-y-scroll { + overflow-y: scroll; +} + +.cb-grid-divider { + position: relative; +} + +.cb-username-max-length { + max-width: 180px; +} + +$cb-radius: 0.5rem; +$cb-inset-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.35); + +/* Gold – warmer & shinier*/ +$cb-gold-top: #b08d5d; +$cb-gold-bottom: #9a7b51; + +/* Silver – lighter steel, better contrast*/ +$cb-silver-top: #565d6a; +$cb-silver-bottom: #4c535f; + +/* Bronze – brighter copper, still deep*/ +$cb-bronze-top: #5a3c29; +$cb-bronze-bottom: #4a3223; + +@mixin cb-place-bg($top, $bottom) { + background: linear-gradient(180deg, $top 0%, $bottom 100%) !important; + border-radius: $cb-radius; + box-shadow: $cb-inset-shadow; +} +.cb-gold-place-bg { + @include cb-place-bg($cb-gold-top, $cb-gold-bottom); +} + +.cb-silver-place-bg { + @include cb-place-bg($cb-silver-top, $cb-silver-bottom); +} + +.cb-bronze-place-bg { + @include cb-place-bg($cb-bronze-top, $cb-bronze-bottom); +} + +.cb-game-ranking-table .cb-gold-place-bg { + color: #fff; + + .cb-custom-event-td, + .cb-custom-event-name { + color: #fff; + } +} + +/* .cb-gold-place-bg { + background: linear-gradient(180deg, #8f734c 0%, #7f6442 100%) !important; + border-radius: 0.5rem; + box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.35); +} + +.cb-silver-place-bg { + background: linear-gradient(180deg, #3a3f4a 0%, #343944 100%) !important; + border-radius: 0.5rem; + box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.35); +} + +.cb-bronze-place-bg { + background: linear-gradient(180deg, #3a271a 0%, #2f2016 100%) !important; + border-radius: 0.5rem; + box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.35); +} */ + +#tasklang-dropdown { + &-toggle, + &-menu { + min-width: 4.375rem; + } +} + +.dropdown-menu, +.cb-dropdown-menu { + & .dropdown-item.cb-dropdown-item { + color: white !important; + + &:hover:not(:active):not(.active), + &:focus:not(:active):not(.active) { + color: white !important; + background-color: $cb-bg-panel; + } + + &:active, + &.active { + color: white !important; + background-color: $cb-bg-panel; + } + } +} + +.cb-dark-select, +.cb-dark-select option { + color: white; + background-color: $cb-bg-panel; +} + +.cb-dark-select { + color-scheme: dark; +} + +div.cb-dropdown-menu { + transform: translate3d(-100%, 0, 0); +} + +.cb-height-info { + min-height: 300px; + height: 300px; + + .nav-link.active { + color: white; + border-bottom: 1px; + background-color: $cb-secondary-hover-background; + } + + .nav-link:hover { + color: white; + background-color: $cb-secondary-hover-background; + } + + .nav-link:not(.active):hover { + color: white; + background-color: $cb-secondary-hover-background; + border-bottom: 1px; + } + + @media (max-width: $sm) { + height: auto; + } +} + +@keyframes scale { +} + +.nav-tabs { + border-bottom: 1px solid $cb-border-color; + + & .bg-danger { + color: white; + } + + & .bg-info { + color: white; + } + + .nav-item.active { + color: white; + } + + .nav-item.active, + .nav-item:hover { + background-color: $cb-secondary-hover-background; + border-color: $cb-border-color; + border-top: 1px solid $cb-border-color; + border-right: 1px solid $cb-border-color; + border-left: 1px solid $cb-border-color; + } + + .nav-item:not(.active) { + color: var(--gray); + opacity: 0.6; + background-color: #21242e; + border-color: #13151b; + } + + .nav-item:not(.active):hover { + color: white; + opacity: 1; + background-color: $cb-secondary-hover-background; + } + + .nav-item.cb-nav-item.active { + color: var(--white); + border-color: $cb-border-color; + } + + .nav-item.cb-nav-item.active, + .nav-item.cb-nav-item:hover { + background-color: $cb-secondary-hover-background; + border-bottom: 1px solid $cb-border-color; + /* border-top: 1px solid black;*/ + /* border-right: 1px solid black;*/ + /* border-left: 1px solid black;*/ + } + + .nav-item.cb-nav-item:not(.active) { + color: white; + } + + .nav-item.cb-nav-item:not(.active):hover { + color: white; + background: var(--gray); + } +} + +.spectator { + .monaco-scrollable-element { + margin-top: 18px; + } +} + +@media (max-width: $xl) { +} + +@media (max-width: $lg) { +} + +@media screen and (min-width: $md) { + .modal-dialog.cb-join-game-modal { + width: calc(100vw - 2rem); + min-width: 0; + max-width: 900px; + } + + .cb-join-game-modal table { + width: 100%; + table-layout: fixed; + } + + .cb-join-game-modal .cb-username-td { + max-width: 0; + } +} + +@media (max-width: $sm) { +} + +/* adapted styles from bootstrap 5.3*/ + +.user-select-none { + user-select: none; + -webkit-user-select: text; + /* Safari fallback only */ + -webkit-user-select: none; + /* Chrome/Safari */ + -moz-user-select: none; + /* Firefox */ + -ms-user-select: none; + /* IE10+ */ +} + +.scroll-button { + background-image: url('../static/images/arrowDown.svg'); + width: 25px; + height: 25px; + bottom: 25px; + right: 5%; + background-size: cover; + background-repeat: no-repeat; + background-position: center; +} + +.scroll-button.invisible { + display: none; +} + +#editor.cb-editor-height { + height: 370px; +} + +#main-editor.cb-editor-height { + height: 410px; +} + +// Stream kiosk page: keep html/body transparent so OBS browser source +// composites the cb-stream editor over the live capture instead of a solid bg. +html:has(body.cb-stream-transparent-page), +body.cb-stream-transparent-page { + background: transparent !important; +} + +// Drop Monaco's focus/decoration borders on the stream kiosk so the editor +// blends into the OBS overlay instead of showing a blue outline. +body.cb-stream-transparent-page { + .monaco-editor, + .monaco-editor .overflow-guard, + .monaco-editor.focused, + .monaco-editor .decorationsOverviewRuler { + outline: none !important; + border: none !important; + } +} + +.cb-stream-tasks-stats { + background-color: #faff0f; + padding: 20px 16px; + border-radius: 25px; +} + +.cb-stream-output-title { + background-color: #faff0f; + + padding: 16px 20px; + border-radius: 25px; +} + +.cb-stream-editor-panel { + border: 4px solid #3c4168; +} + +.cb-stream-editor-left { + border-top-left-radius: 25px; + border-right: 0px; + border-bottom: 0px; +} + +.cb-stream-editor-right { + border-top-right-radius: 25px; + border-left: 0px; + border-bottom: 0px; +} + +.cb-stream-name { + width: 118px; + color: #faff0f; +} + +.cb-stream-output { + width: 100%; + border: 4px solid #3c4168; + border-radius: 25px; +} + +.cb-stream-task-description { + color: #b6a4ff; +} + +.cb-stream-widget { + background-color: #000000; +} + +.cb-stream-output-data { + color: #b6a4ff; + display: inline-block; + overflow: hidden; + white-space: nowrap; +} + +.cb-stream-full-video { + border: 4px solid #3c4168; + border-radius: 25px; +} + +.cb-stream-full-editor { + border: 4px solid #3c4168; + border-radius: 25px; +} + +.editor-left { + border-top-left-radius: 25px; + border-right: 0px; + border-bottom: 0px; +} + +.editor-right { + border-top-right-radius: 25px; + border-left: 0px; + border-bottom: 0px; +} + +.cb-stream-widget-text { + font-family: 'External'; + font-weight: 700; +} + +.cb-stream-widget-header-img-left { + background-size: cover; + width: 20%; + background-image: url(../static/images/stream/back-stripes.svg); + fill: #faff0f; +} + +.cb-stream-widget-header-img-right { + background-size: cover; + width: 20%; + background-image: url(../static/images/stream/stripes.svg); + fill: #faff0f; +} + +.cb-stream-widget-header-title { + width: 60%; + background-color: #faff0f; +} + +.cb-stream-player-number { + background-color: #faff0f; + padding: 20px 16px; + border-radius: 25px; +} + +.clan-title { + font-size: 14px; + font-weight: 900; + text-transform: uppercase; + letter-spacing: 1px; +} + +.clan-tag { + font-size: 24px; + display: block; +} + +.stat-item { + text-align: center; + border-right: 1px solid #3a3a45; + /* Vertical dividers */ + padding: 0 5px; +} + +.stat-line { + border-bottom: 1px solid #3a3a45; +} + +.stat-line:last-child { + border-bottom: none; +} + +.stat-item:last-child { + border-right: none; +} + +.stat-value { + font-size: 20px; + font-weight: 700; + /* Accent color for key numbers */ + line-height: 1.2; +} + +.stat-label { + font-size: 11px; +} + +.cb-font-size-small { + font-size: 12px; +} + +.cb-rounded { + border-radius: $cb-border-radius; +} + +.cb-rounded-top { + border-top-left-radius: $cb-border-radius; + border-top-right-radius: $cb-border-radius; +} + +.cb-rounded-bottom { + border-top-left-radius: $cb-border-radius; + border-top-right-radius: $cb-border-radius; +} + +.cb-rounded-left { + border-top-left-radius: $cb-border-radius; + border-bottom-left-radius: $cb-border-radius; +} + +.cb-rounded-right { + border-top-right-radius: $cb-border-radius; + border-bottom-right-radius: $cb-border-radius; +} + +.cb-bg-panel { + background-color: $cb-bg-panel; + + &:not(.cb-toolbar):not(.cb-slider-timeline) { + background: $cb-bg-panel-background; + } + + &.form-control { + background-color: $cb-bg-highlight-panel; + } + + &.form-control:hover, + &.form-control:focus { + background-color: $cb-bg-panel; + } + + &.custom-select { + background-color: $cb-bg-panel; + transition: none; + } +} + +.cb-bg-highlight-panel { + background-color: $cb-bg-highlight-panel; + + &.form-control { + background-color: $cb-bg-highlight-panel; + color: white; + caret-color: white; + } + + &.form-control:hover, + &.form-control:focus { + background-color: $cb-bg-highlight-panel; + color: white; + } +} + +.cb-create-game { + display: flex; + flex-direction: column; + gap: 16px; +} + +.cb-create-game__section { + background: $cb-bg-highlight-panel; + border: 1px solid $cb-border-color; + border-radius: $cb-border-radius; + padding: 14px 16px 16px; + box-shadow: 0 8px 18px rgba(0, 0, 0, 0.25); +} + +.cb-create-game__section-title { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 8px; + + h5 { + letter-spacing: 0.02em; + } +} + +.cb-create-game__section-title--with-value { + margin-bottom: 12px; +} + +.cb-create-game__time-value { + color: white; + background: rgba(238, 55, 55, 0.16); + border: 1px solid rgba(238, 55, 55, 0.45); + padding: 2px 10px; + border-radius: 999px; + font-size: 0.85rem; +} + +.cb-create-game__footer { + display: flex; + justify-content: flex-end; + padding-top: 4px; +} + +.cb-border-color { + border-color: $cb-border-color !important; +} + +.cb-text { + color: $cb-text-color; + font-family: 'Arial', sans-serif; +} + +a.cb-text:hover { + color: white; +} + +.cb-text-light { + color: $cb-text-light-color; + font-family: 'Arial', sans-serif; +} + +a.cb-text-light:hover { + color: white; +} + +.cb-text-success { + color: $cb-success; +} + +.cb-text-danger { + color: #f04c5c; +} + +.cb-bg-secondary { + background-color: $cb-secondary; +} + +.cb-btn-secondary { + background-color: $cb-secondary; + border-color: $cb-secondary; + + &.show, + &.cb-active, + &:focus-visible { + background-color: $cb-secondary; + border-color: $cb-secondary-focus-border; + } + + &:hover:not(:disabled):not(.disabled) { + background-color: $cb-secondary-hover-background; + border-color: $cb-secondary-hover-border; + } + + &:focus:not(:disabled):not(.disabled) { + background-color: $cb-secondary; + border-color: $cb-secondary-focus-border; + } + + &:not(:disabled):not(.disabled):active, + &:not(:disabled):not(.disabled).active { + background-color: #2c303d; + border-color: #1c1e27; + } + + &:not(:disabled):not(.disabled):active, + &:not(:disabled):not(.disabled).active, + .show > &.dropdown-toggle { + color: $cb-text-color; + background-color: $cb-secondary; + border-color: #282c38; + } + + &:not(.active):not(:active).disabled, + &:not(.active):not(:active):disabled { + color: $cb-secondary-disabled-color; + background-color: $cb-secondary-disabled-background; + border-color: $cb-secondary-disabled-border; + } +} + +.cb-btn-outline-secondary { + color: $cb-text-color; + border-color: $cb-secondary; + + &.show, + &.cb-active, + &:focus-visible { + color: white; + background-color: $cb-secondary; + border-color: $cb-secondary-focus-border; + } + + &:hover:not(:disabled):not(.disabled) { + color: white; + background-color: $cb-secondary-hover-background; + border-color: $cb-secondary-hover-border; + } + + &:focus:not(:disabled):not(.disabled) { + color: white; + background-color: $cb-secondary; + border-color: $cb-secondary-focus-border; + } + + &:not(.active):not(:active).disabled, + &:not(.active):not(:active):disabled { + color: $cb-secondary-disabled-color; + border-color: $cb-secondary-disabled-border; + } + + &:not(:disabled):not(.disabled):active, + &:not(:disabled):not(.disabled).active, + .show > &.dropdown-toggle { + color: $cb-text-color; + background-color: $cb-secondary; + border-color: #282c38; + } + + &:not(:disabled):not(.disabled):active, + &:not(:disabled):not(.disabled).active { + color: white; + background-color: #2c303d; + border-color: #1c1e27; + } +} + +.cb-btn-success { + background-color: $cb-success; + border-color: $cb-success; + + &:hover:not(:disabled):not(.disabled) { + background-color: $cb-hovered-success; + border-color: $cb-hovered-success; + } + + &:focus:not(:disabled):not(.disabled) { + background-color: $cb-hovered-success; + border-color: $cb-hovered-success; + } +} + +.cb-btn-outline-success { + border-color: $cb-success; + + &:hover:not(:disabled):not(.disabled) { + background-color: $cb-hovered-success; + border-color: $cb-hovered-success; + } +} + +.cb-level-badge { + width: auto; + height: auto; +} + +.cb-separator { + width: 100%; + border: 1px solid gray; +} + +/* react big calendar for tournaments*/ + +.cb-rbc-calendar { + background-color: $cb-bg-panel; + border-color: $cb-border-color; + + & .rbc-day-bg { + border-color: $cb-border-color; + + &.rbc-off-range-bg { + background-color: $cb-bg-highlight-panel; + } + } + + & .rbc-btn-group button { + color: #e0e0e0; + background-color: $cb-bg-panel; + border-color: $cb-border-color; + } + + & .rbc-btn-group button:hover { + color: white; + background-color: #454552; + border-color: $cb-border-color; + } + + & .rbc-btn-group button:active, + & .rbc-btn-group button.rbc-active { + color: white; + background-image: none; + background-color: #555566 !important; + box-shadow: none; + border-color: $cb-border-color; + } + + & .rbc-toolbar-label { + color: #fff; + font-weight: bold; + border-color: $cb-border-color; + } + + & .rbc-header { + background-color: $cb-bg-panel; + padding: 8px 0; + border-color: $cb-border-color; + } + + & .rbc-row { + border-color: $cb-border-color; + } + + & .rbc-month-row { + min-height: 92px; + border-color: $cb-border-color; + } + + & .rbc-row-content { + z-index: auto; + } + + & .rbc-date-cell { + color: #e0e0e0; + border-color: $cb-border-color; + } + + & .rbc-show-more { + display: inline-block; + margin: 1px 4px 2px; + padding: 0 4px; + color: #cdd6e0; + font-size: 0.72rem; + font-weight: 600; + line-height: 1.3; + background-color: rgba(90, 123, 151, 0.25); + border-radius: 4px; + + &:hover { + color: #fff; + background-color: rgba(90, 123, 151, 0.5); + } + } + + & .rbc-off-range-bg { + background-color: #222228; + border-color: $cb-border-color; + } + + & .rbc-off-range .rbc-date-cell { + color: #888; + background-color: $cb-bg-highlight-panel; + border-color: $cb-border-color; + } + + & .rbc-now { + border-color: $cb-border-color; + } + + & .rbc-today { + background-color: #383845; + border-color: $cb-border-color; + /* Slightly lighter background for "today" */ + } + + & .rbc-allday-cell .rbc-today { + background-color: $cb-bg-panel; + } + + & .rbc-current-time-indicator { + height: 4px; + } +} + +.rbc-time-header, +.rbc-time-header-content, +.rbc-label, +.rbc-time-slot { + background-color: $cb-bg-panel; + border-color: $cb-border-color !important; +} + +.rbc-agenda-table { + border-color: $cb-border-color !important; + + & .rbc-agenda-time-cell, + & .rbc-agenda-date-cell, + & thead, + & tr, + & th { + border-color: $cb-border-color !important; + } +} + +.cb-rbc-calendar, +.cb-rbc-calendar * { + color: #e0e0e0; + border-color: $cb-border-color; +} + +.rbc-overlay { + color: white; + background-color: $cb-bg-panel; + border-color: $cb-border-color; + border-radius: $cb-border-radius; +} + +.rbc-overlay-header { + background-color: $cb-bg-highlight-panel; + border-top-left-radius: $cb-border-radius; + border-top-right-radius: $cb-border-radius; +} + +/* Event background (default is usually blue) */ +.cb-rbc-calendar .rbc-event { + background-color: #5a7b97; + border-color: $cb-border-color; + /* A visible event color */ + color: white; + /* Event text is white */ +} + +.rbc-agenda-empty { + height: 100%; + text-align: center; + align-content: center; +} + +.rbc-agenda-time-cell { + border: 1px solid $cb-border-color; +} + +.rbc-overlay .cb-rbc-event, +.rbc-row .cb-rbc-event, +.rbc-events-container .cb-rbc-event { + --evt-grade: #5a7b97; + + cursor: pointer; + color: #fff; + font-weight: 500; + border: 1px solid color-mix(in srgb, var(--evt-grade), transparent 45%); + border-left: 3px solid var(--evt-grade); + border-radius: 5px; + background: linear-gradient( + 135deg, + color-mix(in srgb, var(--evt-grade), transparent 48%), + color-mix(in srgb, var(--evt-grade), transparent 72%) + ); + transition: + background 0.12s ease, + box-shadow 0.12s ease; + + &.cb-rbc-rookie-event { + --evt-grade: var(--cb-grade-rookie); + } + + &.cb-rbc-challenger-event { + --evt-grade: var(--cb-grade-challenger); + } + + &.cb-rbc-pro-event { + --evt-grade: var(--cb-grade-pro); + } + + &.cb-rbc-masters-event { + --evt-grade: var(--cb-grade-masters); + } + + &.cb-rbc-elite-event { + --evt-grade: var(--cb-grade-elite); + } + + &.cb-rbc-grand-slam-event { + --evt-grade: var(--cb-grade-grand_slam); + } + + &:hover { + background: linear-gradient( + 135deg, + color-mix(in srgb, var(--evt-grade), transparent 30%), + color-mix(in srgb, var(--evt-grade), transparent 58%) + ); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); + } +} + +.cb-rbc-event { + --evt-grade: #5a7b97; + + border-color: $cb-border-color; + + & .rbc-agenda-event-cell { + cursor: pointer; + color: #fff; + border-color: $cb-border-color; + border-left: 3px solid var(--evt-grade); + background: color-mix(in srgb, var(--evt-grade), transparent 55%); + + &:hover { + background: color-mix(in srgb, var(--evt-grade), transparent 38%); + } + } + + &.cb-rbc-rookie-event { + --evt-grade: var(--cb-grade-rookie); + } + + &.cb-rbc-challenger-event { + --evt-grade: var(--cb-grade-challenger); + } + + &.cb-rbc-pro-event { + --evt-grade: var(--cb-grade-pro); + } + + &.cb-rbc-masters-event { + --evt-grade: var(--cb-grade-masters); + } + + &.cb-rbc-elite-event { + --evt-grade: var(--cb-grade-elite); + } + + &.cb-rbc-grand-slam-event { + --evt-grade: var(--cb-grade-grand_slam); + } +} + +/* Tournament schedule: segmented tabs, grade legend and history list */ +.cb-schedule-tabs { + display: inline-flex; + flex-wrap: wrap; + justify-content: center; + gap: 2px; + padding: 4px; + border: 1px solid $cb-border-color; + border-radius: 999px; + background-color: rgba(0, 0, 0, 0.2); +} + +.cb-schedule-tab { + border: 0; + background: transparent; + color: $cb-text-light-color; + opacity: 0.65; + padding: 7px 20px; + border-radius: 999px; + font-weight: 500; + font-size: 0.95rem; + line-height: 1.1; + white-space: nowrap; + outline: none; + transition: + background-color 0.15s ease, + color 0.15s ease, + opacity 0.15s ease; + + &:hover:not(:disabled):not(.active) { + opacity: 1; + background-color: rgba(90, 123, 151, 0.18); + } + + &:focus-visible { + box-shadow: 0 0 0 2px rgba(90, 123, 151, 0.6); + } + + &.active { + opacity: 1; + color: #fff; + font-weight: 600; + background-color: rgba(90, 123, 151, 0.55); + } + + &:disabled { + cursor: not-allowed; + opacity: 0.35; + } +} + +.cb-schedule-grade-legend { + column-gap: 18px; + row-gap: 6px; + font-size: 0.78rem; + color: rgba(255, 255, 255, 0.6); +} + +.cb-schedule-grade-item { + gap: 6px; +} + +.cb-schedule-grade-dot { + display: inline-block; + width: 9px; + height: 9px; + border-radius: 50%; + flex-shrink: 0; + box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.25); +} + +.cb-schedule-list { + border: 1px solid $cb-border-color; + border-radius: 8px; + overflow: hidden; +} + +.cb-schedule-list-head { + font-size: 0.75rem; + text-transform: uppercase; + letter-spacing: 0.03em; + color: rgba(255, 255, 255, 0.5); + border-bottom: 1px solid $cb-border-color; +} + +.cb-schedule-list-row { + color: $cb-text-light-color; + text-decoration: none; + gap: 8px; + border-left: 3px solid var(--cb-row-grade, transparent); + border-bottom: 1px solid rgba(76, 76, 90, 0.5); + transition: background-color 0.15s ease; + + &:last-child { + border-bottom: 0; + } + + &:hover { + color: $cb-text-light-color; + text-decoration: none; + background-color: rgba(90, 123, 151, 0.15); + } + + .cb-schedule-col-action { + opacity: 0; + transition: opacity 0.15s ease; + } + + &:hover .cb-schedule-col-action { + opacity: 1; + } +} + +.cb-schedule-col-grade { + flex: 1 1 40%; + min-width: 0; +} + +.cb-schedule-col-date, +.cb-schedule-col-duration { + flex: 0 0 auto; + width: 120px; + color: rgba(255, 255, 255, 0.75); +} + +.cb-schedule-col-players { + flex: 0 0 auto; + width: 90px; + color: rgba(255, 255, 255, 0.75); +} + +.cb-schedule-col-winner { + flex: 1 1 20%; + min-width: 0; +} + +.cb-schedule-col-action { + flex: 0 0 auto; + width: 80px; + text-align: right; +} + +.cb-schedule-row-name { + font-weight: 600; +} + +.cb-schedule-row-grade-label { + color: rgba(255, 255, 255, 0.5); +} + +.cb-schedule-winner-avatar { + width: 24px; + height: 24px; + border-radius: 50%; + object-fit: cover; +} + +@media (max-width: 767px) { + .cb-schedule-col-date, + .cb-schedule-col-duration, + .cb-schedule-col-players, + .cb-schedule-col-winner { + width: auto; + font-size: 0.85rem; + } +} + +.card.cb-card { + background-color: transparent; + border-color: $cb-border-color; + + & .card-header { + color: white; + font-family: 'Arial', sans-serif; + background-color: $cb-bg-highlight-panel; + border-color: $cb-border-color; + } + + & .card-footer { + color: white; + font-family: 'Arial', sans-serif; + background-color: $cb-bg-highlight-panel; + border-color: $cb-border-color; + } + + & .card-text { + color: white; + font-family: 'Arial', sans-serif; + } + + & code { + color: white; + } +} + +.cb-password-input { + padding-right: 3rem; +} + +.cb-password-toggle { + top: 0; + right: 0; + z-index: 3; + width: 2.75rem; + height: 100%; + padding: 0.375rem; + color: rgba(255, 255, 255, 0.7); + + &:hover, + &:focus { + color: white; + text-decoration: none; + } + + &.cb-password-toggle-invalid { + right: 2rem; + } +} + +.text-white { + fill: white; + + & pre { + color: white; + fill: white; + } + + & code { + color: white; + fill: white; + } +} + +.nav-pills .nav-link { + color: white; + + &:hover:not(.active) { + color: var(--danger); + } +} + +.pagination { + & .page-item.disabled .page-link, + & .page-link { + color: white; + background-color: $cb-bg-highlight-panel; + border-color: $cb-bg-highlight-panel; + } + + & .page-item.active .page-link { + color: white; + background-color: $cb-bg-panel; + border-color: $cb-bg-highlight-panel; + } + + & .page-link:hover { + color: var(--danger); + background-color: $cb-bg-panel; + border-color: $cb-bg-highlight-panel; + } +} + +/* &:hover {*/ +/* background-color: rgba(90, 123, 151, 0.2);*/ +/* }*/ +/**/ + +.btn-link { + color: white; +} + +.cb-subtle-background { + background: radial-gradient(circle at 50% 0%, #3a3b40 0%, $cb-bg-panel 100%); +} + +.cb-season-layout { + margin-left: 0; + margin-right: 0; +} + +.cb-season-main-card, +.cb-season-profile-card, +.cb-nearby-card, +.cb-lobby-chat-card, +.cb-tournament-card { + width: 100%; + overflow: hidden; +} + +.cb-tournament-grid { + gap: 8px; +} + +.cb-tournament-card { + margin-right: 0 !important; + max-width: 350px; +} + +.cb-tournament-title-wrap, +.cb-tournament-meta-row { + width: 100%; +} + +.cb-tournament-header { + gap: 8px; +} + +.cb-tournament-title { + max-width: 100%; + min-width: 0; +} + +.cb-tournament-gold, +.cb-tournament-points-value, +.cb-tournament-starts-in { + color: $gold !important; +} + +.cb-tournament-starts-in .text-warning { + color: $gold !important; +} + +.cb-tournament-meta { + min-width: 0; + flex: 1 1 auto; +} + +.cb-tournament-actions { + gap: 6px; +} + +.cb-tournament-top-actions { + flex-shrink: 0; +} + +.cb-tournament-main-action { + min-width: 84px; +} + +.cb-tournament-info-icon-btn { + display: inline-flex; + align-items: center; + justify-content: center; + width: 30px; + min-width: 30px; + height: 30px; + padding: 0 !important; + font-size: 13px; +} + +.cb-lobby-chat-main { + flex: 0 0 66.666%; + max-width: 66.666%; + min-width: 0; +} + +.cb-lobby-chat-sidebar { + flex: 0 0 33.333%; + max-width: 33.333%; +} + +.cb-lobby-chat-card .text-muted { + color: #a6a6b3 !important; +} + +.cb-lobby-chat-action { + display: inline-flex; + align-items: center; + justify-content: center; + width: 32px; + min-width: 32px; + height: 32px; +} + +.cb-season-actions .btn { + flex: 1 1 0; + min-width: 0; + margin-bottom: 8px; + display: inline-flex; + align-items: center; + justify-content: center; + height: 40px; + padding-top: 0; + padding-bottom: 0; + line-height: 1; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.cb-season-actions .btn:last-child { + margin-bottom: 0; +} + +.cb-nearby-user-name { + min-width: 0; + max-width: 110px; +} + +.cb-nearby-metric { + width: 72px; +} + +.cb-league-description .btn-link { + white-space: normal; + text-align: left; +} + +.cb-lobby-controls-primary { + gap: 8px; +} + +.cb-player-stats-bar { + display: flex; + flex-wrap: wrap; + align-items: stretch; + gap: 10px 0; + padding: 12px 6px; + background: linear-gradient( + 135deg, + rgba($cb-bg-panel, 0.55), + rgba($cb-bg-highlight-panel, 0.9) + ); + border: 1px solid rgba($cb-border-color, 0.6); +} + +.cb-player-stat { + display: flex; + min-width: 84px; + padding: 0 18px; + flex-direction: column; + gap: 3px; + justify-content: center; + + & + & { + border-left: 1px solid rgba($cb-border-color, 0.55); + } +} + +.cb-player-stat-label { + color: rgba($cb-text-color, 0.85); + font-size: 10px; + font-weight: 700; + letter-spacing: 0.07em; + text-transform: uppercase; +} + +.cb-player-stat-value { + color: $cb-text-light-color; + font-size: 20px; + font-weight: 700; + line-height: 1.1; + font-variant-numeric: tabular-nums; +} + +.cb-player-stat--place .cb-player-stat-value { + color: $warning; +} + +.cb-player-stat--score .cb-player-stat-value { + color: #fff; +} + +.cb-player-record { + display: inline-flex; + gap: 6px; + align-items: baseline; + font-size: 18px; +} + +.cb-player-record-win { + color: $success; +} + +.cb-player-record-loss { + color: $danger; +} + +.cb-player-record-draw { + color: rgba($cb-text-color, 0.9); +} + +.cb-player-record-sep { + color: rgba($cb-text-color, 0.5); + font-weight: 400; +} + +/* Tournament join / hero panel (shown to users who have not joined yet) */ +.cb-join-hero { + display: flex; + flex-direction: column; + gap: 1.35rem; + padding: 1.75rem; + border-radius: $cb-border-radius; + border: 1px solid rgba($cb-border-color, 0.6); + background: + radial-gradient( + 130% 130% at 100% 0%, + rgba($secondary, 0.22), + transparent 55% + ), + linear-gradient( + 135deg, + rgba($cb-bg-panel, 0.95), + rgba($cb-bg-highlight-panel, 0.96) + ); +} + +.cb-join-hero-head { + display: flex; + align-items: center; + gap: 1rem; +} + +.cb-join-hero-icon { + display: inline-flex; + align-items: center; + justify-content: center; + flex: 0 0 auto; + width: 56px; + height: 56px; + border-radius: 14px; + font-size: 24px; + color: #fff; + background: linear-gradient( + 135deg, + lighten($secondary, 6%), + darken($secondary, 10%) + ); + box-shadow: 0 8px 22px rgba(0, 0, 0, 0.4); +} + +.cb-join-hero-title { + margin: 0; + font-size: 1.5rem; + font-weight: 700; + line-height: 1.15; + color: $cb-text-light-color; +} + +.cb-join-hero-subtitle { + margin: 0.2rem 0 0; + color: rgba($cb-text-light-color, 0.72); + font-size: 0.95rem; +} + +.cb-join-meta { + display: flex; + flex-wrap: wrap; + gap: 0.6rem; +} + +.cb-join-meta-item { + display: flex; + align-items: center; + gap: 0.6rem; + min-width: 104px; + padding: 0.6rem 0.9rem; + border-radius: 12px; + border: 1px solid rgba($cb-border-color, 0.5); + background: rgba($cb-bg-highlight-panel, 0.6); +} + +.cb-join-meta-icon { + color: lighten($secondary, 12%); + font-size: 16px; +} + +.cb-join-meta-text { + display: flex; + flex-direction: column; + line-height: 1.15; +} + +.cb-join-meta-value { + color: $cb-text-light-color; + font-weight: 700; + font-size: 1rem; + font-variant-numeric: tabular-nums; +} + +.cb-join-meta-label { + color: rgba($cb-text-color, 0.85); + font-size: 10px; + font-weight: 700; + letter-spacing: 0.06em; + text-transform: uppercase; +} + +.cb-join-actions { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 0.75rem; +} + +.cb-join-primary-btn .btn { + padding: 0.6rem 1.7rem; + font-size: 1rem; + font-weight: 700; + color: #fff; + border-color: $secondary; + background: linear-gradient( + 135deg, + lighten($secondary, 6%), + darken($secondary, 10%) + ); +} + +.cb-join-primary-btn .btn:hover:not(:disabled), +.cb-join-primary-btn .btn:focus:not(:disabled) { + color: #fff; + filter: brightness(1.08); + box-shadow: 0 6px 18px rgba($secondary, 0.4); +} + +.cb-join-description { + padding-top: 1.1rem; + border-top: 1px solid rgba($cb-border-color, 0.5); + color: rgba($cb-text-light-color, 0.8); + + p:last-child { + margin-bottom: 0; + } +} + +/* Generic empty-state block (e.g. "no matches yet") */ +.cb-empty-state { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 0.85rem; + min-height: 240px; + padding: 2.75rem 1.5rem; + text-align: center; + color: rgba($cb-text-color, 0.9); +} + +.cb-empty-state-icon { + display: inline-flex; + align-items: center; + justify-content: center; + width: 66px; + height: 66px; + border-radius: 50%; + font-size: 26px; + color: rgba($cb-text-light-color, 0.7); + background: rgba($cb-bg-highlight-panel, 0.7); + border: 1px solid rgba($cb-border-color, 0.5); +} + +.cb-empty-state-title { + color: $cb-text-light-color; + font-size: 1.05rem; + font-weight: 700; +} + +.cb-empty-state-text { + max-width: 340px; + font-size: 0.9rem; + line-height: 1.4; +} + +/* Tournament control panel: keep the stats + pane-selector header a consistent + height across every panel (matches the player stats bar height). */ +@media (min-width: 768px) { + .cb-tournament-control-panel { + min-height: 60px; + } +} + +/* Tournament header polish */ +.cb-tournament-header-title { + color: $cb-text-light-color; + font-weight: 700; + letter-spacing: 0.01em; +} + +.cb-tournament-header-meta { + display: flex; + flex-wrap: wrap; + gap: 0.5rem; + margin-top: 0.85rem; +} + +.cb-tournament-header-meta-item { + display: inline-flex; + align-items: center; + gap: 0.4rem; + padding: 0.3rem 0.65rem; + border-radius: 999px; + font-size: 0.8rem; + font-weight: 600; + color: rgba($cb-text-light-color, 0.85); + background: rgba($cb-bg-highlight-panel, 0.7); + border: 1px solid rgba($cb-border-color, 0.5); + + .cb-tournament-header-meta-icon { + color: lighten($secondary, 12%); + font-size: 0.8rem; + } +} + +/* Tournament chat: a compact single-room dark panel */ +.cb-tournament-chat { + height: 450px; + overflow: hidden; + border: 1px solid rgba($cb-border-color, 0.65); + background: linear-gradient( + 180deg, + rgba($cb-bg-panel, 0.98), + rgba(#111218, 0.98) + ); +} + +.cb-tournament-chat-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 0.75rem; + min-height: 64px; + padding: 0.75rem 1rem; + border-bottom: 1px solid rgba($cb-border-color, 0.6); + background: rgba($cb-bg-highlight-panel, 0.38); +} + +.cb-tournament-chat-title { + color: $cb-text-light-color; + font-size: 0.95rem; + font-weight: 700; + line-height: 1.2; +} + +.cb-tournament-chat-subtitle { + margin-top: 0.15rem; + overflow: hidden; + color: rgba($cb-text-color, 0.82); + font-size: 0.75rem; + line-height: 1.2; + text-overflow: ellipsis; + white-space: nowrap; +} + +.cb-tournament-chat-clean { + flex: 0 0 auto; + padding: 0.3rem 0.65rem; + color: $danger; + font-size: 0.75rem; + font-weight: 600; + border: 1px solid rgba($danger, 0.32); + border-radius: 999px; + background: rgba($danger, 0.08); + + &:hover:not(:disabled), + &:focus:not(:disabled) { + color: #ff6b78; + border-color: rgba($danger, 0.55); + background: rgba($danger, 0.16); + } + + &:disabled { + opacity: 0.45; + } +} + +.cb-tournament-chat-messages { + padding: 0.35rem 0; + background: rgba(#111218, 0.2); + + .cb-messages-list { + top: 0; + padding: 0.35rem 0.85rem 0.75rem !important; + color: rgba($cb-text-light-color, 0.86); + font-size: 0.9rem; + } + + .cb-messages-list > li { + padding: 0.3rem 0.45rem; + margin-bottom: 0.1rem !important; + border-radius: 6px; + + &:hover { + background: rgba($cb-bg-highlight-panel, 0.32); + } + } +} + +.cb-tournament-chat-ban { + display: inline-flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + margin-left: 0.4rem; + padding: 0; + color: rgba($danger, 0.78); + border: 1px solid transparent; + border-radius: 6px; + background: transparent; + + &:hover, + &:focus { + color: #ff6b78; + border-color: rgba($danger, 0.35); + background: rgba($danger, 0.12); + } +} + +.cb-chat-message-delete { + display: inline-flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + margin-left: 0.4rem; + padding: 0; + color: rgba($cb-text-color, 0.85); + border: 1px solid transparent; + border-radius: 6px; + background: transparent; + + &:hover, + &:focus { + color: #ff6b78; + border-color: rgba($danger, 0.35); + background: rgba($danger, 0.12); + } +} + +.cb-tournament-chat-composer { + padding: 0.75rem; + border-top: 1px solid rgba($cb-border-color, 0.6); + background: rgba(#111218, 0.48); +} + +.cb-tournament-chat-form { + margin: 0; +} + +.cb-tournament-chat-input-group { + border: 1px solid rgba($cb-border-color, 0.78); + border-radius: 10px; + background: rgba(#0f1015, 0.82); + transition: + border-color 0.15s ease, + box-shadow 0.15s ease; + + &:focus-within { + border-color: rgba($secondary, 0.9); + box-shadow: 0 0 0 3px rgba($secondary, 0.15); + } +} + +.cb-tournament-chat-input { + height: 44px; + padding: 0 0.9rem; + color: $cb-text-light-color !important; + border: 0 !important; + border-radius: 9px 0 0 9px !important; + outline: 0; + background: transparent !important; + box-shadow: none !important; + + &::placeholder { + color: rgba($cb-text-color, 0.68); + } + + &:disabled { + color: rgba($cb-text-color, 0.55) !important; + background: rgba(#000, 0.12) !important; + } +} + +.cb-tournament-chat-emoji { + color: rgba($cb-text-light-color, 0.8); + border: 0; + border-left: 1px solid rgba($cb-border-color, 0.55); + border-radius: 0; + background: transparent; + + &:hover, + &:focus { + color: #fff; + background: rgba($cb-bg-highlight-panel, 0.7); + } +} + +.cb-tournament-chat-send { + min-width: 76px; + padding: 0 1rem; + color: $cb-text-light-color; + font-weight: 700; + border: 0; + border-left: 1px solid rgba($cb-border-color, 0.7); + border-radius: 0 9px 9px 0; + background: rgba($secondary, 0.82); + + &:hover:not(:disabled), + &:focus:not(:disabled) { + color: #fff; + background: $secondary; + } + + &:disabled { + color: rgba($cb-text-color, 0.6); + background: rgba($cb-bg-highlight-panel, 0.55); + opacity: 1; + } +} + +.cb-tournament-match { + position: relative; + display: grid; + padding: 7px 16px 7px 20px; + margin: 6px 12px; + grid-template-columns: minmax(0, 1fr) auto; + gap: 16px; + align-items: center; + overflow: hidden; + background: rgba($cb-bg-highlight-panel, 0.42); + border: 1px solid rgba($cb-border-color, 0.72); + border-radius: $cb-border-radius; + transition: + background-color 120ms ease, + border-color 120ms ease, + transform 120ms ease, + box-shadow 120ms ease; + + &::before { + position: absolute; + top: 0; + bottom: 0; + left: 0; + width: 4px; + background: rgba($cb-border-color, 0.9); + content: ''; + } + + &:hover { + background: rgba($cb-bg-highlight-panel, 0.68); + border-color: rgba($cb-border-color, 1); + transform: translateY(-1px); + box-shadow: 0 6px 18px rgba(0, 0, 0, 0.28); + } +} + +.cb-tournament-match--won::before { + background: linear-gradient(180deg, $warning, darken($warning, 12%)); +} + +.cb-tournament-match--lost::before { + background: linear-gradient(180deg, $danger, darken($danger, 12%)); +} + +.cb-tournament-match--playing::before { + background: linear-gradient(180deg, $success, darken($success, 12%)); +} + +.cb-tournament-match--pending::before, +.cb-tournament-match--neutral::before { + background: rgba($cb-border-color, 0.9); +} + +.cb-tournament-match-body { + min-width: 0; +} + +.cb-tournament-match-summary { + display: grid; + grid-template-columns: auto minmax(0, 1fr) auto; + gap: 10px 14px; + align-items: center; +} + +.cb-tournament-match-header, +.cb-tournament-match-players, +.cb-tournament-match-meta, +.cb-tournament-match-meta-item, +.cb-tournament-match-action { + display: flex; + align-items: center; +} + +.cb-tournament-match-header { + gap: 14px; +} + +.cb-tournament-match-round { + display: inline-flex; + width: 40px; + height: 26px; + align-items: center; + justify-content: center; + color: $cb-text-light-color; + background: rgba($cb-bg-panel, 0.78); + border: 1px solid rgba($cb-border-color, 0.65); + border-radius: 999px; + font-size: 12px; + font-weight: 700; + letter-spacing: 0.02em; + font-variant-numeric: tabular-nums; +} + +.cb-tournament-match-result { + display: inline-flex; + min-width: 70px; + + .badge { + padding: 4px 10px; + border-radius: 999px; + font-size: 11px; + font-weight: 700; + letter-spacing: 0.05em; + text-transform: uppercase; + } +} + +.cb-tournament-match-players { + min-width: 0; + gap: 16px; + padding-right: 6px; +} + +.cb-tournament-match-vs { + color: rgba($cb-text-color, 0.72); + font-size: 11px; + font-weight: 700; + letter-spacing: 0.08em; +} + +.cb-tournament-match-score { + display: inline-flex; + justify-content: center; + min-width: 46px; + margin-left: 8px; + padding: 1px 9px; + border-radius: 999px; + font-size: 12px; + font-weight: 700; + font-variant-numeric: tabular-nums; + color: $cb-text-light-color; + background: rgba($cb-bg-highlight-panel, 0.85); + border: 1px solid rgba($cb-border-color, 0.6); +} + +.cb-tournament-match-pct { + display: inline-block; + min-width: 42px; + margin-left: 6px; + font-size: 12px; + font-weight: 600; + font-variant-numeric: tabular-nums; + text-align: center; + color: $success; +} + +.cb-tournament-match-duration { + display: inline-flex; + justify-content: center; + min-width: 46px; + padding: 1px 9px; + border-radius: 999px; + font-size: 12px; + font-weight: 700; + font-variant-numeric: tabular-nums; + color: $cb-text-light-color; + background: rgba($cb-bg-highlight-panel, 0.85); + border: 1px solid rgba($cb-border-color, 0.6); +} + +.cb-user-panel-place { + display: inline-flex; + align-items: center; + justify-content: center; + min-width: 32px; + padding: 1px 8px; + border-radius: 999px; + font-size: 12px; + font-weight: 700; + font-variant-numeric: tabular-nums; + color: $cb-text-light-color; + background: rgba($cb-bg-panel, 0.78); + border: 1px solid rgba($cb-border-color, 0.65); +} + +.cb-user-panel-head { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 6px 16px; +} + +.cb-user-panel-name { + display: inline-flex; + align-items: center; + font-weight: 600; + color: $cb-text-light-color; +} + +.cb-user-panel-stat { + display: inline-flex; + align-items: center; + gap: 2px; + font-size: 0.9rem; + color: rgba($cb-text-color, 0.9); + font-variant-numeric: tabular-nums; +} + +.cb-user-panel-stat-value { + color: $cb-text-light-color; + font-weight: 700; +} + +.cb-tournament-match-meta { + gap: 20px; + color: $cb-text-color; + font-size: 12px; + white-space: nowrap; +} + +.cb-tournament-match-meta-item { + gap: 8px; +} + +.cb-tournament-match-meta-icon { + display: inline-flex; + width: 16px; + align-items: center; + justify-content: center; +} + +.cb-tournament-match-action { + justify-content: center; + + .btn { + min-width: 34px; + } +} + +.cb-score-breakdown { + display: flex; + padding-top: 10px; + margin-top: 12px; + flex-direction: column; + gap: 6px; + color: $cb-text-light-color; + border-top: 1px solid rgba($cb-border-color, 0.52); +} + +.cb-score-formula-row { + display: flex; + min-height: 34px; + padding: 3px 8px; + align-items: center; + border-radius: 6px; + border-left: 2px solid transparent; +} + +.cb-score-formula-row--winner { + background: rgba($warning, 0.07); + border-left-color: rgba($warning, 0.75); +} + +.cb-score-player-label { + flex: 0 0 72px; + color: $cb-text-color; + font-size: 10px; + font-weight: 700; + letter-spacing: 0.06em; + text-transform: uppercase; +} + +.cb-score-total { + display: inline-flex; + flex: 0 0 90px; + gap: 4px; + align-items: baseline; + color: $warning; + + strong { + font-size: 17px; + line-height: 1; + font-variant-numeric: tabular-nums; + } + + span { + color: rgba($warning, 0.74); + font-size: 9px; + font-weight: 700; + text-transform: uppercase; + } +} + +.cb-score-equals, +.cb-score-operator { + color: rgba($cb-text-color, 0.64); + font-size: 13px; + font-weight: 700; +} + +.cb-score-equals { + margin-right: 8px; +} + +.cb-score-equation { + display: flex; + flex-wrap: wrap; + gap: 6px; + align-items: center; +} + +.cb-score-term { + display: inline-flex; + padding: 4px 9px; + gap: 7px; + align-items: baseline; + background: rgba($cb-bg-panel, 0.56); + border: 1px solid rgba($cb-border-color, 0.4); + border-radius: 5px; + line-height: 1.1; +} + +.cb-score-term-label { + color: $cb-text-color; + font-size: 8px; + font-weight: 700; + letter-spacing: 0.045em; + text-transform: uppercase; +} + +.cb-score-term-value { + color: $cb-text-light-color; + font-size: 13px; + font-weight: 700; + font-variant-numeric: tabular-nums; +} + +.cb-score-term-base { + border-color: rgba($primary, 0.35); + background: rgba($primary, 0.08); + + .cb-score-term-value { + color: lighten($primary, 12%); + } +} + +.cb-score-term-factor { + border-color: rgba(#b197fc, 0.35); + background: rgba(#b197fc, 0.08); + + .cb-score-term-value { + color: #b197fc; + } +} + +.cb-score-term-tests { + border-color: rgba($success, 0.35); + background: rgba($success, 0.08); + + .cb-score-term-value { + color: lighten($success, 8%); + } +} + +@media (max-width: $lg) { + .cb-tournament-match-summary { + grid-template-columns: auto minmax(0, 1fr); + } + + .cb-tournament-match-meta { + grid-column: 1 / -1; + } + + .cb-tournament-card { + max-width: 100%; + } + + .cb-season-actions .btn { + flex: 0 0 auto; + } + + .cb-lobby-chat-main, + .cb-lobby-chat-sidebar { + flex: 1 1 auto; + max-width: 100%; + } + + .cb-lobby-chat-sidebar { + border-left: none !important; + border-top: 1px solid #3a3a45; + border-radius: 0 0 $cb-border-radius $cb-border-radius; + } +} + +@media (max-width: $sm) { + .cb-tournament-match { + padding: 12px; + margin: 8px; + grid-template-columns: minmax(0, 1fr); + } + + .cb-tournament-match-summary { + grid-template-columns: minmax(0, 1fr); + gap: 12px; + } + + .cb-tournament-match-meta { + grid-column: auto; + flex-wrap: wrap; + gap: 10px 16px; + } + + .cb-tournament-match-action { + justify-content: flex-end; + } + + .cb-score-formula-row { + flex-wrap: wrap; + } + + .cb-score-player-label { + flex-basis: 74px; + } + + .cb-score-total { + flex-basis: auto; + } + + .cb-score-equals { + display: none; + } + + .cb-score-equation { + width: 100%; + margin-top: 6px; + } + + .cb-score-term { + flex: 1 1 auto; + } + + .cb-season-main-card { + padding: 14px !important; + } + + .cb-season-section-title .h4 { + font-size: 18px; + margin-bottom: 0; + } + + .cb-season-actions { + padding-top: 8px !important; + margin-top: 6px !important; + } + + .cb-season-actions .btn { + white-space: nowrap !important; + line-height: 1; + height: 40px; + padding: 0 12px; + } + + .cb-lobby-controls-primary { + flex-direction: column; + } + + .cb-lobby-controls-primary .btn { + margin-right: 0 !important; + } + + .cb-lobby-bottom-layout > .col-12, + .cb-season-layout > .col-12 { + padding-left: 0; + padding-right: 0; + } + + .cb-lobby-chat-card { + margin-top: 8px !important; + } + + .cb-lobby-widget-container { + min-height: 320px; + max-height: none; + } + + .cb-players-container { + max-height: 260px; + } + + .cb-nearby-row { + padding-top: 7px !important; + padding-bottom: 7px !important; + margin-left: 4px !important; + margin-right: 4px !important; + } + + .cb-nearby-user-name { + max-width: none; + } + + .cb-nearby-metric { + width: auto; + min-width: 58px; + } + + .cb-nearby-metric .stat-value { + font-size: 16px; + } + + .cb-season-stats .stat-value { + font-size: 18px; + } + + .clan-tag { + font-size: 20px; + } + + .stat-label { + font-size: 10px; + } + + .cb-league-description { + margin-top: 0 !important; + margin-bottom: 8px !important; + } + + .cb-league-description .card-header .btn { + padding-left: 0; + padding-right: 0; + font-size: 12px; + } + + .cb-tournament-grid { + flex-direction: column; + gap: 6px; + } + + .cb-tournament-card { + margin: 4px 0 !important; + } + + .cb-tournament-card-body { + padding: 12px !important; + } + + .cb-tournament-meta-row { + flex-direction: row; + flex-wrap: wrap; + align-items: flex-start; + gap: 8px; + } + + .cb-tournament-meta { + flex: 1 1 220px; + min-width: 0; + } + + .cb-tournament-top-actions { + margin-left: auto; + flex: 0 0 auto; + } + + .cb-tournament-actions { + justify-content: flex-end; + } + + .cb-tournament-actions .btn { + min-width: 84px; + } + + .cb-tournament-main-action { + min-width: 72px; + } + + .cb-tournament-info-icon-btn { + width: 28px; + min-width: 28px; + height: 28px; + } +} + +.cb-blur { + background: rgba(0, 0, 0, 0.3); + backdrop-filter: blur(16px); +} + +.arrow::after, +.bs-popover-bottom .arrow::after { + border-bottom-color: rgba(0, 0, 0); + + .cb-blur & { + border-bottom-color: rgba(0, 0, 0, 0.3); + } +} + +// Settings page +.cb-settings-page { + width: 100%; + max-width: 1120px; + margin: 0 auto; +} + +.cb-settings-page-header { + margin-bottom: 24px; + + h2 { + margin-bottom: 4px; + color: #fff; + font-size: clamp(2rem, 4vw, 2.75rem); + font-weight: 600; + letter-spacing: -0.03em; + } + + p { + margin: 0; + color: rgba(255, 255, 255, 0.55); + font-size: 15px; + } +} + +.cb-settings-section { + margin-bottom: 20px; + padding: 24px; + border: 1px solid rgba(255, 255, 255, 0.09); + border-radius: 14px; + background: + linear-gradient(145deg, rgba(46, 46, 59, 0.96), rgba(27, 27, 36, 0.98)), + $cb-bg-panel; + box-shadow: 0 12px 30px rgba(0, 0, 0, 0.16); +} + +.cb-settings-section-heading { + display: flex; + align-items: flex-start; + gap: 12px; + margin-bottom: 22px; + + h3 { + margin: 0; + color: #fff; + font-size: 20px; + font-weight: 600; + } + + p { + margin: 3px 0 0; + color: rgba(255, 255, 255, 0.5); + font-size: 14px; + } +} + +.cb-settings-section-icon { + display: inline-flex; + flex: 0 0 38px; + align-items: center; + justify-content: center; + width: 38px; + height: 38px; + border: 1px solid rgba(255, 106, 61, 0.24); + border-radius: 10px; + color: #ff825d; + background: rgba(255, 106, 61, 0.1); +} + +.cb-settings-profile-grid, +.cb-settings-security-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 4px 24px; + + .form-group { + min-width: 0; + } + + .form-control, + .dropdown-toggle { + min-height: 46px; + border-radius: 8px; + } +} + +.cb-settings-security-grid { + grid-template-columns: repeat(3, minmax(0, 1fr)); +} + +.cb-settings-label { + width: auto; + margin-bottom: 10px; + color: rgba(255, 255, 255, 0.72); + font-size: 14px; + font-weight: 600; +} + +.cb-settings-sound-heading { + align-items: center; +} + +.cb-settings-sound-toggle { + min-width: 116px; + border: 1px solid rgba(88, 190, 125, 0.48); + color: #9fddb5; + background: rgba(46, 160, 88, 0.1); + + &:hover, + &:focus { + color: #c7f0d5; + background: rgba(46, 160, 88, 0.18); + } + + &[aria-pressed='true'] { + border-color: rgba(255, 255, 255, 0.18); + color: rgba(255, 255, 255, 0.62); + background: rgba(255, 255, 255, 0.05); + } +} + +.cb-settings-sound-types { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 10px; +} + +.cb-settings-sound-option { + position: relative; + + label { + display: flex; + align-items: center; + gap: 9px; + min-height: 52px; + margin: 0; + padding: 12px 14px; + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 10px; + color: rgba(255, 255, 255, 0.68); + background: rgba(12, 12, 18, 0.3); + cursor: pointer; + transition: + border-color 0.16s ease, + color 0.16s ease, + background-color 0.16s ease, + transform 0.16s ease; + } + + label:hover { + border-color: rgba(255, 106, 61, 0.42); + color: #fff; + background: rgba(255, 106, 61, 0.07); + transform: translateY(-1px); + } +} + +.cb-settings-sound-input { + position: absolute; + width: 1px; + height: 1px; + opacity: 0; + + &:focus-visible + label { + outline: 2px solid #ff825d; + outline-offset: 2px; + } + + &:checked + label { + border-color: rgba(255, 106, 61, 0.72); + color: #fff; + background: linear-gradient( + 135deg, + rgba(255, 106, 61, 0.2), + rgba(238, 55, 55, 0.08) + ); + box-shadow: inset 0 0 0 1px rgba(255, 106, 61, 0.12); + } + + &:checked + label .cb-settings-sound-check { + opacity: 1; + transform: scale(1); + } +} + +.cb-settings-sound-check { + margin-left: auto; + color: #ff825d; + opacity: 0; + transform: scale(0.7); + transition: + opacity 0.16s ease, + transform 0.16s ease; +} + +.cb-settings-volume-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 14px; +} + +.cb-settings-volume-card { + padding: 16px; + border: 1px solid rgba(255, 255, 255, 0.08); + border-radius: 10px; + background: rgba(12, 12, 18, 0.28); + + > .d-flex > svg { + flex: 0 0 auto; + color: rgba(255, 255, 255, 0.48); + } +} + +.cb-settings-volume-label { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 10px; + color: rgba(255, 255, 255, 0.72); + font-size: 14px; + + strong { + color: #ff9a7b; + font-size: 13px; + font-variant-numeric: tabular-nums; + } +} + +.cb-settings-section-actions { + display: flex; + justify-content: flex-end; + margin-top: 8px; + padding-top: 18px; + border-top: 1px solid rgba(255, 255, 255, 0.08); + + .btn { + min-width: 144px; + min-height: 42px; + } +} + +.cb-settings-account-grid { + display: grid; + grid-template-columns: minmax(260px, 0.72fr) minmax(0, 1.28fr); + gap: 20px; + margin-bottom: 24px; +} + +.cb-settings-social-links { + > .d-flex { + margin-bottom: 8px !important; + padding: 12px 14px; + border: 1px solid rgba(255, 255, 255, 0.08); + border-radius: 9px; + background: rgba(12, 12, 18, 0.25); + } +} + +.cb-settings-device { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + gap: 10px; + margin-bottom: 8px; + padding: 13px 14px; + border: 1px solid rgba(255, 255, 255, 0.08); + border-radius: 9px; + background: rgba(12, 12, 18, 0.25); +} + +@media (max-width: 767.98px) { + .cb-settings-section { + padding: 18px; + } + + .cb-settings-profile-grid, + .cb-settings-security-grid, + .cb-settings-volume-grid, + .cb-settings-account-grid { + grid-template-columns: 1fr; + } + + .cb-settings-sound-types { + grid-template-columns: 1fr; + } + + .cb-settings-sound-heading { + flex-wrap: wrap; + + .cb-settings-sound-toggle { + width: 100%; + justify-content: center; + } + } + + .cb-settings-section-actions .btn { + width: 100%; + } +} diff --git a/services/app/apps/codebattle/assets/css/tournaments.scss b/apps/codebattle/assets/css/tournaments.scss similarity index 76% rename from services/app/apps/codebattle/assets/css/tournaments.scss rename to apps/codebattle/assets/css/tournaments.scss index 86fc2d689..d257337d0 100644 --- a/services/app/apps/codebattle/assets/css/tournaments.scss +++ b/apps/codebattle/assets/css/tournaments.scss @@ -1,3 +1,5 @@ +@use 'sass:color'; + *, *::after, *::before { @@ -8,7 +10,8 @@ display: flex; } -.round, .round-inner { +.round, +.round-inner { display: flex; flex-grow: 1; flex-direction: column; @@ -37,7 +40,7 @@ } .match::before { - content: ""; + content: ''; display: block; height: 30px; border-left: 2px solid purple; @@ -49,7 +52,7 @@ } .match:nth-child(odd)::after { - content: ""; + content: ''; display: block; border: 2px solid transparent; border-top-color: purple; @@ -62,7 +65,7 @@ } .match:nth-child(even)::after { - content: ""; + content: ''; display: block; border: 2px solid transparent; border-bottom-color: purple; @@ -81,7 +84,7 @@ } .match__content::before { - content: ""; + content: ''; display: block; width: 10px; border-bottom: 2px solid purple; @@ -92,6 +95,18 @@ } .tournament-bg-active { - background-color: #dedede !important; + background-color: #dedede !important; } +.cb-match-confirmation-modal .cb-match-confirmation-progress { + background-color: #2f2f38; + + .progress-bar { + background: linear-gradient( + 90deg, + color.adjust($gold, $lightness: -14%) 0%, + $gold 52%, + color.adjust($gold, $lightness: 8%) 100% + ); + } +} diff --git a/services/app/apps/codebattle/assets/js/__fixtures__/signUpData.json b/apps/codebattle/assets/js/__fixtures__/signUpData.json similarity index 87% rename from services/app/apps/codebattle/assets/js/__fixtures__/signUpData.json rename to apps/codebattle/assets/js/__fixtures__/signUpData.json index f340d3f7e..7d1b2dae4 100644 --- a/services/app/apps/codebattle/assets/js/__fixtures__/signUpData.json +++ b/apps/codebattle/assets/js/__fixtures__/signUpData.json @@ -81,14 +81,20 @@ ], [ "password validation: short password", - "11111", - "Should be from 6 to 16 characters", + "pass1", + "Should be at least 8 characters", "password" ], [ - "password validation: long password", - "11111111111111111", - "Should be from 6 to 16 characters", + "password validation: no letter", + "!@#$1234", + "Should contain at least one letter", + "password" + ], + [ + "password validation: no number", + "passwordonly", + "Should contain at least one number", "password" ], ["password validation: empty", "", "Password required", "password"] @@ -97,8 +103,8 @@ "data": { "name": "testName", "email": "valid@email.com", - "password": "testpassword!", - "passwordConfirmation": "testpassword!" + "password": "testpassword1!", + "passwordConfirmation": "testpassword1!" }, "route": "/api/v1/users", "headers": { diff --git a/services/app/apps/codebattle/assets/js/__fixtures__/testData.json b/apps/codebattle/assets/js/__fixtures__/testData.json similarity index 100% rename from services/app/apps/codebattle/assets/js/__fixtures__/testData.json rename to apps/codebattle/assets/js/__fixtures__/testData.json diff --git a/apps/codebattle/assets/js/__mocks__/react-select.tsx b/apps/codebattle/assets/js/__mocks__/react-select.tsx new file mode 100644 index 000000000..f8102ee41 --- /dev/null +++ b/apps/codebattle/assets/js/__mocks__/react-select.tsx @@ -0,0 +1,36 @@ +import React, { useState } from 'react'; +import { vi } from 'vitest'; + +const { createFilter } = await vi.importActual('react-select'); + +interface SelectOption { + name: string; +} + +interface SelectProps { + options: SelectOption[]; + onChange: (option: SelectOption) => void; + filterOption: (option: { data: SelectOption }, input: string) => boolean; +} + +function Select({ options, onChange, filterOption }: SelectProps) { + const [selectInput, setSelectInput] = useState('task'); + + return ( +
+ {options + .filter(({ name }) => filterOption({ data: { name } }, selectInput)) + .map((option) => ( + + ))} + +
+ ); +} + +export { createFilter }; +export default Select; diff --git a/apps/codebattle/assets/js/__mocks__/react-select/async.tsx b/apps/codebattle/assets/js/__mocks__/react-select/async.tsx new file mode 100644 index 000000000..eef4a93cd --- /dev/null +++ b/apps/codebattle/assets/js/__mocks__/react-select/async.tsx @@ -0,0 +1,39 @@ +import React, { useEffect, useState } from 'react'; + +interface Entity { + name: string; +} + +interface AsyncOption { + value: Entity; +} + +interface AsyncSelectProps { + loadOptions: (input: string, callback: (options: AsyncOption[]) => void) => void; + onChange: (option: AsyncOption) => void; +} + +function AsyncSelect({ loadOptions, onChange }: AsyncSelectProps) { + const [entities, setEntities] = useState([]); + + useEffect(() => { + const callback = (options: AsyncOption[]) => { + setEntities(options.map((option) => option.value)); + }; + + loadOptions('test', callback); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return ( +
+ {entities.map((entity) => ( + + ))} +
+ ); +} + +export default AsyncSelect; diff --git a/apps/codebattle/assets/js/__tests__/ChatInputEmoji.test.ts b/apps/codebattle/assets/js/__tests__/ChatInputEmoji.test.ts new file mode 100644 index 000000000..424ed6200 --- /dev/null +++ b/apps/codebattle/assets/js/__tests__/ChatInputEmoji.test.ts @@ -0,0 +1,12 @@ +import { getEmojiSearchQuery } from '../widgets/components/ChatInput'; + +describe('chat emoticon search', () => { + test('maps happy and sad text emoticons to the matching emoji', () => { + expect(getEmojiSearchQuery(':)')).toBe('smiley'); + expect(getEmojiSearchQuery(':(')).toBe('disappointed'); + }); + + test('keeps regular emoji shortcodes unchanged', () => { + expect(getEmojiSearchQuery(':rocket')).toBe('rocket'); + }); +}); diff --git a/apps/codebattle/assets/js/__tests__/ChatMessageDelete.test.tsx b/apps/codebattle/assets/js/__tests__/ChatMessageDelete.test.tsx new file mode 100644 index 000000000..60a2081e7 --- /dev/null +++ b/apps/codebattle/assets/js/__tests__/ChatMessageDelete.test.tsx @@ -0,0 +1,65 @@ +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import '@testing-library/jest-dom'; +import React from 'react'; + +import Message from '../widgets/components/Message'; + +vi.mock('react-redux', () => ({ useSelector: () => ({ name: 'General' }) })); + +test('shows a delete action on the current user own message and calls back with its id', async () => { + const user = userEvent.setup(); + const handleDelete = vi.fn(); + + render( + , + ); + + await user.click(screen.getByRole('button', { name: 'Delete message' })); + expect(handleDelete).toHaveBeenCalledWith(7); +}); + +test('hides the delete action on another user message for a non-privileged user', () => { + render( + , + ); + + expect(screen.queryByRole('button', { name: 'Delete message' })).not.toBeInTheDocument(); +}); + +test('shows the delete action on another user message when the viewer can delete any', async () => { + const user = userEvent.setup(); + const handleDelete = vi.fn(); + + render( + , + ); + + await user.click(screen.getByRole('button', { name: 'Delete message' })); + expect(handleDelete).toHaveBeenCalledWith(7); +}); diff --git a/apps/codebattle/assets/js/__tests__/ChatNotifications.test.ts b/apps/codebattle/assets/js/__tests__/ChatNotifications.test.ts new file mode 100644 index 000000000..981bf2645 --- /dev/null +++ b/apps/codebattle/assets/js/__tests__/ChatNotifications.test.ts @@ -0,0 +1,26 @@ +import { isIncomingPrivateMessage } from '../widgets/utils/chat'; + +vi.mock('@/inertia/pageProps', () => ({ + getPageProp: (key: string, fallback: unknown) => (key === 'current_user' ? { id: 7 } : fallback), +})); + +describe('private message notifications', () => { + test('recognizes a private message received by the current user', () => { + expect( + isIncomingPrivateMessage({ + userId: 9, + meta: { type: 'private', targetUserId: 7 }, + }), + ).toBe(true); + }); + + test('ignores sent private messages and public chat messages', () => { + expect( + isIncomingPrivateMessage({ + userId: 7, + meta: { type: 'private', targetUserId: 9 }, + }), + ).toBe(false); + expect(isIncomingPrivateMessage({ userId: 9, meta: { type: 'general' } })).toBe(false); + }); +}); diff --git a/apps/codebattle/assets/js/__tests__/ContributorsList.test.tsx b/apps/codebattle/assets/js/__tests__/ContributorsList.test.tsx new file mode 100644 index 000000000..b5abbccc9 --- /dev/null +++ b/apps/codebattle/assets/js/__tests__/ContributorsList.test.tsx @@ -0,0 +1,38 @@ +// +// import { configureStore, combineReducers } from '@reduxjs/toolkit'; +// import { render } from '@testing-library/react'; +import '@testing-library/jest-dom'; +// import { Provider } from 'react-redux'; +// +// import ContributorsList from '../widgets/pages/game/ContributorsList'; +// import reducers from '../widgets/slices'; + +vi.mock('@/inertia/pageProps', () => { + const pageProps = { local: 'en' }; + return { + getPageProp: (key: keyof typeof pageProps, fallback?: unknown) => pageProps[key] ?? fallback, + }; +}); + +const users: unknown[] = []; +beforeAll(() => { + globalThis.fetch = vi.fn().mockResolvedValue({ + ok: true, + json: async () => users, + }) as unknown as typeof fetch; +}); +// +test('rendering ContributorsList', async () => { + // const reducer = combineReducers(reducers); + // + // const preloadedState = { + // user: '', + // }; + // const store = configureStore({ + // reducer, + // preloadedState, + // }); + // const { findByText } = render(); + // expect(await findByText(/This users have contributed to this task:/)).toBeInTheDocument(); + expect(true).toBe(true); +}); diff --git a/apps/codebattle/assets/js/__tests__/CreateGameDialog.test.tsx b/apps/codebattle/assets/js/__tests__/CreateGameDialog.test.tsx new file mode 100644 index 000000000..a01038ae9 --- /dev/null +++ b/apps/codebattle/assets/js/__tests__/CreateGameDialog.test.tsx @@ -0,0 +1,348 @@ +import { configureStore, combineReducers } from '@reduxjs/toolkit'; +import { render, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import '@testing-library/jest-dom'; +import noop from 'lodash/noop'; +import omit from 'lodash/omit'; +import React, { type ReactElement } from 'react'; +import { Provider } from 'react-redux'; + +import * as invitesMiddleware from '../widgets/middlewares/Invite'; +import * as lobbyMiddlewares from '../widgets/middlewares/Lobby'; +import CreateGameDialog from '../widgets/pages/lobby/CreateGameDialog'; +import reducers from '../widgets/slices'; + +import { getTestData } from './helpers'; + +vi.mock('@/inertia/pageProps', () => { + const pageProps = { + local: 'en', + current_user: { id: 1, sound_settings: {} }, + task_tags: ['math', 'string', 'asd', 'rest'], + }; + return { + getPageProp: (key: keyof typeof pageProps, fallback?: unknown) => pageProps[key] ?? fallback, + }; +}); + +const { + elementaryTasksFromBackend, + easyTasksFromBackend, + tasksMatchingRestTags, + tasksUnsuitableForRestTags, + tasksMatchingMathTag, + tasksUnsuitableForMathTag, + tasksMatchingMathAndStringTags, + tasksUnsuitableForMathAndStringTags, + tasksFilteredByName, + tasksEliminatedByName, + tasksFilteredByNameAndTag, + tasksEliminatedByNameAndTag, +} = getTestData('testData.json'); + +const users = [ + { name: 'user1', id: -4 }, + { name: 'user2', id: -2 }, +]; +const userData = { avatarUrl: '' }; + +vi.mock('react-select', async () => await import('../__mocks__/react-select')); +vi.mock('react-select/async', async () => await import('../__mocks__/react-select/async')); +/* + AsyncSelect and Select component mock is made by means of the series of buttons. + Each button represents one option. + Clicking the buttons you simulate a choice of the options in the AsyncSelect component. + Button "filter tasks by name" simulates a user to type 'name' into the Select +*/ + +vi.mock('../widgets/middlewares/Lobby', async () => { + const originalModule = await vi.importActual('../widgets/middlewares/Lobby'); + + return { + __esModule: true, + ...originalModule, + createGame: vi.fn(), + }; +}); + +vi.mock('../widgets/middlewares/Invite', async () => { + const originalModule = await vi.importActual('../widgets/middlewares/Invite'); + + return { + __esModule: true, + ...originalModule, + createInvite: vi.fn(() => ({ type: '', payload: {} })), + }; +}); + +const reducer = combineReducers(reducers); + +const preloadedState = { + user: { + currentUserId: 1, + }, +}; + +const store = configureStore({ + reducer, + preloadedState: preloadedState as never, +}); + +const setup = (jsx: ReactElement) => ({ + user: userEvent.setup(), + ...render(jsx), +}); + +const defaultGameParams = { + level: 'elementary', + opponent_type: 'other_user', + timeout_seconds: 480, + task_id: null, + task_tags: [], +}; + +let vdom: ReactElement; + +beforeAll(() => { + globalThis.fetch = vi.fn((url: string | URL | Request) => { + if (String(url).includes('/api/v1/tasks')) { + return Promise.resolve({ + ok: true, + json: async () => ({ + tasks: [...elementaryTasksFromBackend, ...easyTasksFromBackend], + }), + }); + } + + return Promise.resolve({ + ok: true, + json: async () => ({ + users, + user: userData, + }), + }); + }) as unknown as typeof fetch; + + vdom = ( + + + + ); +}); + +describe('test create game', () => { + test('with random task with default parameters', async () => { + const { getByRole, user } = setup(vdom); + + await user.click(getByRole('button', { name: 'Create battle' })); + + expect(lobbyMiddlewares.createGame).toHaveBeenCalledWith(defaultGameParams); + }); + + test('with chosen task', async () => { + const { findByRole, getByRole, user } = setup(vdom); + const paramsWithChosenTask = { + ...defaultGameParams, + task_id: 1, + }; + + await user.click(await findByRole('button', { name: 'task1 name' })); + await user.click(getByRole('button', { name: 'Create battle' })); + + expect(lobbyMiddlewares.createGame).toHaveBeenCalledWith(paramsWithChosenTask); + }); + + test('with random task with chosen tags', async () => { + const { findByRole, getByRole, user } = setup(vdom); + const paramsWithChosenTags = { + ...defaultGameParams, + task_tags: ['math', 'string'], + }; + + await user.click(await findByRole('button', { name: 'math' })); + await user.click(getByRole('button', { name: 'string' })); + await user.click(getByRole('button', { name: 'Create battle' })); + + expect(lobbyMiddlewares.createGame).toHaveBeenCalledWith(paramsWithChosenTags); + }); + + test('with chosen task and changed level', async () => { + const { findByRole, getByRole, getByTitle, user } = setup(vdom); + const paramsWithChosenTaskAndChangedLevel = { + ...defaultGameParams, + level: 'easy', + task_id: 7, + }; + + await user.click(getByTitle('easy')); + await user.click(await findByRole('button', { name: 'task7 name' })); + await user.click(getByRole('button', { name: 'Create battle' })); + + expect(lobbyMiddlewares.createGame).toHaveBeenCalledWith(paramsWithChosenTaskAndChangedLevel); + }); + + test('with opponent and random task', async () => { + const { findByRole, getByRole, user } = setup(vdom); + const paramsWithOpponent = { + ...omit(defaultGameParams, ['opponent_type']), + recipient_id: -4, + recipient_name: 'user1', + }; + + await user.click(getByRole('button', { name: 'With a friend' })); + + const createInviteButton = getByRole('button', { name: 'Create invite' }); + + expect(createInviteButton).toBeDisabled(); + + await user.click(await findByRole('button', { name: 'user1' })); + + expect(createInviteButton).toBeEnabled(); + + await user.click(createInviteButton); + + expect(invitesMiddleware.createInvite).toHaveBeenCalledWith(paramsWithOpponent); + }); + + test('with opponent and chosen task', async () => { + const { findByRole, getByRole, user } = setup(vdom); + const paramsWithOpponentAndChosenTask = { + ...omit(defaultGameParams, ['opponent_type']), + recipient_id: -4, + recipient_name: 'user1', + task_id: 1, + }; + + await user.click(getByRole('button', { name: 'With a friend' })); + await user.click(await findByRole('button', { name: 'user1' })); + await user.click(getByRole('button', { name: 'task1 name' })); + await user.click(getByRole('button', { name: 'Create invite' })); + + expect(invitesMiddleware.createInvite).toHaveBeenCalledWith(paramsWithOpponentAndChosenTask); + }); +}); + +test('filter tasks by level', async () => { + const { findByTitle, findByRole, queryByRole, user } = setup(vdom); + + const easyLevelButton = await findByTitle('easy'); + await findByRole('button', { name: elementaryTasksFromBackend[0].name }); + + elementaryTasksFromBackend.forEach((task) => + expect(queryByRole('button', { name: task.name })).toBeInTheDocument(), + ); + easyTasksFromBackend.forEach((task) => + expect(queryByRole('button', { name: task.name })).not.toBeInTheDocument(), + ); + + await user.click(easyLevelButton); + + easyTasksFromBackend.forEach((task) => + expect(queryByRole('button', { name: task.name })).toBeInTheDocument(), + ); + elementaryTasksFromBackend.forEach((task) => + expect(queryByRole('button', { name: task.name })).not.toBeInTheDocument(), + ); +}); + +test('filter tasks by tags', async () => { + const { findByRole, getByRole, queryByRole, user } = setup(vdom); + + const mathTag = await findByRole('button', { name: 'math' }); + const stringTag = getByRole('button', { name: 'string' }); + const asdTag = getByRole('button', { name: 'asd' }); + const restTag = getByRole('button', { name: 'rest' }); + + expect(mathTag).toBeEnabled(); + expect(stringTag).toBeEnabled(); + expect(asdTag).toBeEnabled(); + expect(restTag).toBeEnabled(); + + await user.click(restTag); + await user.click(await findByRole('button', { name: 'task5 name' })); + + expect(mathTag).toBeDisabled(); + expect(stringTag).toBeDisabled(); + expect(asdTag).toBeDisabled(); + expect(restTag).toBeDisabled(); + + await user.click(await findByRole('button', { name: /random task/ })); + + await waitFor(() => { + tasksMatchingRestTags.forEach((task) => + expect(getByRole('button', { name: task.name })).toBeInTheDocument(), + ); + + tasksUnsuitableForRestTags.forEach((task) => + expect(queryByRole('button', { name: task.name })).not.toBeInTheDocument(), + ); + }); + + await user.click(restTag); + + await waitFor(() => { + elementaryTasksFromBackend.forEach((task) => + expect(getByRole('button', { name: task.name })).toBeInTheDocument(), + ); + }); + + await user.click(mathTag); + + await waitFor(() => { + tasksMatchingMathTag.forEach((task) => + expect(getByRole('button', { name: task.name })).toBeInTheDocument(), + ); + tasksUnsuitableForMathTag.forEach((task) => + expect(queryByRole('button', { name: task.name })).not.toBeInTheDocument(), + ); + }); + + await user.click(stringTag); + + await waitFor(() => { + tasksMatchingMathAndStringTags.forEach((task) => + expect(getByRole('button', { name: task.name })).toBeInTheDocument(), + ); + tasksUnsuitableForMathAndStringTags.forEach((task) => + expect(queryByRole('button', { name: task.name })).not.toBeInTheDocument(), + ); + }); + + await user.click(mathTag); + await user.click(stringTag); + + await waitFor(() => { + elementaryTasksFromBackend.forEach((task) => + expect(getByRole('button', { name: task.name })).toBeInTheDocument(), + ); + }); +}, 6000); + +test('filter tasks by name', async () => { + const { getByRole, findByRole, queryByRole, user } = setup(vdom); + + await user.click(await findByRole('button', { name: 'filter tasks by name' })); + + await waitFor(() => { + tasksFilteredByName.forEach((task) => + expect(getByRole('button', { name: task.name })).toBeInTheDocument(), + ); + tasksEliminatedByName.forEach((task) => + expect(queryByRole('button', { name: task.name })).not.toBeInTheDocument(), + ); + }); +}); + +test('filter tasks by name and tags', async () => { + const { getByRole, findByRole, queryByRole, user } = setup(vdom); + + await user.click(await findByRole('button', { name: 'filter tasks by name' })); + await user.click(getByRole('button', { name: 'math' })); + + tasksFilteredByNameAndTag.forEach((task) => + expect(queryByRole('button', { name: task.name })).toBeInTheDocument(), + ); + tasksEliminatedByNameAndTag.forEach((task) => + expect(queryByRole('button', { name: task.name })).not.toBeInTheDocument(), + ); +}); diff --git a/apps/codebattle/assets/js/__tests__/GameActionButton.test.tsx b/apps/codebattle/assets/js/__tests__/GameActionButton.test.tsx new file mode 100644 index 000000000..5f7d519ea --- /dev/null +++ b/apps/codebattle/assets/js/__tests__/GameActionButton.test.tsx @@ -0,0 +1,22 @@ +import React from 'react'; + +import { render, screen } from '@testing-library/react'; + +import GameActionButton from '../widgets/pages/lobby/GameActionButton'; + +test('uses the full-width localized continue action outside the games table', () => { + render( + , + ); + + expect(screen.getByRole('link', { name: 'Continue' })).toHaveClass('w-100'); +}); diff --git a/apps/codebattle/assets/js/__tests__/GameActionButtons.test.tsx b/apps/codebattle/assets/js/__tests__/GameActionButtons.test.tsx new file mode 100644 index 000000000..f2a6798c2 --- /dev/null +++ b/apps/codebattle/assets/js/__tests__/GameActionButtons.test.tsx @@ -0,0 +1,75 @@ +import { act, render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import React from 'react'; +import { createActor } from 'xstate'; + +import RoomContext from '../widgets/components/RoomContext'; +import GameStateCodes from '../widgets/config/gameStateCodes'; +import machines from '../widgets/machines'; +import ReplayerControlButton from '../widgets/pages/game/ReplayerControlButton'; +import SignUpButton from '../widgets/pages/game/SignUpButton'; + +const { dispatchMock } = vi.hoisted(() => ({ + dispatchMock: vi.fn((action) => { + if (typeof action === 'function') { + return action(dispatchMock); + } + + return action; + }), +})); + +vi.mock('react-redux', () => ({ + useDispatch: () => dispatchMock, +})); + +vi.mock('../widgets/middlewares/Room', () => ({ + downloadPlaybook: (service: ReturnType) => () => { + service.send({ type: 'START_LOADING_PLAYBOOK' }); + service.send({ type: 'LOAD_PLAYBOOK', payload: {} }); + }, + openPlaybook: (service: ReturnType) => () => { + service.send({ type: 'OPEN_REPLAYER' }); + }, +})); + +describe('game action buttons', () => { + beforeEach(() => { + dispatchMock.mockClear(); + }); + + test('guest sign-up links to the registration page', () => { + render(); + + expect(screen.getByRole('link', { name: 'Sign up' })).toHaveAttribute('href', '/users/new'); + }); + + test('opens and closes history with one click', async () => { + const user = userEvent.setup(); + const mainService = createActor(machines.game, { + input: { subscriptionType: 'premium' }, + }); + mainService.start(); + mainService.send({ + type: 'LOAD_GAME', + payload: { state: GameStateCodes.gameOver }, + }); + + render( + + + , + ); + + await user.click(screen.getByRole('button', { name: 'Open Record Player' })); + expect(screen.getByRole('button', { name: 'Close Record Player' })).toBeInTheDocument(); + + await user.click(screen.getByRole('button', { name: 'Close Record Player' })); + expect(screen.getByRole('button', { name: 'Open Record Player' })).toBeInTheDocument(); + + await user.click(screen.getByRole('button', { name: 'Open Record Player' })); + expect(screen.getByRole('button', { name: 'Close Record Player' })).toBeInTheDocument(); + + act(() => mainService.stop()); + }); +}); diff --git a/apps/codebattle/assets/js/__tests__/GameRecovery.test.ts b/apps/codebattle/assets/js/__tests__/GameRecovery.test.ts new file mode 100644 index 000000000..c3a5e5e2a --- /dev/null +++ b/apps/codebattle/assets/js/__tests__/GameRecovery.test.ts @@ -0,0 +1,42 @@ +import { createActor } from 'xstate'; + +import machines from '../widgets/machines'; +import { findCurrentUserPlayingGame } from '../widgets/middlewares/Lobby'; + +describe('game recovery flows', () => { + test('opens, closes, and reopens a loaded replay on the first event', () => { + // xstate v5: seed context via `input` and drive the machine through a running actor. + const actor = createActor(machines.game, { input: { subscriptionType: 'premium' } }); + actor.start(); + + actor.send({ type: 'START_LOADING_PLAYBOOK' }); + expect(actor.getSnapshot().matches({ replayer: 'loading' })).toBe(true); + + actor.send({ type: 'LOAD_PLAYBOOK', payload: {} }); + expect(actor.getSnapshot().matches({ replayer: 'on' })).toBe(true); + + actor.send({ type: 'SET_SPEED_MODE', speedMode: '2.5x' }); + expect(actor.getSnapshot().context.speedMode).toBe('2.5x'); + + actor.send({ type: 'CLOSE_REPLAYER' }); + expect(actor.getSnapshot().matches({ replayer: 'off' })).toBe(true); + + actor.send({ type: 'OPEN_REPLAYER' }); + expect(actor.getSnapshot().matches({ replayer: 'on' })).toBe(true); + + actor.send({ type: 'CLOSE_REPLAYER' }); + expect(actor.getSnapshot().matches({ replayer: 'off' })).toBe(true); + + actor.stop(); + }); + + test('recovers a playing game from a lobby channel snapshot', () => { + const games = [ + { id: 10, state: 'waiting_opponent', players: [{ id: 7 }] }, + { id: 11, state: 'playing', players: [{ id: 7 }, { id: 8 }] }, + ]; + + expect(findCurrentUserPlayingGame(games, 7)?.id).toBe(11); + expect(findCurrentUserPlayingGame(games, 9)).toBeUndefined(); + }); +}); diff --git a/apps/codebattle/assets/js/__tests__/InviteNotifications.test.ts b/apps/codebattle/assets/js/__tests__/InviteNotifications.test.ts new file mode 100644 index 000000000..99ef0f8cd --- /dev/null +++ b/apps/codebattle/assets/js/__tests__/InviteNotifications.test.ts @@ -0,0 +1,115 @@ +import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'; + +const mocks = vi.hoisted(() => ({ + listeners: new Map void>(), + play: vi.fn(), +})); + +vi.mock('../socket', () => ({ + channelMethods: { + invitesAccept: 'invites:accept', + invitesCancel: 'invites:cancel', + invitesCreate: 'invites:create', + }, + channelTopics: { + invitesAcceptedTopic: 'invites:accepted', + invitesCanceledTopic: 'invites:canceled', + invitesCreatedTopic: 'invites:created', + invitesDroppedTopic: 'invites:dropped', + invitesExpiredTopic: 'invites:expired', + invitesInitTopic: 'invites:init', + }, +})); + +vi.mock('../widgets/lib/sound', () => ({ + default: { play: mocks.play }, +})); + +vi.mock('../widgets/middlewares/Channel', () => ({ + default: class ChannelMock { + addListener(topic: string, callback: (data: any) => void) { + mocks.listeners.set(topic, callback); + return this; + } + + join() { + const push = { + receive: (status: string, callback: () => void) => { + if (status === 'ok') callback(); + return push; + }, + }; + + return push; + } + + push() { + const push = { receive: () => push }; + return push; + } + }, +})); + +import { initInvites } from '../widgets/middlewares/Invite'; + +describe('invite notification sounds', () => { + beforeEach(() => { + mocks.listeners.clear(); + mocks.play.mockClear(); + vi.useFakeTimers(); + }); + + afterEach(() => { + vi.useRealTimers(); + }); + + test('plays distinct sounds for received, accepted, and declined invites', () => { + const currentUserId = 10; + const dispatch = vi.fn(); + initInvites(currentUserId)(dispatch); + + mocks.listeners.get('invites:created')?.({ + invite: { creatorId: 20, recipientId: currentUserId, creator: { name: 'Creator' } }, + }); + expect(mocks.play).toHaveBeenLastCalledWith('round_created'); + + mocks.listeners.get('invites:accepted')?.({ + invite: { + creatorId: currentUserId, + recipientId: 20, + executorId: 20, + gameId: 123, + recipient: { name: 'Invitee' }, + }, + }); + expect(mocks.play).toHaveBeenLastCalledWith('win'); + + mocks.listeners.get('invites:canceled')?.({ + invite: { + creatorId: currentUserId, + recipientId: 20, + executorId: 20, + recipient: { name: 'Invitee' }, + }, + }); + expect(mocks.play).toHaveBeenLastCalledWith('give_up'); + expect(mocks.play).toHaveBeenCalledTimes(3); + }); + + test('does not notify the user who performed the invite action', () => { + const currentUserId = 10; + initInvites(currentUserId)(vi.fn()); + + mocks.listeners.get('invites:created')?.({ + invite: { creatorId: currentUserId, recipientId: 20 }, + }); + mocks.listeners.get('invites:accepted')?.({ + invite: { executorId: currentUserId, gameId: 123 }, + }); + mocks.listeners.get('invites:canceled')?.({ + invite: { executorId: currentUserId }, + }); + + expect(mocks.play).not.toHaveBeenCalled(); + }); +}); diff --git a/apps/codebattle/assets/js/__tests__/LanguagePickerView.test.tsx b/apps/codebattle/assets/js/__tests__/LanguagePickerView.test.tsx new file mode 100644 index 000000000..b272c1d24 --- /dev/null +++ b/apps/codebattle/assets/js/__tests__/LanguagePickerView.test.tsx @@ -0,0 +1,39 @@ +import { configureStore } from '@reduxjs/toolkit'; +import { render, screen } from '@testing-library/react'; +import React from 'react'; +import { Provider } from 'react-redux'; + +import LanguagePickerView from '../widgets/components/LanguagePickerView'; + +vi.mock('../widgets/components/LanguageIcon', () => ({ default: () => null })); + +const langs = [ + { slug: 'js', name: 'javascript', version: '22' }, + { slug: 'kotlin', name: 'kotlin', version: '2.1' }, +]; + +function renderPicker(currentLangSlug: string) { + const store = configureStore({ + reducer: () => ({ editor: { langs } }), + }); + + return render( + + + , + ); +} + +describe('LanguagePickerView', () => { + test('shows a saved language even when it is hidden from the selectable languages', () => { + renderPicker('kotlin'); + + expect(screen.getByRole('button')).toHaveTextContent('Kotlin2.1'); + }); + + test('falls back to the slug when a saved language is no longer available', () => { + renderPicker('removed-language'); + + expect(screen.getByRole('button')).toHaveTextContent('Removed-language'); + }); +}); diff --git a/apps/codebattle/assets/js/__tests__/Localization.test.ts b/apps/codebattle/assets/js/__tests__/Localization.test.ts new file mode 100644 index 000000000..d3024c830 --- /dev/null +++ b/apps/codebattle/assets/js/__tests__/Localization.test.ts @@ -0,0 +1,19 @@ +import ru from '../../../priv/gettext/ru/LC_MESSAGES/default.po'; + +test('provides Russian translations for the reported interface strings', () => { + expect(ru).toMatchObject({ + 'View Hall of Fame': 'Посмотреть зал славы', + 'My Tournaments': 'Мои турниры', + Achievements: 'Достижения', + Calendar: 'Календарь', + 'Task Packs': 'Наборы задач', + Clans: 'Кланы', + 'Game Type': 'Тип игры', + 'Time control': 'Контроль времени', + Feedback: 'Обратная связь', + 'Send feedback': 'Отправить отзыв', + 'Opponent has left': 'Соперник покинул игру', + 'Are you sure you want to give up?': 'Вы уверены, что хотите сдаться?', + Rematch: 'Реванш', + }); +}); diff --git a/apps/codebattle/assets/js/__tests__/Localization.test.tsx b/apps/codebattle/assets/js/__tests__/Localization.test.tsx new file mode 100644 index 000000000..d3c8efd62 --- /dev/null +++ b/apps/codebattle/assets/js/__tests__/Localization.test.tsx @@ -0,0 +1,110 @@ +import { configureStore } from '@reduxjs/toolkit'; +import { render, screen } from '@testing-library/react'; +import React from 'react'; +import { Provider } from 'react-redux'; + +import i18n from '../i18n'; +import dayjs from '../i18n/dayjs'; +import AchievementBadge from '../widgets/components/AchievementBadge'; +import InvitesList from '../widgets/components/InvitesList'; +import TournamentDescription from '../widgets/components/TournamentDescription'; +import TournamentPreviewPanel from '../widgets/components/TournamentPreviewPanel'; +import { localizeTournamentName } from '../widgets/utils/localizeTournamentName'; + +const translations = [ + ['Points', 'Очки'], + ['Today', 'Сегодня'], + ['Back', 'Назад'], + ['Next', 'Далее'], + ['Month', 'Месяц'], + ['Day', 'День'], + ['Agenda', 'Расписание'], + ['Season Points Distribution', 'Распределение очков сезона'], + ['Duration', 'Длительность'], + ['Winner', 'Победитель'], + ['Ranking Points', 'Рейтинговые очки'], + ['Tournament chat', 'Чат турнира'], + ['Easy', 'Лёгкий'], + ['Tournament: %{name}', 'Турнир: %{name}'], + ['Open Tournament', 'Открыть турнир'], + ['View League Ranking Points System', 'Система рейтинговых очков лиги'], + ['Replay settings', 'Настройки повтора'], + ['Tournament details', 'Подробности турнира'], + ['Function Signature', 'Сигнатура функции'], + ['Fastest Solutions', 'Самые быстрые решения'], + ['Forgot your password?', 'Забыли пароль?'], + ['Restricted Content', 'Ограниченный доступ'], + ['No completed games', 'Нет завершённых игр'], + ['Live tournaments', 'Активные турниры'], + ['Editor settings', 'Настройки редактора'], + ['Start tournament confirmation', 'Подтверждение запуска турнира'], +] as const; + +beforeAll(async () => { + await i18n.changeLanguage('ru'); + dayjs.locale('ru'); +}); + +afterAll(async () => { + await i18n.changeLanguage('en'); + dayjs.locale('en'); +}); + +test.each(translations)('translates %s into Russian', (key, translation) => { + expect(i18n.t(key)).toBe(translation); +}); + +test('localizes the best streak achievement', () => { + render(); + + expect(screen.getByText('Лучшая серия')).toBeInTheDocument(); + expect(screen.getByTitle('Лучшая серия побед')).toBeInTheDocument(); +}); + +test('localizes the empty invites state', () => { + const store = configureStore({ reducer: () => ({}) }); + + render( + + + , + ); + + expect(screen.getByText('Нет приглашений')).toBeInTheDocument(); +}); + +test('localizes tournament preview dates and point labels', () => { + render( + , + ); + + expect(screen.getByText('Дата начала: 5 августа 2026')).toBeInTheDocument(); + expect(screen.getByText('Время: 02:00 - 02:15')).toBeInTheDocument(); + expect(screen.getByText('Очки за первое место: 8')).toBeInTheDocument(); +}); + +test('localizes tournament highlights and grade names', () => { + render(); + + expect(screen.getByText('Главное о турнире:')).toBeInTheDocument(); + expect(screen.getByText('Задачи: 4 уникальных алгоритмических задач')).toBeInTheDocument(); + expect(screen.getByText('Система рейтинговых очков лиги')).toBeInTheDocument(); + expect(screen.getByText('Новичок(*)')).toBeInTheDocument(); + expect(screen.getByText('Челленджер')).toBeInTheDocument(); + expect(screen.getByText('Гранд-слэм')).toBeInTheDocument(); +}); + +test('localizes only system-generated tournament names', () => { + expect(localizeTournamentName('Challenger Tournament #12', 'challenger')).toBe( + 'Турнир «Челленджер» №12', + ); + expect(localizeTournamentName('Grand_slam Tournament #9', 'grand_slam')).toBe( + 'Турнир «Гранд-слэм» №9', + ); + expect(localizeTournamentName('Rookie', 'rookie')).toBe('Новичок'); + expect(localizeTournamentName('My custom tournament', 'rookie')).toBe('My custom tournament'); +}); diff --git a/apps/codebattle/assets/js/__tests__/Main.test.ts b/apps/codebattle/assets/js/__tests__/Main.test.ts new file mode 100644 index 000000000..5161ab561 --- /dev/null +++ b/apps/codebattle/assets/js/__tests__/Main.test.ts @@ -0,0 +1,7 @@ +import { changePresenceState } from '../widgets/middlewares/Main'; + +describe('main channel middleware', () => { + test('ignores presence changes when the main channel is not initialized', () => { + expect(() => changePresenceState('watching')()).not.toThrow(); + }); +}); diff --git a/apps/codebattle/assets/js/__tests__/MainChannelContainer.test.tsx b/apps/codebattle/assets/js/__tests__/MainChannelContainer.test.tsx new file mode 100644 index 000000000..cc83cccb9 --- /dev/null +++ b/apps/codebattle/assets/js/__tests__/MainChannelContainer.test.tsx @@ -0,0 +1,35 @@ +import { render } from '@testing-library/react'; +import React from 'react'; + +const { channelLeave, dispatch, initPresence } = vi.hoisted(() => ({ + channelLeave: vi.fn(), + dispatch: vi.fn(), + initPresence: vi.fn(), +})); + +vi.mock('react-redux', () => ({ + useDispatch: () => dispatch, + useSelector: (selector: (state: { gameUI: { followId: number } }) => unknown) => + selector({ gameUI: { followId: 42 } }), +})); + +vi.mock('../widgets/middlewares/Main', () => ({ + default: initPresence, +})); + +import MainChannelContainer from '../widgets/components/MainChannelContainer'; + +describe('MainChannelContainer', () => { + test('keeps the browser-session presence channel alive when the page unmounts', () => { + initPresence.mockReturnValue(() => ({ leave: channelLeave })); + + const { unmount } = render(); + + expect(initPresence).toHaveBeenCalledWith(42); + expect(initPresence).toHaveBeenCalledTimes(1); + + unmount(); + + expect(channelLeave).not.toHaveBeenCalled(); + }); +}); diff --git a/apps/codebattle/assets/js/__tests__/PictureInPicture.test.tsx b/apps/codebattle/assets/js/__tests__/PictureInPicture.test.tsx new file mode 100644 index 000000000..3cdb44102 --- /dev/null +++ b/apps/codebattle/assets/js/__tests__/PictureInPicture.test.tsx @@ -0,0 +1,123 @@ +import { render, waitFor } from '@testing-library/react'; +import '@testing-library/jest-dom'; +import React from 'react'; +import PictureInPicture, { copyStyles } from '../widgets/components/PictureInPicture'; + +describe('PictureInPicture component', () => { + // Document Picture-in-Picture is not part of TypeScript's DOM library yet. + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let mockPipWindow: any; + let requestWindow: ReturnType; + + beforeEach(() => { + mockPipWindow = { + document: { + body: { + appendChild: vi.fn(), + style: {}, + }, + createElement: vi.fn().mockImplementation((tag: string) => { + return document.createElement(tag); + }), + }, + addEventListener: vi.fn(), + close: vi.fn(), + }; + + requestWindow = vi.fn().mockResolvedValue(mockPipWindow); + Object.assign(window, { documentPictureInPicture: { requestWindow } }); + }); + + afterEach(() => { + Reflect.deleteProperty(window, 'documentPictureInPicture'); + }); + + test('does not render when isActive is false', () => { + const { container } = render( + +
Timer Content
+
, + ); + + expect(container).toBeEmptyDOMElement(); + expect(requestWindow).not.toHaveBeenCalled(); + }); + + test('opens pip window and renders children via portal when isActive is true', async () => { + const onCloseMock = vi.fn(); + + render( + +
Timer Content
+
, + ); + + await waitFor(() => { + expect(requestWindow).toHaveBeenCalled(); + }); + + expect(mockPipWindow.document.body.appendChild).toHaveBeenCalled(); + }); + + test('closes pip window on unmount', async () => { + const { unmount } = render( + +
Timer Content
+
, + ); + + await waitFor(() => { + expect(requestWindow).toHaveBeenCalled(); + }); + + unmount(); + expect(mockPipWindow.close).toHaveBeenCalled(); + }); + + test('calls onClose when requestWindow fails', async () => { + requestWindow.mockRejectedValue(new Error('Permission denied')); + const onCloseMock = vi.fn(); + + render( + +
Timer Content
+
, + ); + + await waitFor(() => { + expect(onCloseMock).toHaveBeenCalled(); + }); + }); + + test('copyStyles copies styleSheets correctly', () => { + const sourceDoc = { + styleSheets: [ + { + cssRules: [{ cssText: '.test-rule { color: red; }' }], + }, + { + href: 'http://example.com/styles.css', + }, + ], + }; + + const targetDoc = { + createElement: vi.fn().mockImplementation((_tag: string) => { + return { + appendChild: vi.fn(), + appendChildNode: vi.fn(), + }; + }), + createTextNode: vi.fn().mockImplementation((text: string) => text), + head: { + appendChild: vi.fn(), + }, + }; + + copyStyles(sourceDoc as unknown as Document, targetDoc as unknown as Document); + + expect(targetDoc.createElement).toHaveBeenCalledWith('style'); + expect(targetDoc.createElement).toHaveBeenCalledWith('link'); + expect(targetDoc.head.appendChild).toHaveBeenCalled(); + }); +}); diff --git a/apps/codebattle/assets/js/__tests__/PopoverStickOnHover.test.tsx b/apps/codebattle/assets/js/__tests__/PopoverStickOnHover.test.tsx new file mode 100644 index 000000000..918c9635c --- /dev/null +++ b/apps/codebattle/assets/js/__tests__/PopoverStickOnHover.test.tsx @@ -0,0 +1,37 @@ +import React from 'react'; + +import { act, fireEvent, render, screen } from '@testing-library/react'; +import '@testing-library/jest-dom'; + +import PopoverStickOnHover from '../widgets/components/PopoverStickOnHover'; + +describe('PopoverStickOnHover', () => { + afterEach(() => { + vi.useRealTimers(); + }); + + test('keeps the delayed hover timer across parent rerenders', () => { + vi.useFakeTimers(); + + const component = user details; + const view = render( + + + , + ); + + fireEvent.mouseEnter(screen.getByRole('button', { name: 'Ada' })); + + view.rerender( + + + , + ); + + act(() => vi.advanceTimersByTime(399)); + expect(screen.queryByText('user details')).not.toBeInTheDocument(); + + act(() => vi.advanceTimersByTime(1)); + expect(screen.getByText('user details')).toBeInTheDocument(); + }); +}); diff --git a/apps/codebattle/assets/js/__tests__/PresentationalComponents.test.tsx b/apps/codebattle/assets/js/__tests__/PresentationalComponents.test.tsx new file mode 100644 index 000000000..49d272aa1 --- /dev/null +++ b/apps/codebattle/assets/js/__tests__/PresentationalComponents.test.tsx @@ -0,0 +1,107 @@ +import React from 'react'; + +import { render, screen } from '@testing-library/react'; + +import Card from '../widgets/components/Card'; +import EditorLoading from '../widgets/components/EditorLoading'; +import GameLevelBadge from '../widgets/components/GameLevelBadge'; +import InfoMessage from '../widgets/components/InfoMessage'; +import Loading from '../widgets/components/Loading'; +import LobbyLoading from '../widgets/pages/lobby/LobbyLoading'; +import MessageTimestamp from '../widgets/components/MessageTimestamp'; +import Messages from '../widgets/components/Messages'; +import PlayerLoading from '../widgets/components/PlayerLoading'; +import SystemMessage from '../widgets/components/SystemMessage'; +import Timer from '../widgets/components/Timer'; + +vi.mock('../widgets/utils/useTimer', () => ({ + default: () => ['01:02:03', 3723], +})); + +vi.mock('../widgets/utils/useStayScrolled', () => ({ + default: () => ({ stayScrolled: vi.fn(), scrollBottom: vi.fn() }), +})); + +describe('presentational components', () => { + test('renders a game level badge', () => { + render(); + + expect(screen.getByRole('img', { name: 'easy' })).toHaveAttribute( + 'src', + '/assets/images/levels/easy.svg', + ); + }); + + test('renders an informational message', () => { + render(); + + expect(screen.getByText('The tournament has started')).toBeInTheDocument(); + }); + + test('renders the requested loading size', () => { + render(); + + expect(screen.getByRole('status')).toHaveStyle({ width: '30px', height: '30px' }); + }); + + test('renders the lobby loading shell', () => { + const { container } = render(); + + expect(screen.getByRole('status')).toHaveTextContent('Loading...'); + expect(screen.getByText('Preparing your arena')).toBeInTheDocument(); + expect(container.querySelectorAll('.cb-text-skeleton')).toHaveLength(18); + }); + + test('renders the timer duration', () => { + render(); + + expect(screen.getByText('01:02:03')).toBeInTheDocument(); + }); + + test('shows the editor loading overlay when requested', () => { + const { container } = render(); + + expect(container.firstElementChild).toHaveClass('d-flex', 'cb-loading-background'); + expect(container.firstElementChild).not.toHaveClass('d-none'); + }); + + test('renders a small player loading indicator', () => { + render(); + + expect(screen.getByRole('status')).toHaveStyle({ width: '30px', height: '30px' }); + expect(screen.getByRole('status')).not.toHaveClass('invisible'); + }); + + test('renders a local message timestamp', () => { + render(); + + expect(screen.getByText(/\d{2}:\d{2} [AP]M/)).toHaveClass('text-muted'); + }); + + test('renders chat messages as semantic list items', () => { + render(); + + const list = screen.getByRole('list'); + + expect(list).toHaveClass('list-unstyled'); + expect(list.children).toHaveLength(1); + expect(list.firstElementChild).toHaveRole('listitem'); + }); + + test('renders system message status styling', () => { + render(); + + expect(screen.getByText('Unable to join the game')).toHaveClass('text-danger'); + }); + + test('renders card content with its title', () => { + render( + +

Win as many games as possible.

+
, + ); + + expect(screen.getByRole('heading', { name: 'Tournament rules' })).toBeInTheDocument(); + expect(screen.getByText('Win as many games as possible.')).toBeInTheDocument(); + }); +}); diff --git a/apps/codebattle/assets/js/__tests__/Registration.test.tsx b/apps/codebattle/assets/js/__tests__/Registration.test.tsx new file mode 100644 index 000000000..6def56f1b --- /dev/null +++ b/apps/codebattle/assets/js/__tests__/Registration.test.tsx @@ -0,0 +1,141 @@ +import { render, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import '@testing-library/jest-dom'; +import React, { type ReactElement } from 'react'; + +import Registration from '../widgets/pages/registration'; + +import { getTestData } from './helpers'; + +// jsdom URL the registration page reads (was @jest-environment-options). +window.history.pushState({}, '', '/users/new'); + +const { invalidData: fixtureInvalidData, validData } = getTestData('signUpData.json'); +const invalidData = fixtureInvalidData as Array<[string, string, string, string]>; +const { data, route, headers } = validData; + +vi.mock('@/inertia/pageProps', () => { + const pageProps = { local: 'en', current_user: { sound_settings: {} } }; + return { + getPageProp: (key: keyof typeof pageProps, fallback?: unknown) => pageProps[key] ?? fallback, + }; +}); + +describe('sign up', () => { + let fetchMock = vi.fn(); + + function setup(jsx: ReactElement) { + return { + user: userEvent.setup(), + ...render(jsx), + }; + } + + beforeAll(() => { + document.head.innerHTML = ''; + }); + + beforeEach(() => { + window.history.pushState({}, '', '/users/new'); + fetchMock = vi.fn(); + globalThis.fetch = fetchMock as unknown as typeof fetch; + }); + + test('render', () => { + const { getByText } = setup(); + + expect(getByText(/Sign Up/)).toBeInTheDocument(); + }); + + test('reveals and hides passwords without removing the controls', async () => { + const { getByLabelText, getByRole, user } = setup(); + const password = getByLabelText('password'); + const confirmation = getByLabelText('passwordConfirmation'); + + expect(password).toHaveAttribute('type', 'password'); + expect(confirmation).toHaveAttribute('type', 'password'); + + await user.click(getByRole('button', { name: 'Show password' })); + await user.click(getByRole('button', { name: 'Show password confirmation' })); + + expect(password).toHaveAttribute('type', 'text'); + expect(confirmation).toHaveAttribute('type', 'text'); + expect(getByRole('button', { name: 'Hide password' })).toBeInTheDocument(); + expect(getByRole('button', { name: 'Hide password confirmation' })).toBeInTheDocument(); + + await user.click(getByRole('button', { name: 'Hide password' })); + + expect(password).toHaveAttribute('type', 'password'); + expect(getByRole('button', { name: 'Show password' })).toBeInTheDocument(); + }); + + test('reveals the password on the sign-in page', async () => { + window.history.pushState({}, '', '/session/new'); + const { getByLabelText, getByRole, user } = setup(); + const password = getByLabelText('password'); + + await user.click(getByRole('button', { name: 'Show password' })); + + expect(password).toHaveAttribute('type', 'text'); + expect(getByRole('button', { name: 'Hide password' })).toBeInTheDocument(); + }); + + test.each(invalidData)('%s', async (testName, value, validationMessage, inputName) => { + const { getByLabelText, findByText, user } = setup(); + + const nameInput = getByLabelText(inputName); + if (value) { + await userEvent.type(nameInput, value); + } + + const submitButton = getByLabelText('Submit form'); + await user.click(submitButton); + + expect(await findByText(validationMessage)).toBeInTheDocument(); + }); + + test('successful sign up', async () => { + const { getByLabelText, user } = setup(); + + const signUpSpy = vi.fn().mockResolvedValueOnce({ + ok: true, + json: async () => ({}), + }); + fetchMock.mockImplementation(signUpSpy); + + await userEvent.type(getByLabelText('name'), data.name); + await userEvent.type(getByLabelText('email'), data.email); + await userEvent.type(getByLabelText('password'), data.password); + await userEvent.type(getByLabelText('passwordConfirmation'), data.passwordConfirmation); + + const submitButton = getByLabelText('Submit form'); + await user.click(submitButton); + + await waitFor(() => { + expect(signUpSpy).toHaveBeenCalledWith(route, { + method: 'POST', + headers: headers.headers, + body: JSON.stringify(data), + }); + }); + }); + + test('shows a readable password recovery confirmation', async () => { + window.history.pushState({}, '', '/remind_password'); + fetchMock.mockResolvedValueOnce({ + ok: true, + json: async () => ({}), + }); + + const { getByLabelText, findByText, user } = setup(); + + await user.type(getByLabelText('email'), 'user@example.com'); + await user.click(getByLabelText('Submit form')); + + const confirmation = await findByText( + 'We have sent you an email with instructions on how to reset your password', + ); + + expect(confirmation).toHaveClass('text-white'); + }); +}); diff --git a/apps/codebattle/assets/js/__tests__/ReplayControlPanel.test.tsx b/apps/codebattle/assets/js/__tests__/ReplayControlPanel.test.tsx new file mode 100644 index 000000000..9e434f873 --- /dev/null +++ b/apps/codebattle/assets/js/__tests__/ReplayControlPanel.test.tsx @@ -0,0 +1,93 @@ +import { configureStore } from '@reduxjs/toolkit'; +import { fireEvent, render, screen, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import React from 'react'; +import { Provider } from 'react-redux'; + +import playbackModes from '../widgets/config/playbackModes'; +import ControlPanel from '../widgets/pages/game/ControlPanel'; + +const { copyMock } = vi.hoisted(() => ({ + copyMock: vi.fn().mockResolvedValue(true), +})); + +vi.mock('copy-to-clipboard', () => ({ + default: copyMock, +})); + +const store = configureStore({ + reducer: (state = {}) => state, +}); + +const makeRoomState = (replayerState = 'on.paused', speedMode = '1x') => ({ + context: { speedMode }, + matches: ({ replayer }: { replayer: string }) => replayer === replayerState, +}); + +describe('replay control panel', () => { + beforeEach(() => { + copyMock.mockClear(); + }); + + test('keeps clear playback controls visible while changing their values', async () => { + const user = userEvent.setup(); + const onChangeSpeed = vi.fn(); + const onChangePlaybackMode = vi.fn(); + + render( + + +
+ + , + ); + + expect(screen.getByRole('button', { name: 'Play replay' })).toBeInTheDocument(); + expect(screen.getByTestId('timeline')).toBeInTheDocument(); + expect(screen.getByLabelText('Playback time')).toHaveTextContent('00:02 / 00:10'); + expect(screen.queryByRole('slider', { name: 'Playback speed' })).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: 'Uniform' })).not.toBeInTheDocument(); + + await user.click(screen.getByRole('button', { name: 'Replay settings' })); + expect(screen.getByRole('dialog', { name: 'Replay settings' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: /Playback speed/ })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: 'Uniform' })).toBeInTheDocument(); + + await user.click(screen.getByRole('button', { name: /Playback speed/ })); + expect(screen.getByRole('button', { name: 'Back to replay settings' })).toBeInTheDocument(); + const speedSlider = screen.getByRole('slider', { name: 'Playback speed' }); + expect(speedSlider).toHaveAttribute('min', '0.5'); + expect(speedSlider).toHaveAttribute('max', '4'); + expect(speedSlider).toHaveAttribute('step', '0.5'); + + fireEvent.change(speedSlider, { target: { value: '2.5' } }); + expect(onChangeSpeed).toHaveBeenCalledWith('2.5x'); + + await user.click(screen.getByRole('button', { name: 'Set playback speed to 3×' })); + expect(onChangeSpeed).toHaveBeenCalledWith('3x'); + + await user.click(screen.getByRole('button', { name: 'Increase playback speed' })); + expect(onChangeSpeed).toHaveBeenCalledWith('1.5x'); + + await user.click(screen.getByRole('button', { name: 'Back to replay settings' })); + await user.click(screen.getByRole('button', { name: 'Uniform' })); + expect(onChangePlaybackMode).toHaveBeenCalledWith(playbackModes.standard); + + await user.click(screen.getByRole('button', { name: 'Copy replay link at current position' })); + await waitFor(() => expect(copyMock).toHaveBeenCalledWith('http://localhost/?t=12')); + expect(screen.getByText('Link copied')).toBeInTheDocument(); + + await user.click(screen.getByRole('button', { name: 'Replay settings' })); + expect(screen.queryByRole('dialog', { name: 'Replay settings' })).not.toBeInTheDocument(); + }); +}); diff --git a/apps/codebattle/assets/js/__tests__/RootContainer.test.tsx b/apps/codebattle/assets/js/__tests__/RootContainer.test.tsx new file mode 100644 index 000000000..237d72213 --- /dev/null +++ b/apps/codebattle/assets/js/__tests__/RootContainer.test.tsx @@ -0,0 +1,282 @@ +import NiceModal from '@ebay/nice-modal-react'; +import { configureStore, combineReducers } from '@reduxjs/toolkit'; +import { render } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import '@testing-library/jest-dom'; +import React, { type ReactElement } from 'react'; +import { Provider } from 'react-redux'; +import { createMachine } from 'xstate'; + +import GameRoomModes from '../widgets/config/gameModes'; +import GameStateCodes from '../widgets/config/gameStateCodes'; +import userTypes from '../widgets/config/userTypes'; +import editor, { config as editorConfig } from '../widgets/machines/editor'; +import game, { config as gameConfig } from '../widgets/machines/game'; +import task, { config as taskConfig } from '../widgets/machines/task'; +import RootContainer from '../widgets/pages/RoomWidget'; +import reducers from '../widgets/slices'; + +vi.mock('pixelmatch', () => ({ default: () => {} })); + +vi.mock('monaco-editor', () => ({ + editor: { + defineTheme: () => {}, + create: () => ({ + dispose: () => {}, + onDidChangeModelContent: () => {}, + setValue: () => {}, + getValue: () => {}, + getModel: () => {}, + focus: () => {}, + }), + }, +})); + +vi.mock('monaco-vim', () => ({ + VimMode: class { + constructor() { + return { + dispose: () => {}, + }; + } + }, +})); + +vi.mock('../widgets/initEditor', () => ({ default: () => {} })); + +vi.mock('../widgets/pages/game/TaskDescriptionMarkdown', () => ({ + default: function () { + return <>Examples: ; + }, +})); + +vi.mock('@fortawesome/react-fontawesome', () => ({ + FontAwesomeIcon: 'img', +})); + +const createPlayer = (params: Record) => ({ + isAdmin: false, + id: 0, + name: '', + githubId: 0, + rating: 0, + ratingDiff: 0, + lang: 'js', + ...params, +}); + +vi.mock('@/inertia/pageProps', () => { + const pageProps = { + local: 'en', + current_user: { id: 1, sound_settings: {} }, + game_id: 10, + players: [ + { + isAdmin: false, + id: 0, + name: 'Tim Urban', + githubId: 0, + rating: 0, + ratingDiff: 0, + lang: 'js', + }, + { + isAdmin: false, + id: 0, + name: 'John Kramer', + githubId: 0, + rating: 0, + ratingDiff: 0, + lang: 'js', + }, + ], + game: { + state: '', + players: [], + langs: [], + }, + }; + + return { + getPageProp: (key: keyof typeof pageProps, fallback?: unknown) => pageProps[key] ?? fallback, + }; +}); + +vi.mock('../widgets/pages/game/EditorContainer', () => ({ + default: function EditorContainer() { + return <>; + }, +})); + +vi.mock('../widgets/components/FeedbackWidget', () => ({ + default: function FeedbackWidget() { + return <>; + }, +})); + +vi.mock('../widgets/utils/useStayScrolled', () => ({ + default: () => ({ stayScrolled: () => {} }), +})); + +beforeAll(() => { + globalThis.fetch = vi.fn().mockResolvedValue({ + ok: true, + json: async () => ({}), + }) as unknown as typeof fetch; +}); + +vi.mock('phoenix', async () => { + const originalModule = await vi.importActual('phoenix'); + + return { + __esModule: true, + ...originalModule, + Socket: vi.fn().mockImplementation(function () { + return { + channel: vi.fn(() => { + const channel = { + join: vi.fn(() => channel), + leave: vi.fn(() => channel), + receive: vi.fn(() => channel), + on: vi.fn(), + off: vi.fn(), + push: vi.fn(), + onError: vi.fn(), + }; + + return channel; + }), + connect: vi.fn(() => {}), + }; + }), + }; +}); + +const reducer = combineReducers(reducers); + +const players = { + 1: createPlayer({ + name: 'John Kramer', + type: userTypes.firstPlayer, + id: 1, + }), + 2: createPlayer({ + name: 'Tim Urban', + type: userTypes.secondPlayer, + id: -1, + isBot: true, + }), +}; + +const preloadedState = { + user: { + currentUserId: 1, + users: players, + settings: { mute: null }, + }, + game: { + gameStatus: { + state: GameStateCodes.playing, + mode: GameRoomModes.standard, + checking: {}, + startsAt: '0', + }, + task: { + id: 0, + name: '', + description: '', + examples: '', + level: 'medium', + }, + players, + useChat: true, + }, + editor: { + meta: { + 1: { userId: 1, currentLangSlug: 'js' }, + 2: { userId: 2, currentLangSlug: 'js' }, + }, + text: { + '1:js': '', + '2:js': '', + }, + }, + usersInfo: { + 1: {}, + 2: {}, + }, + chat: { + users: Object.values(players), + messages: [ + { + id: 1, + name: 'Tim Urban', + text: 'bot message', + type: 'text', + time: 1679056894, + userId: -1, + }, + ], + channel: { online: true }, + activeRoom: { name: 'General', targetUserId: null }, + rooms: [{ name: 'General', targetUserId: null }], + history: { + messages: [], + }, + }, +}; + +game.states.room.initial = 'active'; +editor.initial = 'idle'; + +const setup = (jsx: ReactElement) => ({ + user: userEvent.setup(), + ...render(jsx), +}); + +test('rendering preview game component', async () => { + const store = configureStore({ + reducer, + preloadedState: preloadedState as never, + }); + + const { findByText } = setup( + + + + + , + ); + + expect(await findByText(/Examples:/)).toBeInTheDocument(); +}); + +test('a bot invite button', async () => { + const store = configureStore({ + reducer, + preloadedState: preloadedState as never, + }); + + const { findByLabelText, findByTitle, user } = setup( + + + + + , + ); + + const target = await findByTitle('Message (Tim Urban)'); + await user.pointer({ keys: '[MouseLeft]', target }); + + expect(await findByLabelText('Send an invite')).toHaveAttribute('aria-disabled', 'true'); +}); diff --git a/apps/codebattle/assets/js/__tests__/SeasonProfilePanel.test.tsx b/apps/codebattle/assets/js/__tests__/SeasonProfilePanel.test.tsx new file mode 100644 index 000000000..70c9798c6 --- /dev/null +++ b/apps/codebattle/assets/js/__tests__/SeasonProfilePanel.test.tsx @@ -0,0 +1,29 @@ +import { render } from '@testing-library/react'; +import React from 'react'; + +const { dispatch, loadNearbyUsers } = vi.hoisted(() => ({ + dispatch: vi.fn(), + loadNearbyUsers: vi.fn(), +})); + +vi.mock('react-redux', () => ({ + useDispatch: () => dispatch, + useSelector: () => undefined, +})); + +vi.mock('../widgets/middlewares/Users', () => ({ + loadNearbyUsers, +})); + +import { SeasonNearbyUsers } from '../widgets/pages/lobby/SeasonProfilePanel'; + +describe('SeasonNearbyUsers', () => { + test('aborts the pending request with its AbortController when unmounted', () => { + const { unmount } = render(); + const controller = loadNearbyUsers.mock.calls[0][0] as AbortController; + + expect(controller.signal.aborted).toBe(false); + expect(() => unmount()).not.toThrow(); + expect(controller.signal.aborted).toBe(true); + }); +}); diff --git a/apps/codebattle/assets/js/__tests__/Sound.test.ts b/apps/codebattle/assets/js/__tests__/Sound.test.ts new file mode 100644 index 000000000..9735c6d9f --- /dev/null +++ b/apps/codebattle/assets/js/__tests__/Sound.test.ts @@ -0,0 +1,84 @@ +import sound, { configureSound, createPlayer } from '../widgets/lib/sound'; + +const howlerMocks = vi.hoisted(() => ({ + howl: vi.fn(), + play: vi.fn(), + stop: vi.fn(), + volume: vi.fn(), +})); + +vi.mock('howler', () => ({ + Howl: function Howl(options: unknown) { + howlerMocks.howl(options); + + return { + play: howlerMocks.play, + volume: howlerMocks.volume, + }; + }, + Howler: { + stop: howlerMocks.stop, + volume: howlerMocks.volume, + }, +})); + +vi.mock('@/inertia/pageProps', () => ({ + getPageProp: () => ({ + sound_settings: { + type: 'standard', + level: 5, + }, + }), +})); + +describe('game sound settings', () => { + beforeEach(() => { + localStorage.clear(); + howlerMocks.howl.mockClear(); + howlerMocks.play.mockClear(); + howlerMocks.volume.mockClear(); + }); + + test('uses newly saved sound settings without a page reload', () => { + configureSound({ type: 'cs', level: 7, tournamentLevel: 3 }); + + sound.play('win'); + + const options = howlerMocks.howl.mock.calls[0][0] as { + src: string; + volume: number; + }; + + expect(options.src).toBe('/assets/audio/audioSprites/csSpritesAudio.wav'); + expect(options.volume).toBeCloseTo(0.7); + expect(howlerMocks.play).toHaveBeenCalledWith('win'); + }); + + test('does not create a player for silent mode', () => { + configureSound({ type: 'silent', level: 5 }); + + sound.play('win'); + + expect(howlerMocks.howl).not.toHaveBeenCalled(); + expect(howlerMocks.play).not.toHaveBeenCalled(); + }); + + test('does not play while quick mute is enabled', () => { + configureSound({ type: 'standard', level: 5 }); + localStorage.setItem('ui_mute_sound', 'true'); + + sound.play('round_created'); + + expect(howlerMocks.howl).not.toHaveBeenCalled(); + expect(howlerMocks.play).not.toHaveBeenCalled(); + }); + + test('does not play settings previews while quick mute is enabled', () => { + localStorage.setItem('ui_mute_sound', 'true'); + + createPlayer().standard.play('win', 0.5); + + expect(howlerMocks.howl).not.toHaveBeenCalled(); + expect(howlerMocks.play).not.toHaveBeenCalled(); + }); +}); diff --git a/apps/codebattle/assets/js/__tests__/SoundToggle.test.tsx b/apps/codebattle/assets/js/__tests__/SoundToggle.test.tsx new file mode 100644 index 000000000..f18e19b85 --- /dev/null +++ b/apps/codebattle/assets/js/__tests__/SoundToggle.test.tsx @@ -0,0 +1,83 @@ +import { configureStore } from '@reduxjs/toolkit'; +import { render, screen, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import React from 'react'; +import { Provider } from 'react-redux'; + +import SoundToggle from '../widgets/components/SoundToggle'; +import sound from '../widgets/lib/sound'; + +vi.mock('../widgets/lib/sound', () => ({ + default: { toggle: vi.fn() }, +})); + +const reducer = ( + state = { user: { settings: { mute: false } } }, + action: { type: string; payload?: boolean }, +) => + action.type === 'user/setMuteSound' + ? { user: { settings: { mute: Boolean(action.payload) } } } + : state; + +afterEach(() => { + vi.clearAllMocks(); + vi.unstubAllGlobals(); +}); + +test('toggles sound from the profile menu', async () => { + const fetchMock = vi.fn().mockResolvedValue({ ok: true }); + vi.stubGlobal('fetch', fetchMock); + const store = configureStore({ reducer }); + const user = userEvent.setup(); + + render( + + + , + ); + + const toggle = screen.getByRole('button', { name: 'Mute sound' }); + expect(toggle).toHaveAttribute('aria-pressed', 'false'); + expect(screen.getByText('On')).toBeInTheDocument(); + + await user.click(toggle); + + expect(sound.toggle).toHaveBeenCalledWith(0); + expect(screen.getByRole('button', { name: 'Turn sound on' })).toHaveAttribute( + 'aria-pressed', + 'true', + ); + expect(screen.getByText('Off')).toBeInTheDocument(); + + await waitFor(() => expect(fetchMock).toHaveBeenCalledOnce()); + expect(fetchMock).toHaveBeenCalledWith( + '/api/v1/settings', + expect.objectContaining({ + method: 'PATCH', + body: JSON.stringify({ sound_settings: { muted: true } }), + }), + ); +}); + +test('restores the previous state when the preference cannot be saved', async () => { + vi.stubGlobal('fetch', vi.fn().mockResolvedValue({ ok: false, status: 500 })); + const store = configureStore({ reducer }); + const user = userEvent.setup(); + + render( + + + , + ); + + await user.click(screen.getByRole('button', { name: 'Mute sound' })); + + await waitFor(() => + expect(screen.getByRole('button', { name: 'Mute sound' })).toHaveAttribute( + 'aria-pressed', + 'false', + ), + ); + expect(sound.toggle).toHaveBeenNthCalledWith(1, 0); + expect(sound.toggle).toHaveBeenNthCalledWith(2, undefined); +}); diff --git a/apps/codebattle/assets/js/__tests__/TaskPreviewWidget.test.tsx b/apps/codebattle/assets/js/__tests__/TaskPreviewWidget.test.tsx new file mode 100644 index 000000000..886143f19 --- /dev/null +++ b/apps/codebattle/assets/js/__tests__/TaskPreviewWidget.test.tsx @@ -0,0 +1,27 @@ +import { render, screen } from '@testing-library/react'; +import '@testing-library/jest-dom'; +import React from 'react'; + +import TaskPreviewWidget from '../widgets/pages/taskPreview/TaskPreviewWidget'; + +test('shows the task solve time and base static score', () => { + render( + , + ); + + expect(screen.getByText('Time to solve')).toBeInTheDocument(); + expect(screen.getByText('2m 5s')).toBeInTheDocument(); + expect(screen.getByText('Base static score')).toBeInTheDocument(); + expect(screen.getByText('275')).toBeInTheDocument(); +}); diff --git a/apps/codebattle/assets/js/__tests__/TournamentChatInput.test.tsx b/apps/codebattle/assets/js/__tests__/TournamentChatInput.test.tsx new file mode 100644 index 000000000..378bececa --- /dev/null +++ b/apps/codebattle/assets/js/__tests__/TournamentChatInput.test.tsx @@ -0,0 +1,48 @@ +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import '@testing-library/jest-dom'; +import React from 'react'; + +import TournamentChatInput from '../widgets/pages/tournament/TournamentChatInput'; +import { addMessage } from '../widgets/middlewares/Chat'; + +vi.mock('i18next', () => ({ + default: { init: vi.fn(), t: (key: string) => key }, +})); +vi.mock('../widgets/middlewares/Chat', () => ({ addMessage: vi.fn() })); +vi.mock('react-redux', () => ({ useSelector: () => ({ name: 'General' }) })); +vi.mock('bad-words-next', () => ({ + default: class BadWordsNextMock { + add() {} + + filter(value: string) { + return value; + } + }, +})); + +test('TournamentChatInput keeps Send disabled for an empty message', async () => { + const user = userEvent.setup(); + render(); + + const input = screen.getByRole('textbox', { name: 'Chat message' }); + const sendButton = screen.getByRole('button', { name: 'Send' }); + + expect(sendButton).toBeDisabled(); + await user.type(input, ' '); + expect(sendButton).toBeDisabled(); + expect(addMessage).not.toHaveBeenCalled(); +}); + +test('TournamentChatInput sends a general tournament chat message', async () => { + const user = userEvent.setup(); + render(); + + await user.type(screen.getByRole('textbox', { name: 'Chat message' }), 'Good luck!'); + await user.click(screen.getByRole('button', { name: 'Send' })); + + expect(addMessage).toHaveBeenCalledWith({ + text: 'Good luck!', + meta: { type: 'general' }, + }); +}); diff --git a/apps/codebattle/assets/js/__tests__/TournamentChatMessage.test.tsx b/apps/codebattle/assets/js/__tests__/TournamentChatMessage.test.tsx new file mode 100644 index 000000000..3c126bd7d --- /dev/null +++ b/apps/codebattle/assets/js/__tests__/TournamentChatMessage.test.tsx @@ -0,0 +1,29 @@ +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import '@testing-library/jest-dom'; +import React from 'react'; + +import Message from '../widgets/components/Message'; + +vi.mock('react-redux', () => ({ useSelector: () => ({ name: 'General' }) })); + +test('tournament chat renders a plain player name with an explicit admin ban action', async () => { + const user = userEvent.setup(); + const handleBanUser = vi.fn(); + + render( + , + ); + + expect(screen.getByText('TournamentPlayer').closest('[role="button"]')).toBeNull(); + expect(screen.queryByTitle('Message (TournamentPlayer)')).not.toBeInTheDocument(); + + await user.click(screen.getByRole('button', { name: 'Ban TournamentPlayer' })); + expect(handleBanUser).toHaveBeenCalledWith({ userId: 42, name: 'TournamentPlayer' }); +}); diff --git a/apps/codebattle/assets/js/__tests__/TournamentHeader.test.tsx b/apps/codebattle/assets/js/__tests__/TournamentHeader.test.tsx new file mode 100644 index 000000000..3696a2da8 --- /dev/null +++ b/apps/codebattle/assets/js/__tests__/TournamentHeader.test.tsx @@ -0,0 +1,103 @@ +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import '@testing-library/jest-dom'; +import copy from 'copy-to-clipboard'; +import React from 'react'; + +import TournamentHeader from '../widgets/pages/tournament/TournamentHeader'; + +vi.mock('copy-to-clipboard', () => ({ default: vi.fn() })); +vi.mock('../widgets/pages/tournament/TournamentMainControlButtons', () => ({ + default: () => null, +})); +vi.mock('../widgets/pages/tournament/JoinButton', () => ({ default: () => null })); + +test('TournamentHeader copies full private tournament url', async () => { + const user = userEvent.setup(); + + render( + , + ); + + const copyButton = screen.getByTestId('copy-button'); + await user.click(copyButton); + + expect(copy).toHaveBeenCalledWith('http://localhost/tournaments/42?access_token=secret-token'); +}); + +test('TournamentHeader shows the grade icon and first-place ranking points', () => { + const { container } = render( + , + ); + + expect(screen.getByLabelText('masters grade')).toContainElement(container.querySelector('svg')); + expect(screen.getByText('1024')).toHaveClass('cb-tournament-points-value'); + expect(screen.getByText('Ranking Points')).toBeInTheDocument(); +}); + +test('TournamentHeader omits grade details for open tournaments', () => { + render( + , + ); + + expect(screen.queryByText('Ranking Points')).not.toBeInTheDocument(); + expect(screen.queryByLabelText('open grade')).not.toBeInTheDocument(); +}); diff --git a/apps/codebattle/assets/js/__tests__/TournamentListItem.test.tsx b/apps/codebattle/assets/js/__tests__/TournamentListItem.test.tsx new file mode 100644 index 000000000..94672d819 --- /dev/null +++ b/apps/codebattle/assets/js/__tests__/TournamentListItem.test.tsx @@ -0,0 +1,63 @@ +import { render, screen } from '@testing-library/react'; +import '@testing-library/jest-dom'; +import React from 'react'; + +import i18n from '../i18n'; +import dayjs from '../i18n/dayjs'; +import TournamentListItem from '../widgets/pages/lobby/TournamentListItem'; + +vi.mock('@/inertia/pageProps', () => ({ + getPageProp: (key: string, fallback?: unknown) => (key === 'locale' ? 'en' : fallback), +})); + +vi.mock('@fortawesome/react-fontawesome', () => ({ + FontAwesomeIcon: 'img', +})); + +afterEach(async () => { + await i18n.changeLanguage('en'); + dayjs.locale('en'); + vi.useRealTimers(); +}); + +const baseTournament = { + id: 1, + name: 'Rookie', + grade: 'rookie', + state: 'finished', + startsAt: '2026-07-09T00:00:00Z', + playersCount: 3, +}; + +test('does not render invalid date for finished tournament without last round end date', () => { + render(); + + expect(screen.queryByText('Invalid Date')).not.toBeInTheDocument(); + expect(screen.getByText('Rookie')).toBeInTheDocument(); + expect(screen.getAllByText(/at /).length).toBeGreaterThan(0); +}); + +test('localizes the tournament date, action, and countdown label', async () => { + vi.useFakeTimers(); + vi.setSystemTime(new Date('2026-08-01T00:00:00Z')); + await i18n.changeLanguage('ru'); + dayjs.locale('ru'); + + const { rerender } = render(); + + expect(screen.getByRole('link', { name: 'Открыть' })).toBeInTheDocument(); + expect(screen.getAllByText(/июл/).length).toBeGreaterThan(0); + + rerender( + , + ); + + expect(screen.getByText(/начнётся через/)).toBeInTheDocument(); + expect(screen.getAllByText(/авг/).length).toBeGreaterThan(0); +}); diff --git a/apps/codebattle/assets/js/__tests__/TournamentMainControlButtons.test.tsx b/apps/codebattle/assets/js/__tests__/TournamentMainControlButtons.test.tsx new file mode 100644 index 000000000..f7c903af6 --- /dev/null +++ b/apps/codebattle/assets/js/__tests__/TournamentMainControlButtons.test.tsx @@ -0,0 +1,71 @@ +import '@testing-library/jest-dom'; +import { configureStore } from '@reduxjs/toolkit'; +import { render, screen } from '@testing-library/react'; +import React from 'react'; +import { Provider } from 'react-redux'; + +import TournamentMainControlButtons from '../widgets/pages/tournament/TournamentMainControlButtons'; + +vi.mock('@fortawesome/react-fontawesome', () => ({ + FontAwesomeIcon: 'img', +})); + +vi.mock('../widgets/middlewares/TournamentAdmin', () => ({ + cancelTournament: vi.fn(), + finishTournament: vi.fn(), + restartTournament: vi.fn(), + retryTournament: vi.fn(), + finishRoundTournament: vi.fn(), + openUpTournament: vi.fn(), + showTournamentResults: vi.fn(), +})); + +function renderComponent(props = {}) { + const store = configureStore({ + reducer: () => ({}), + }); + + const defaultProps = { + accessType: 'public', + streamMode: false, + tournamentId: 42, + canStart: false, + canStartRound: false, + canFinishRound: true, + canFinishTournament: true, + canToggleShowBots: false, + canRestart: false, + showBots: true, + hideResults: true, + disabled: false, + toggleShowBots: vi.fn(), + handleStartRound: vi.fn(), + handleOpenDetails: vi.fn(), + toggleStreamMode: vi.fn(), + }; + + return render( + + + , + ); +} + +test('shows Finish button for an active tournament even when restart is unavailable', () => { + renderComponent(); + + expect(screen.getByRole('button', { name: /Finish Tournament/ })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: /Finish Round/ })).toBeInTheDocument(); + expect(screen.queryByRole('button', { name: /Restart/ })).not.toBeInTheDocument(); +}); + +test('does not show Finish button for a finished tournament', () => { + renderComponent({ + canFinishRound: false, + canFinishTournament: false, + canRestart: true, + }); + + expect(screen.queryByRole('button', { name: 'Finish' })).not.toBeInTheDocument(); + expect(screen.getByRole('button', { name: 'Restart' })).toBeInTheDocument(); +}); diff --git a/apps/codebattle/assets/js/__tests__/UserInfo.test.tsx b/apps/codebattle/assets/js/__tests__/UserInfo.test.tsx new file mode 100644 index 000000000..407e198c7 --- /dev/null +++ b/apps/codebattle/assets/js/__tests__/UserInfo.test.tsx @@ -0,0 +1,94 @@ +import React, { type ReactNode } from 'react'; + +import { render, screen, waitFor } from '@testing-library/react'; +import '@testing-library/jest-dom'; + +import UserInfo from '../widgets/components/UserInfo'; + +const dispatch = vi.fn(); + +vi.mock('react-redux', () => ({ + useDispatch: () => dispatch, + useSelector: () => ({ presenceList: [] }), +})); + +vi.mock('../widgets/selectors', () => ({ + lobbyDataSelector: vi.fn(), +})); + +vi.mock('../widgets/slices', () => ({ + actions: { setError: vi.fn() }, +})); + +vi.mock('../widgets/components/PopoverStickOnHover', () => ({ + default: ({ + children, + component, + delay, + }: { + children: ReactNode; + component: ReactNode; + delay?: number; + }) => ( + <> + {children} +
+ {component} +
+ + ), +})); + +vi.mock('../widgets/components/UserName', () => ({ + default: ({ user }: { user: { name: string } }) => {user.name}, +})); + +vi.mock('../widgets/components/UserStats', () => ({ + default: ({ data }: { data?: unknown }) => ( +
{data ? 'loaded user details' : 'loading user details'}
+ ), +})); + +describe('UserInfo', () => { + beforeEach(() => { + dispatch.mockClear(); + }); + + test('renders only bot text in the tooltip without preloading user details', () => { + const fetchMock = vi.fn(); + globalThis.fetch = fetchMock; + + render(); + + expect(screen.getByTestId('popover-content')).toHaveTextContent(/^bot$/); + expect(fetchMock).not.toHaveBeenCalled(); + }); + + test('delays user popovers and shares cached requests for the same user', async () => { + const fetchMock = vi.fn().mockResolvedValue({ + ok: true, + json: vi.fn().mockResolvedValue({ achievements: [], metrics: {} }), + }); + globalThis.fetch = fetchMock; + + const view = render( + <> + + + , + ); + + expect(screen.getAllByTestId('popover-content')[0]).toHaveAttribute('data-delay', '150'); + expect(fetchMock).toHaveBeenCalledTimes(1); + + await waitFor(() => { + expect(screen.getAllByText('loaded user details')).toHaveLength(2); + }); + + view.unmount(); + render(); + + expect(fetchMock).toHaveBeenCalledTimes(1); + expect(screen.getByText('loaded user details')).toBeInTheDocument(); + }); +}); diff --git a/apps/codebattle/assets/js/__tests__/UserName.test.tsx b/apps/codebattle/assets/js/__tests__/UserName.test.tsx new file mode 100644 index 000000000..2cab5fe98 --- /dev/null +++ b/apps/codebattle/assets/js/__tests__/UserName.test.tsx @@ -0,0 +1,56 @@ +import React from 'react'; + +import { render, screen } from '@testing-library/react'; +import '@testing-library/jest-dom'; + +import UserName from '../widgets/components/UserName'; + +vi.mock('@fortawesome/react-fontawesome', () => ({ + FontAwesomeIcon: 'span', +})); + +vi.mock('../widgets/components/LanguageIcon', () => ({ + default: () => , +})); + +describe('UserName', () => { + test('renders the user name as-is', () => { + render( + , + ); + + expect(screen.getByText('A-211250(2011)')).toBeInTheDocument(); + }); + + test('does not append rank to the rendered user name', () => { + const { container } = render( + , + ); + + expect(screen.getByText('A-211250')).toBeInTheDocument(); + expect(container).toHaveTextContent('A-211250'); + expect(container).not.toHaveTextContent('A-211250(2011)'); + }); + + test('renders bot icon without language icon for bots', () => { + const { container } = render( + , + ); + + expect(screen.getByText('CasperDesigner')).toBeInTheDocument(); + expect(screen.queryByTestId('language-icon')).not.toBeInTheDocument(); + expect(container.querySelectorAll('span').length).toBeGreaterThan(0); + }); +}); diff --git a/apps/codebattle/assets/js/__tests__/UserProfile.test.tsx b/apps/codebattle/assets/js/__tests__/UserProfile.test.tsx new file mode 100644 index 000000000..910fe85fb --- /dev/null +++ b/apps/codebattle/assets/js/__tests__/UserProfile.test.tsx @@ -0,0 +1,119 @@ +import '@testing-library/jest-dom'; +import { configureStore, combineReducers } from '@reduxjs/toolkit'; +import { render, waitFor } from '@testing-library/react'; +import React, { type ReactNode } from 'react'; +import { Provider } from 'react-redux'; + +import UserProfile from '../widgets/pages/profile'; +import reducers from '../widgets/slices'; + +// jsdom URL the profile page reads the user id from (was @jest-environment-options). +window.history.pushState({}, '', '/users/42'); + +vi.mock('@/inertia/pageProps', () => { + const pageProps = { local: 'en', current_user: { sound_settings: {} } }; + return { + getPageProp: (key: keyof typeof pageProps, fallback?: unknown) => pageProps[key] ?? fallback, + }; +}); + +vi.mock('../i18n', () => ({ + __esModule: true, + getLocale: vi.fn(() => 'en'), + getSupportedLocale: vi.fn((locale: string | undefined) => locale || 'en'), + default: { + language: 'en', + t: vi.fn((key: string, params: Record = {}) => + key.replace(/%\{(\w+)\}/g, (_match: string, name: string) => + String(params[name] ?? `%{${name}}`), + ), + ), + }, +})); + +vi.mock('../widgets/components/LanguageIcon', () => ({ default: () => lang-icon })); +vi.mock('../widgets/components/Loading', () => ({ + default: ({ small }: { small?: boolean; children?: ReactNode }) => ( +
{small ? 'loading-small' : 'loading'}
+ ), +})); +vi.mock('../widgets/pages/profile/Heatmap', () => ({ default: () =>
heatmap
})); +vi.mock('../widgets/pages/profile/UserStatCharts', () => ({ default: () =>
charts
})); +vi.mock('../widgets/pages/profile/UserTournaments', () => ({ + default: () =>
tournaments
, +})); +vi.mock('../widgets/pages/lobby/CompletedGames', () => ({ + default: () =>
completed-games
, +})); + +const reducer = combineReducers(reducers); + +describe('UserProfile', () => { + let fetchMock = vi.fn(); + + beforeEach(() => { + fetchMock = vi + .fn() + .mockResolvedValueOnce({ + ok: true, + json: async () => ({ + active_game_id: null, + achievements: [], + metrics: { + game_stats: { won: 3, lost: 1, gave_up: 0 }, + language_stats: { js: 2, ts: 2 }, + tournaments_stats: { + rookie_wins: 0, + challenger_wins: 0, + pro_wins: 0, + elite_wins: 0, + masters_wins: 0, + grand_slam_wins: 0, + }, + }, + season_results: [], + stats: { games: { won: 3, lost: 1, gave_up: 0 }, all: [] }, + user: { + id: 42, + name: 'Kleria', + avatar_url: '/assets/images/logo.svg', + lang: 'js', + clan: '', + clan_id: null, + github_name: 'Kleria', + inserted_at: '2026-01-01T12:00:00Z', + rating: 1500, + rank: 10, + points: 100, + is_bot: false, + }, + }), + }) + .mockResolvedValueOnce({ + ok: true, + json: async () => ({ + top_rivals: [], + }), + }); + globalThis.fetch = fetchMock as unknown as typeof fetch; + }); + + test('does not render or request holopin resources on the profile page', async () => { + const store = configureStore({ reducer }); + const { container, getByLabelText, queryByText } = render( + + + , + ); + + await waitFor(() => { + expect(getByLabelText('Github account')).toHaveAttribute('href', 'https://github.com/Kleria'); + }); + + expect(fetchMock).toHaveBeenNthCalledWith(1, '/api/v1/user/42/stats'); + expect(fetchMock).toHaveBeenNthCalledWith(2, '/api/v1/user/42/rivals'); + expect(queryByText('Holopins')).not.toBeInTheDocument(); + expect(container.querySelector('a[href^="https://holopin.io/@"]')).not.toBeInTheDocument(); + expect(container.querySelector('img[src^="https://holopin.me/@"]')).not.toBeInTheDocument(); + }); +}); diff --git a/apps/codebattle/assets/js/__tests__/UserSettings.test.tsx b/apps/codebattle/assets/js/__tests__/UserSettings.test.tsx new file mode 100644 index 000000000..763d88a7f --- /dev/null +++ b/apps/codebattle/assets/js/__tests__/UserSettings.test.tsx @@ -0,0 +1,525 @@ +import '@testing-library/jest-dom'; +import { configureStore, combineReducers } from '@reduxjs/toolkit'; +import { fireEvent, render, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import React, { type ReactElement, type ReactNode } from 'react'; +import { Provider } from 'react-redux'; + +import UserSettings from '../widgets/pages/settings'; +import reducers from '../widgets/slices'; + +vi.mock('@fortawesome/react-fontawesome', () => ({ + FontAwesomeIcon: () =>
diff --git a/apps/codebattle/lib/codebattle_web/templates/layout/empty.html.heex b/apps/codebattle/lib/codebattle_web/templates/layout/empty.html.heex new file mode 100644 index 000000000..8a41ae964 --- /dev/null +++ b/apps/codebattle/lib/codebattle_web/templates/layout/empty.html.heex @@ -0,0 +1,68 @@ + + + + + + + {google_fonts_head()} + + + + + + + + + + + + + {render_tags_all(assigns[:meta_tags] || %{})} + + {Application.get_env(:codebattle, :app_title)} + + + <%= if CodebattleWeb.Vite.dev?() do %> + + + + + <% else %> + + <%= for href <- CodebattleWeb.Vite.css_paths("app.js") do %> + + <% end %> + + <% end %> + + + {@inner_content} + + diff --git a/apps/codebattle/lib/codebattle_web/templates/layout/external.html.heex b/apps/codebattle/lib/codebattle_web/templates/layout/external.html.heex new file mode 100644 index 000000000..93e403bbe --- /dev/null +++ b/apps/codebattle/lib/codebattle_web/templates/layout/external.html.heex @@ -0,0 +1,206 @@ + + + + + + + {google_fonts_head()} + + + + + + + + + + + + + {render_tags_all(assigns[:meta_tags] || %{})} + + {Application.get_env(:codebattle, :app_title)} + + + + <%= if CodebattleWeb.Vite.dev?() do %> + + + + + <% else %> + + <%= for href <- CodebattleWeb.Vite.css_paths("external.js") do %> + + <% end %> + + <% end %> + + +
+ <%= if assigns[:show_header] do %> +
+ +
+ <% end %> + <%= if @ticker_text do %> +
+
+ <%= for _ <- 1..20 do %> + {@ticker_text} + <% end %> +
+
+ <% end %> + + {@inner_content} +
+ + diff --git a/apps/codebattle/lib/codebattle_web/templates/layout/landing.html.heex b/apps/codebattle/lib/codebattle_web/templates/layout/landing.html.heex new file mode 100644 index 000000000..c2ef703ba --- /dev/null +++ b/apps/codebattle/lib/codebattle_web/templates/layout/landing.html.heex @@ -0,0 +1,86 @@ + + + + + + + {google_fonts_head()} + + + + + + + + + + + + + {render_tags_all(assigns[:meta_tags] || %{})} + + + <%= if CodebattleWeb.Vite.dev?() do %> + + + + + <% else %> + + <%= for href <- CodebattleWeb.Vite.css_paths("landing.js") do %> + + <% end %> + + <% end %> + + {Application.get_env(:codebattle, :app_title)} + + + <%= if FunWithFlags.enabled?(:use_external_js) do %> + + <% end %> + + + + <%= if FunWithFlags.enabled?(:use_external_js) do %> + + <% end %> + {@inner_content} + + diff --git a/apps/codebattle/lib/codebattle_web/templates/public_event/show.html.heex b/apps/codebattle/lib/codebattle_web/templates/public_event/show.html.heex new file mode 100644 index 000000000..0fe2d20a6 --- /dev/null +++ b/apps/codebattle/lib/codebattle_web/templates/public_event/show.html.heex @@ -0,0 +1,9 @@ +
+ <%= unless @current_user.is_guest do %> +
+ <% end %> +
+
+ diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/root/_contributors_asserts.html.heex b/apps/codebattle/lib/codebattle_web/templates/root/_contributors_asserts.html.heex similarity index 100% rename from services/app/apps/codebattle/lib/codebattle_web/templates/root/_contributors_asserts.html.heex rename to apps/codebattle/lib/codebattle_web/templates/root/_contributors_asserts.html.heex diff --git a/apps/codebattle/lib/codebattle_web/templates/root/_contributors_codebattle.html.heex b/apps/codebattle/lib/codebattle_web/templates/root/_contributors_codebattle.html.heex new file mode 100644 index 000000000..993f4ae03 --- /dev/null +++ b/apps/codebattle/lib/codebattle_web/templates/root/_contributors_codebattle.html.heex @@ -0,0 +1,1287 @@ + +
+ ReDBrother +
+
+ +
+ vtm9 +
+
+ +
+ imamatory +
+
+ +
+ solar05 +
+
+ +
+ lazycoder9 +
+
+ +
+ PeresvetS +
+
+ +
+ Guryanov-Maksim +
+
+ +
+ krivtsov +
+
+ +
+ kjubybot +
+
+ +
+ VladimirAfanasievFS +
+
+ +
+ mimikria96 +
+
+ +
+ igor-i +
+
+ +
+ Abbath +
+
+ +
+ ushachev +
+
+ +
+ possesion +
+
+ +
+ v1valasvegan +
+
+ +
+ nunsez +
+
+ +
+ thepry +
+
+ +
+ skhrv +
+
+ +
+ PlugIN73 +
+
+ +
+ voitd +
+
+ +
+ zipofar +
+
+ +
+ MityaDementiy +
+
+ +
+ jougene +
+
+ +
+ disheg +
+
+ +
+ rexemtoxa +
+
+ +
+ amshkv +
+
+ +
+ valerr +
+
+ +
+ greybutton +
+
+ +
+ vicimpa +
+
+ +
+ Yoffic +
+
+ +
+ ayshvab +
+
+ +
+ enmalafeev +
+
+ +
+ Galbator1x +
+
+ +
+ x0xl0ma +
+
+ +
+ aenglisc +
+
+ +
+ Hubble999 +
+
+ +
+ 21aLeX +
+
+ +
+ RomaSub +
+
+ +
+ emp7yhead +
+
+ +
+ fey +
+
+ +
+ CryFromTheHeart +
+
+ +
+ AlinLob +
+
+ +
+ grozwalker +
+
+ +
+ ilyar +
+
+ +
+ seth2810 +
+
+ +
+ jurassic-period +
+
+ +
+ IoannP +
+
+ +
+ deadit +
+
+ +
+ glebmanov +
+
+ +
+ eldarik +
+
+ +
+ romanoffivan +
+
+ +
+ mettled +
+
+ +
+ denikeev +
+
+ +
+ yanushok +
+
+ +
+ malikin +
+
+ +
+ CalledByThe4ire +
+
+ +
+ Surtt +
+
+ +
+ aarefiev +
+
+ +
+ glagius +
+
+ +
+ Titonatos +
+
+ +
+ twogog +
+
+ +
+ YuriySho +
+
+ +
+ morphizm +
+
+ +
+ mmolostvova +
+
+ +
+ dekimiq +
+
+ +
+ mjh-sakh +
+
+ +
+ driveGosling +
+
+ +
+ kaldown +
+
+ +
+ philatm +
+
+ +
+ egorsmth +
+
+ +
+ MaratSalakh +
+
+ +
+ MONDAYMIND +
+
+ +
+ natalialukashova +
+
+ +
+ valera-seregin +
+
+ +
+ Aallyycoop +
+
+ +
+ AnastasiaKv +
+
+ +
+ letzabelin +
+
+ +
+ rizhik356 +
+
+ +
+ GordienkoEvgeny +
+
+ +
+ ivanlemeshev +
+
+ +
+ mokevnin +
+
+ +
+ patapiks +
+
+ +
+ viktorkasap +
+
+ +
+ Rafail6666 +
+
+ +
+ irkinwork +
+
+ +
+ avshukan +
+
+ +
+ tysky +
+
+ +
+ po1inakoroleva +
+
+ +
+ richpeach-bot +
+
+ +
+ SpaYkeR696 +
+
+ +
+ SmartRW +
+
+ +
+ devality +
+
+ +
+ akivonen +
+
+ +
+ GPopov9 +
+
+ +
+ imleykin +
+
+ +
+ aelaau +
+
+ +
+ puku +
+
+ +
+ LoseGameng +
+
diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/root/_contributors_extension.html.heex b/apps/codebattle/lib/codebattle_web/templates/root/_contributors_extension.html.heex similarity index 100% rename from services/app/apps/codebattle/lib/codebattle_web/templates/root/_contributors_extension.html.heex rename to apps/codebattle/lib/codebattle_web/templates/root/_contributors_extension.html.heex diff --git a/apps/codebattle/lib/codebattle_web/templates/root/_contributors_tasks.html.heex b/apps/codebattle/lib/codebattle_web/templates/root/_contributors_tasks.html.heex new file mode 100644 index 000000000..903c76332 --- /dev/null +++ b/apps/codebattle/lib/codebattle_web/templates/root/_contributors_tasks.html.heex @@ -0,0 +1,18 @@ + +
+ vtm9 +
+
+ +
+ actions-user +
+
diff --git a/apps/codebattle/lib/codebattle_web/templates/root/authorized.html.heex b/apps/codebattle/lib/codebattle_web/templates/root/authorized.html.heex new file mode 100644 index 000000000..be4253c85 --- /dev/null +++ b/apps/codebattle/lib/codebattle_web/templates/root/authorized.html.heex @@ -0,0 +1,8 @@ +
+
+

{gettext("Welcome")}

+

+ {gettext("You successfully authorized to the platform. Open your tournament link to start.")} +

+
+
diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/root/feedback.xml.eex b/apps/codebattle/lib/codebattle_web/templates/root/feedback.xml.eex similarity index 100% rename from services/app/apps/codebattle/lib/codebattle_web/templates/root/feedback.xml.eex rename to apps/codebattle/lib/codebattle_web/templates/root/feedback.xml.eex diff --git a/apps/codebattle/lib/codebattle_web/templates/root/index.html.heex b/apps/codebattle/lib/codebattle_web/templates/root/index.html.heex new file mode 100644 index 000000000..0b0c25cfb --- /dev/null +++ b/apps/codebattle/lib/codebattle_web/templates/root/index.html.heex @@ -0,0 +1,4 @@ +
+ diff --git a/apps/codebattle/lib/codebattle_web/templates/root/landing.html.heex b/apps/codebattle/lib/codebattle_web/templates/root/landing.html.heex new file mode 100644 index 000000000..a98d60e9f --- /dev/null +++ b/apps/codebattle/lib/codebattle_web/templates/root/landing.html.heex @@ -0,0 +1,531 @@ +

Codebattle

+
+
+
+
+ +
+ +
+ +
+
+
+
+ Tournaments. Seasons. Code-first competition. +

Play in the best coding arena

+

+ Codebattle powers head-to-head battles, team brackets, and seasonal leaderboards. + Set formats, invite players, and watch the rankings move in real time. +

+
+ + No registration required +
+
+ Live ladders + Team seasons + Bots + training +
+
+
+
+
+ Current Season Leaderboard + + <%= if @current_season do %> + {@current_season.name} {@current_season.year} + <% else %> + Upcoming + <% end %> + +
+
+
+ <%= if Enum.empty?(@current_season_leaderboard) do %> +

Season standings will appear here soon.

+ <% else %> + <%= for result <- @current_season_leaderboard do %> +
+
{result.place}
+
+ <%= if result.avatar_url do %> + {result.user_name} + <% else %> +
+ <% end %> +
+

{result.user_name}

+ + {result.user_lang || "Any"} + +
+
+
{result.total_points} pts
+
+ <% end %> + <% end %> +
+
+
+
Top 5 players • current season
+
+
+
+
+ +
+
+
+

Seasons and formats

+

Four seasons a year. One Grand Slam to crown the best.

+

+ Join a competitive ladder that resets each season so every coder gets a fresh climb. + Swiss rounds keep every match fair, while lifetime Elo tracks your true skill across seasons. + Top finishers earn prizes and exclusive merch. +

+
+
+
+

Season ladder

+

+ Earn season points, climb the live leaderboard, and lock your place in the finale. +

+
+ Season points + Finals on 21st + Hall of Fame +
+
+
+

Swiss tournaments

+

+ Face opponents with similar scores, solve the same task, and rise with every win. +

+
+ Swiss pairing + Live standings + No repeat pairs +
+
+
+

Grades & schedule

+

Start at rookie, fight up the grades, and aim for the Grand Slam spotlight.

+
+ Rookie → Grand Slam + Grand Slam finale + Points by place +
+
+
+
+
+ +
+
+
+

How it works

+

Join, battle, climb, repeat

+

+ A clear loop that keeps the competition fair and the season exciting. +

+
+
+
+
01
+
+

Join a season

+

Seasons reset points so everyone gets a fresh shot at the top.

+
+
+
+
02
+
+

Battle in Swiss rounds

+

Face opponents with similar scores on the same task each round.

+
+
+
+
03
+
+

Earn season points

+

Climb the live leaderboard and secure your place in the finale.

+
+
+
+
04
+
+

Win the Grand Slam

+

Champions take the spotlight, prizes, and exclusive merch.

+
+
+
+
+
+ +
+
+
+

Private tournaments

+

Build your own tournaments for friends or teams

+

+ Host custom events for meetups, work team‑building, or just fun sessions. + We’ve run tournaments for 1,000+ players. +

+
+
+
+

Friends & communities

+

Create private rooms, invite friends, and enjoy real‑time battles together.

+
+ Invite links + Live standings + Instant rematch +
+
+
+

Team‑building

+

Run company tournaments and energize your team with friendly competition.

+
+ Team brackets + Flexible schedule + Highlights +
+
+
+

Large‑scale events

+

Trusted for tournaments at scale with thousands of players.

+
+ 1,000+ players + Stable rounds + Fast judge +
+
+
+
+
+ +
+
+
+

Languages

+

Battle in your language

+

Pick your stack and jump into any tournament format.

+
+
+ + clojure + + + cpp + + + csharp + + + dart + + + elixir + + + go + + + java + + + javascript + + + kotlin + + + php + + + python + + + ruby + + + rust + + + swift + + + typescript + + + zig + +
+
+
+ +
+
+
+

Community

+

Built by competitive coders

+

+ Codebattle is open and community-driven. Join contributors and help shape upcoming seasons. +

+
+
+ +
+ {render("_contributors_codebattle.html")} +
+
+ #elixir + #phoenix + #live_view + #es6 + #react + #redux + #postgres + #k8s + #podman +
+
+
+
+ +
+
+
+
+

Ready to enter the arena?

+

Spin up a quick match or start planning your next season.

+
+ +
+
+
+
+
+ + diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/root/maintenance.html.heex b/apps/codebattle/lib/codebattle_web/templates/root/maintenance.html.heex similarity index 91% rename from services/app/apps/codebattle/lib/codebattle_web/templates/root/maintenance.html.heex rename to apps/codebattle/lib/codebattle_web/templates/root/maintenance.html.heex index b91002a90..b7fb77edc 100644 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/root/maintenance.html.heex +++ b/apps/codebattle/lib/codebattle_web/templates/root/maintenance.html.heex @@ -4,14 +4,14 @@ Codebattle.Customization.get("maintenance_header") || "

Maintenance

" %>
- <%= raw(header) %> + {raw(header)}
<% body = Codebattle.Customization.get("maintenance_body") || "We are currently performing maintenance on the site. Please come back later." %>
- <%= raw(body) %> + {raw(body)}
diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/root/robots.txt.eex b/apps/codebattle/lib/codebattle_web/templates/root/robots.txt.eex similarity index 100% rename from services/app/apps/codebattle/lib/codebattle_web/templates/root/robots.txt.eex rename to apps/codebattle/lib/codebattle_web/templates/root/robots.txt.eex diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/root/sitemap.xml.eex b/apps/codebattle/lib/codebattle_web/templates/root/sitemap.xml.eex similarity index 75% rename from services/app/apps/codebattle/lib/codebattle_web/templates/root/sitemap.xml.eex rename to apps/codebattle/lib/codebattle_web/templates/root/sitemap.xml.eex index b18f1435f..12297b045 100644 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/root/sitemap.xml.eex +++ b/apps/codebattle/lib/codebattle_web/templates/root/sitemap.xml.eex @@ -9,15 +9,8 @@ - https://codebattle.hexlet.io/users - 2020-05-02T13:13:56+00:00 - daily - 0.5 - - - - https://codebattle.hexlet.io/tournaments - 2020-05-02T13:13:56+00:00 + https://codebattle.hexlet.io/schedule + 2025-05-02T13:13:56+00:00 daily 0.5 diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/root/waiting.html.heex b/apps/codebattle/lib/codebattle_web/templates/root/waiting.html.heex similarity index 87% rename from services/app/apps/codebattle/lib/codebattle_web/templates/root/waiting.html.heex rename to apps/codebattle/lib/codebattle_web/templates/root/waiting.html.heex index 97323979c..54eaa51e3 100644 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/root/waiting.html.heex +++ b/apps/codebattle/lib/codebattle_web/templates/root/waiting.html.heex @@ -4,14 +4,14 @@ Codebattle.Customization.get("waiting_header") || "

Waiting

" %>
- <%= raw(header) %> + {raw(header)}
<% body = Codebattle.Customization.get("waiting_body") || "Please wait for the next tournament to start." %>
- <%= raw(body) %> + {raw(body)}
diff --git a/apps/codebattle/lib/codebattle_web/templates/session/external_oauth.html.heex b/apps/codebattle/lib/codebattle_web/templates/session/external_oauth.html.heex new file mode 100644 index 000000000..cac5b7572 --- /dev/null +++ b/apps/codebattle/lib/codebattle_web/templates/session/external_oauth.html.heex @@ -0,0 +1,27 @@ +
+
+
+
+
+ {Application.get_env(:codebattle, :external)[:app_name]} +
+ +

+ {raw(Application.get_env(:codebattle, :external)[:app_slogan])} +

+ + + + +
+
+ +<%= if body = Codebattle.Customization.get("external_oauth_body") do %> +
+ {raw(body)} +
+<% end %> diff --git a/apps/codebattle/lib/codebattle_web/templates/session/external_signup.html.heex b/apps/codebattle/lib/codebattle_web/templates/session/external_signup.html.heex new file mode 100644 index 000000000..819bd1a52 --- /dev/null +++ b/apps/codebattle/lib/codebattle_web/templates/session/external_signup.html.heex @@ -0,0 +1,27 @@ +
+
+
+
+
+ {Application.get_env(:codebattle, :external)[:app_name]} +
+ +

+ {raw(Application.get_env(:codebattle, :external)[:app_slogan])} +

+ + + + <%= link to: Application.get_env(:codebattle, :free_users_redirect_url), class: "btn btn-yellow mb-4" do %> + {Application.get_env(:codebattle, :external)[:app_signup_button]} + <% end %> + + <%= form_for @conn, Routes.session_path(@conn, :delete), [as: :session, method: :delete], fn _f -> %> + + <% end %> +
+
diff --git a/apps/codebattle/lib/codebattle_web/templates/session/index.html.heex b/apps/codebattle/lib/codebattle_web/templates/session/index.html.heex new file mode 100644 index 000000000..05732e82a --- /dev/null +++ b/apps/codebattle/lib/codebattle_web/templates/session/index.html.heex @@ -0,0 +1,4 @@ +
+ diff --git a/apps/codebattle/lib/codebattle_web/templates/session/local_password.html.heex b/apps/codebattle/lib/codebattle_web/templates/session/local_password.html.heex new file mode 100644 index 000000000..1edb2966c --- /dev/null +++ b/apps/codebattle/lib/codebattle_web/templates/session/local_password.html.heex @@ -0,0 +1,44 @@ +
+
+ <%= if header = Codebattle.Customization.get("login_header") do %> +
+ {raw(header)} +
+ <% end %> + + <%= if body = Codebattle.Customization.get("login_body") do %> +
+ {raw(body)} +
+ <% end %> +
+
+ +
+ +
+ <%= form_for @conn, Routes.session_path(@conn, :create), [as: :session], fn f -> %> +
+ {label(f, :name, gettext("Name"), class: "form-label")} + {text_input(f, :name, class: "form-control", placeholder: gettext("Enter your name"))} +
+
+ {label(f, :password, gettext("Password"), class: "form-label")} + {password_input(f, :password, + class: "form-control", + placeholder: gettext("Enter your password") + )} +
+
+ {submit(gettext("Log in"), class: "btn btn-primary w-100")} +
+ <% end %> +
+
diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/session/token_only.html.heex b/apps/codebattle/lib/codebattle_web/templates/session/token_only.html.heex similarity index 100% rename from services/app/apps/codebattle/lib/codebattle_web/templates/session/token_only.html.heex rename to apps/codebattle/lib/codebattle_web/templates/session/token_only.html.heex diff --git a/apps/codebattle/lib/codebattle_web/templates/task/index.html.heex b/apps/codebattle/lib/codebattle_web/templates/task/index.html.heex new file mode 100644 index 000000000..50c26cf1e --- /dev/null +++ b/apps/codebattle/lib/codebattle_web/templates/task/index.html.heex @@ -0,0 +1,86 @@ +
+

{gettext("Tasks")}

+ {link(gettext("Task packs"), + to: CodebattleWeb.Router.Helpers.task_pack_path(@conn, :index), + class: "btn btn-secondary cb-btn-secondary mt-2 ml-2 cb-rounded" + )} +
+ + + + + + + + + + + + + + + + + + <%= for task <- @tasks do %> + + + + + + + + + + + + + + <% end %> + +
idnameleveltime_to_solvebase_static_scoretagsoriginstatevisibilityupdated_atactions
{task.id}{task.name} +
+
+ {task.level} +
+
+
+ {task.time_to_solve_sec} + {task.base_score} + {Enum.join(task.tags, ", ")} + {task.origin}{task.state}{task.visibility} + {format_datetime(task.updated_at)} + +
+ <%= if !Codebattle.User.admin?(@current_user) do %> + {link(gettext("Show"), + to: CodebattleWeb.Router.Helpers.task_path(@conn, :show, task.id), + class: "btn btn-sm btn-secondary cb-btn-secondary cb-rounded" + )} + <% end %> + <%= if Codebattle.User.admin?(@current_user) do %> + {link(gettext("Show"), + to: CodebattleWeb.Router.Helpers.task_path(@conn, :show, task.id), + class: "btn btn-sm btn-secondary cb-btn-secondary cb-rounded" + )} + {button("Activate", + to: + CodebattleWeb.Router.Helpers.task_activate_path(@conn, :activate, task.id), + method: "patch", + class: "btn btn-sm btn-success cb-btn-success cb-rounded" + )} + {button("Disable", + to: CodebattleWeb.Router.Helpers.task_disable_path(@conn, :disable, task.id), + method: "patch", + class: "btn btn-sm btn-danger cb-rounded" + )} + {button("Delete", + to: CodebattleWeb.Router.Helpers.task_path(@conn, :delete, task.id), + method: "delete", + class: "btn btn-sm btn-danger cb-rounded" + )} + <% end %> +
+
+
+
diff --git a/apps/codebattle/lib/codebattle_web/templates/task_pack/_form.html.heex b/apps/codebattle/lib/codebattle_web/templates/task_pack/_form.html.heex new file mode 100644 index 000000000..6bd690ad8 --- /dev/null +++ b/apps/codebattle/lib/codebattle_web/templates/task_pack/_form.html.heex @@ -0,0 +1,49 @@ +<%= form_for(@changeset, @action, [class: "col-8 offset-2"], fn f -> %> +
+ {render_base_errors(@changeset.errors[:base])} +
+
+
+ Name + Name for task pack, should be unique +
+ {text_input(f, :name, + class: "form-control form-control-lg custom-control cb-bg-panel cb-border-color text-white", + maxlength: "37", + required: false + )} + {error_tag(f, :name)} +
+
+ {label(f, :visibility, class: "text-white")} + {select(f, :visibility, Codebattle.TaskPack.visibility_types(), + class: + "form-select form-select-lg custom-select cb-dark-select cb-bg-panel cb-border-color text-white" + )} + {error_tag(f, :visibility)} +
+
+
+ Task_ids +
+
+ Example: 1,37,42 +
+ {text_input(f, :task_ids, + value: render_task_ids(f.data), + class: "form-control form-control-lg custom-control cb-bg-panel cb-border-color text-white", + required: true + )} + {error_tag(f, :task_ids)} +
+
+ {submit("Save", + phx_disable_with: "Saving...", + class: "btn btn-success cb-btn-success mb-2 cb-rounded" + )} + {link("Back", + to: Routes.task_pack_path(@conn, :index), + class: "btn btn-link text-white ml-auto" + )} +
+<% end) %> diff --git a/apps/codebattle/lib/codebattle_web/templates/task_pack/edit.html.heex b/apps/codebattle/lib/codebattle_web/templates/task_pack/edit.html.heex new file mode 100644 index 000000000..932fc242c --- /dev/null +++ b/apps/codebattle/lib/codebattle_web/templates/task_pack/edit.html.heex @@ -0,0 +1,7 @@ +
+

Edit task pack

+ {render( + "_form.html", + Map.put(assigns, :action, Routes.task_pack_path(@conn, :update, @task_pack)) + )} +
diff --git a/apps/codebattle/lib/codebattle_web/templates/task_pack/index.html.heex b/apps/codebattle/lib/codebattle_web/templates/task_pack/index.html.heex new file mode 100644 index 000000000..067c55baf --- /dev/null +++ b/apps/codebattle/lib/codebattle_web/templates/task_pack/index.html.heex @@ -0,0 +1,74 @@ +
+

{gettext("Task Packs")}

+ {link(gettext("Create new task pack"), + to: CodebattleWeb.Router.Helpers.task_pack_path(@conn, :new), + class: "btn btn-success cb-btn-success mt-2 cb-rounded" + )} + {link(gettext("Tasks"), + to: CodebattleWeb.Router.Helpers.task_path(@conn, :index), + class: "btn btn-secondary cb-btn-secondary mt-2 ml-2 cb-rounded" + )} +
+ + + + + + + + + + + + <%= for task_pack <- @task_packs do %> + + + + + + + + <% end %> + +
namestatevisibilitytask_idsactions
{task_pack.name}{task_pack.state} + {task_pack.visibility} + + {render_task_ids(task_pack)} + +
+ <%= if !Codebattle.User.admin?(@current_user) do %> + {link(gettext("Show"), + to: CodebattleWeb.Router.Helpers.task_pack_path(@conn, :show, task_pack.id), + class: "btn btn-sm btn-secondary cb-btn-secondary cb-rounded" + )} + <% end %> + <%= if Codebattle.User.admin?(@current_user) do %> + {link(gettext("Show"), + to: CodebattleWeb.Router.Helpers.task_pack_path(@conn, :show, task_pack.id), + class: "btn btn-sm btn-secondary cb-btn-secondary cb-rounded" + )} + {button("Activate", + to: + CodebattleWeb.Router.Helpers.task_pack_activate_path( + @conn, + :activate, + task_pack.id + ), + method: "patch", + class: "btn btn-sm btn-success cb-btn-success cb-rounded" + )} + {button("Disable", + to: + CodebattleWeb.Router.Helpers.task_pack_disable_path( + @conn, + :disable, + task_pack.id + ), + method: "patch", + class: "btn btn-sm btn-danger cb-rounded" + )} + <% end %> +
+
+
+
diff --git a/apps/codebattle/lib/codebattle_web/templates/task_pack/new.html.heex b/apps/codebattle/lib/codebattle_web/templates/task_pack/new.html.heex new file mode 100644 index 000000000..08cbe0e8a --- /dev/null +++ b/apps/codebattle/lib/codebattle_web/templates/task_pack/new.html.heex @@ -0,0 +1,7 @@ +
+

Create your own task pack

+

+ Use it for tournaments to play with tasks that you really want +

+ {render("_form.html", Map.put(assigns, :action, Routes.task_pack_path(@conn, :create)))} +
diff --git a/apps/codebattle/lib/codebattle_web/templates/task_pack/show.html.heex b/apps/codebattle/lib/codebattle_web/templates/task_pack/show.html.heex new file mode 100644 index 000000000..949da1015 --- /dev/null +++ b/apps/codebattle/lib/codebattle_web/templates/task_pack/show.html.heex @@ -0,0 +1,82 @@ +
+

+ {@task_pack.name} +

+

Params

+
+ Visibility: {@task_pack.visibility} + State: {@task_pack.state} + <%= if @task_pack.creator_id do %> + Creator_id: {@task_pack.creator_id} + <% end %> + <%= if @tasks != [] and Enum.all?(@tasks, & &1.time_to_solve_sec) do %> + Total time: {div(Enum.reduce(@tasks, 0, &(&1.time_to_solve_sec + &2)), 60)} min + <% end %> +
+ +

Tasks

+
+ + + + + + + + + + + + + + + + <%= for {task_id, index} <- Enum.with_index(@task_pack.task_ids) do %> + <%= if task = Enum.find(@tasks, fn task -> task.id == task_id end) do %> + + + + + + + + + + + + <% else %> + Task not found for id = {task_id} + <% end %> + <% end %> + +
indexidnameleveltagsoriginstatetimevisibility
{index}{task.id} + {link(task.name, + to: Routes.task_path(@conn, :show, task.id), + class: "ml-auto text-primary" + )} + {task.level} + {Enum.join(task.tags, ", ")} + {task.origin}{task.state} + {task.time_to_solve_sec} + {task.visibility}
+
+
+ <%= if Codebattle.TaskPack.can_access_task_pack?(@task_pack, @current_user) do %> + {link("Edit", + to: Routes.task_pack_path(@conn, :edit, @task_pack), + class: "btn btn-success cb-btn-success mt-2 cb-rounded" + )} + <% end %> + + <%= if Codebattle.TaskPack.can_access_task_pack?(@task_pack, @current_user) do %> + {link("Delete", + to: Routes.task_pack_path(@conn, :delete, @task_pack), + class: "btn btn-danger mt-2 cb-rounded", + method: :delete, + data: [confirm: "Delete task pack?"] + )} + <% end %> + + {link("Back", to: Routes.task_pack_path(@conn, :index), class: "ml-auto text-white")} +
+
diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/tournament/player.html.heex b/apps/codebattle/lib/codebattle_web/templates/tournament/player.html.heex similarity index 100% rename from services/app/apps/codebattle/lib/codebattle_web/templates/tournament/player.html.heex rename to apps/codebattle/lib/codebattle_web/templates/tournament/player.html.heex diff --git a/apps/codebattle/lib/codebattle_web/templates/tournament/show.html.heex b/apps/codebattle/lib/codebattle_web/templates/tournament/show.html.heex new file mode 100644 index 000000000..fa0e23c7d --- /dev/null +++ b/apps/codebattle/lib/codebattle_web/templates/tournament/show.html.heex @@ -0,0 +1,4 @@ +
+ diff --git a/apps/codebattle/lib/codebattle_web/templates/tournament/stream.html.heex b/apps/codebattle/lib/codebattle_web/templates/tournament/stream.html.heex new file mode 100644 index 000000000..5c14b4333 --- /dev/null +++ b/apps/codebattle/lib/codebattle_web/templates/tournament/stream.html.heex @@ -0,0 +1,4 @@ +
+ diff --git a/apps/codebattle/lib/codebattle_web/templates/tournament/stream_admin.html.heex b/apps/codebattle/lib/codebattle_web/templates/tournament/stream_admin.html.heex new file mode 100644 index 000000000..0641f6e82 --- /dev/null +++ b/apps/codebattle/lib/codebattle_web/templates/tournament/stream_admin.html.heex @@ -0,0 +1,4 @@ +
+ diff --git a/apps/codebattle/lib/codebattle_web/templates/tournament/threejs_stream.html.heex b/apps/codebattle/lib/codebattle_web/templates/tournament/threejs_stream.html.heex new file mode 100644 index 000000000..a5cda7d92 --- /dev/null +++ b/apps/codebattle/lib/codebattle_web/templates/tournament/threejs_stream.html.heex @@ -0,0 +1 @@ +
diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/user/edit.html.heex b/apps/codebattle/lib/codebattle_web/templates/user/edit.html.heex similarity index 100% rename from services/app/apps/codebattle/lib/codebattle_web/templates/user/edit.html.heex rename to apps/codebattle/lib/codebattle_web/templates/user/edit.html.heex diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/user/new.html.heex b/apps/codebattle/lib/codebattle_web/templates/user/new.html.heex similarity index 100% rename from services/app/apps/codebattle/lib/codebattle_web/templates/user/new.html.heex rename to apps/codebattle/lib/codebattle_web/templates/user/new.html.heex diff --git a/apps/codebattle/lib/codebattle_web/templates/user/show.html.heex b/apps/codebattle/lib/codebattle_web/templates/user/show.html.heex new file mode 100644 index 000000000..5f6cfa21f --- /dev/null +++ b/apps/codebattle/lib/codebattle_web/templates/user/show.html.heex @@ -0,0 +1,3 @@ +
+
+
diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/user/token_only.html.heex b/apps/codebattle/lib/codebattle_web/templates/user/token_only.html.heex similarity index 100% rename from services/app/apps/codebattle/lib/codebattle_web/templates/user/token_only.html.heex rename to apps/codebattle/lib/codebattle_web/templates/user/token_only.html.heex diff --git a/apps/codebattle/lib/codebattle_web/user_auth.ex b/apps/codebattle/lib/codebattle_web/user_auth.ex new file mode 100644 index 000000000..91acaa2f2 --- /dev/null +++ b/apps/codebattle/lib/codebattle_web/user_auth.ex @@ -0,0 +1,63 @@ +defmodule CodebattleWeb.UserAuth do + @moduledoc false + + import Plug.Conn + + alias Codebattle.UserSession + + @session_token_key :user_session_token + + def log_in_user(conn, user) do + {:ok, _session, token} = UserSession.create(user, session_metadata(conn)) + + conn + |> configure_session(renew: true) + |> delete_session(:user_id) + |> delete_session(:session_version) + |> put_session(@session_token_key, token) + end + + def log_out_user(conn) do + conn + |> get_session(@session_token_key) + |> UserSession.revoke_by_token() + + conn + |> clear_session() + |> configure_session(drop: true) + end + + def put_session_token(conn, token) do + conn + |> configure_session(renew: true) + |> delete_session(:user_id) + |> delete_session(:session_version) + |> put_session(@session_token_key, token) + end + + def session_token(conn), do: get_session(conn, @session_token_key) + + def session_metadata(conn) do + [ + user_agent: + conn + |> get_req_header("user-agent") + |> List.first() + |> truncate(512), + ip: format_ip(conn.remote_ip) + ] + |> Enum.reject(fn {_key, value} -> is_nil(value) end) + |> Map.new() + end + + defp format_ip(ip) do + ip + |> :inet.ntoa() + |> to_string() + rescue + ArgumentError -> nil + end + + defp truncate(nil, _max_length), do: nil + defp truncate(value, max_length), do: String.slice(value, 0, max_length) +end diff --git a/apps/codebattle/lib/codebattle_web/views/admin/group_task_view.ex b/apps/codebattle/lib/codebattle_web/views/admin/group_task_view.ex new file mode 100644 index 000000000..e3a802f3d --- /dev/null +++ b/apps/codebattle/lib/codebattle_web/views/admin/group_task_view.ex @@ -0,0 +1,19 @@ +defmodule CodebattleWeb.Admin.GroupTaskView do + use CodebattleWeb, :view + + def format_datetime(nil), do: "none" + + def format_datetime(%NaiveDateTime{} = datetime) do + datetime + |> DateTime.from_naive!("UTC") + |> format_datetime() + end + + def format_datetime(%DateTime{} = datetime) do + Calendar.strftime(datetime, "%Y-%m-%d %H:%M:%S %Z") + end + + def extract_run_error(%{"body" => %{"error" => error}}) when is_binary(error), do: error + def extract_run_error(%{"error" => error}) when is_binary(error), do: error + def extract_run_error(_result), do: "error" +end diff --git a/apps/codebattle/lib/codebattle_web/views/admin/group_tournament_view.ex b/apps/codebattle/lib/codebattle_web/views/admin/group_tournament_view.ex new file mode 100644 index 000000000..478a657e0 --- /dev/null +++ b/apps/codebattle/lib/codebattle_web/views/admin/group_tournament_view.ex @@ -0,0 +1,80 @@ +defmodule CodebattleWeb.Admin.GroupTournamentView do + use CodebattleWeb, :view + + def format_datetime(nil), do: "none" + + def format_datetime(%NaiveDateTime{} = datetime) do + datetime + |> DateTime.from_naive!("UTC") + |> format_datetime() + end + + def format_datetime(%DateTime{} = datetime) do + Calendar.strftime(datetime, "%Y-%m-%d %H:%M:%S %Z") + end + + def extract_run_error(%{errors: errors}), do: inspect(errors) + + def extract_run_error(%{"error" => "runner_request_failed", "reason" => reason} = result) when is_binary(reason) do + if timeout_reason?(reason) do + "timeout" + else + "runner_request_failed: #{reason}#{format_status(result["status"])}" + end + end + + def extract_run_error(%{"error" => "runner_request_failed", "status" => status, "body" => body}) do + inner = extract_run_error(body) + "runner_request_failed (HTTP #{status}): #{inner}" + end + + def extract_run_error(%{"body" => %{"error" => error}}) when is_binary(error), do: error + def extract_run_error(%{"error" => error}) when is_binary(error), do: error + def extract_run_error(_result), do: "error" + + defp timeout_reason?(reason) when is_binary(reason) do + String.contains?(reason, "timeout") + end + + defp format_status(nil), do: "" + defp format_status(status), do: " (HTTP #{status})" + + @doc """ + Build the show-page URL preserving existing query params, overriding any + keys passed in `overrides` (use `nil` to drop a key). + """ + def show_path(conn, group_tournament, overrides \\ %{}) do + base = Routes.admin_group_tournament_path(conn, :show, group_tournament) + + merged = + conn.query_params + |> Map.merge(stringify(overrides)) + |> Enum.reject(fn {_k, v} -> v in [nil, ""] end) + |> Enum.sort() + + case merged do + [] -> base + pairs -> base <> "?" <> URI.encode_query(pairs) + end + end + + defp stringify(map) do + Map.new(map, fn {k, v} -> {to_string(k), if(is_nil(v), do: nil, else: to_string(v))} end) + end + + def slice_label(nil), do: "All" + def slice_label(:unassigned), do: "Unassigned" + def slice_label(n) when is_integer(n), do: "Slice #{n}" + + def sort_link_dir(current_sort_by, current_sort_dir, col) do + cond do + current_sort_by == col and current_sort_dir == :desc -> "asc" + current_sort_by == col and current_sort_dir == :asc -> "desc" + true -> "desc" + end + end + + def sort_arrow(current_sort_by, :asc, col) when current_sort_by == col, do: " ▲" + def sort_arrow(current_sort_by, :desc, col) when current_sort_by == col, do: " ▼" + def sort_arrow(_, _, _), do: "" +end diff --git a/apps/codebattle/lib/codebattle_web/views/admin/tournament_duplicator_view.ex b/apps/codebattle/lib/codebattle_web/views/admin/tournament_duplicator_view.ex new file mode 100644 index 000000000..d2843a3d9 --- /dev/null +++ b/apps/codebattle/lib/codebattle_web/views/admin/tournament_duplicator_view.ex @@ -0,0 +1,3 @@ +defmodule CodebattleWeb.Admin.TournamentDuplicatorView do + use CodebattleWeb, :view +end diff --git a/apps/codebattle/lib/codebattle_web/views/admin_view.ex b/apps/codebattle/lib/codebattle_web/views/admin_view.ex new file mode 100644 index 000000000..ac744a26c --- /dev/null +++ b/apps/codebattle/lib/codebattle_web/views/admin_view.ex @@ -0,0 +1,3 @@ +defmodule CodebattleWeb.AdminView do + use CodebattleWeb, :view +end diff --git a/apps/codebattle/lib/codebattle_web/views/api/game_view.ex b/apps/codebattle/lib/codebattle_web/views/api/game_view.ex new file mode 100644 index 000000000..a5995c206 --- /dev/null +++ b/apps/codebattle/lib/codebattle_web/views/api/game_view.ex @@ -0,0 +1,154 @@ +defmodule CodebattleWeb.Api.GameView do + use CodebattleWeb, :view + + import Codebattle.Game.Helpers + + alias Codebattle.CodeCheck + alias Runner.Languages + + def render_game(game, head_to_head) do + %{ + id: get_game_id(game), + inserted_at: Map.get(game, :inserted_at), + award: game.award, + head_to_head: head_to_head, + langs: get_langs_with_templates(game), + level: game.level, + locked: game.locked, + mode: game.mode, + players: game.players, + rematch_initiator_id: Map.get(game, :rematch_initiator_id), + rematch_state: Map.get(game, :rematch_state, "none"), + starts_at: Map.get(game, :starts_at), + state: game.state, + status: game.state, + task: render_task(game), + duration_sec: Map.get(game, :duration_sec), + finishes_at: Map.get(game, :finishes_at), + hide_banned_player_controls: true, + timeout_seconds: game.timeout_seconds, + tournament_id: Map.get(game, :tournament_id), + type: game.type, + use_chat: game.use_chat, + use_timer: game.use_timer, + visibility_type: game.visibility_type + } + end + + def render_task(%{task_type: "sql"} = game), do: game.sql_task + def render_task(%{task_type: "css"} = game), do: game.css_task + def render_task(game), do: game.task + + def render_completed_games(games) do + Enum.map(games, &render_completed_game/1) + end + + def render_completed_game(game) do + %{ + id: game.id, + players: render_players(game), + finishes_at: game.finishes_at, + duration: game.duration_sec || game.timeout_seconds, + level: game.level + } + end + + # defp get_duration(%{starts_at: nil}), do: 100 + # defp get_duration(%{finishes_at: nil}), do: 100 + + # defp get_duration(%{starts_at: starts_at, finishes_at: finishes_at}) do + # NaiveDateTime.diff(finishes_at, starts_at) + # end + + defp render_players(game) do + game + |> Map.get(:players, []) + |> Enum.sort(&(&1.creator > &2.creator)) + |> Enum.map(fn player -> + player + |> Map.take([ + :creator, + :id, + :is_bot, + :is_guest, + :name, + :rank, + :rating, + :rating_diff, + :result + ]) + |> Map.put(:lang, player.editor_lang) + end) + end + + def get_langs_with_templates(nil), do: [] + + def get_langs_with_templates(%{css_task: %{}}) do + [ + %{ + slug: "css", + name: "css", + version: "3", + solution_template: "body {\n\tbackground-color: #F3AC3C;\n}" + }, + %{ + slug: "sass", + name: "scss", + version: "1.79.4", + solution_template: "body {\n\tbackground-color: #F3AC3C;\n}" + }, + %{ + slug: "less", + name: "less", + version: "4.2.0", + solution_template: "body {\n\tbackground-color: #F3AC3C;\n}" + }, + %{ + slug: "stylus", + name: "stylus", + version: "0.63.0", + solution_template: "body\n\tbackground-color #F3AC3C" + } + ] + end + + def get_langs_with_templates(%{sql_task: %{}}) do + [ + %{ + slug: "postgresql", + name: "postgresql", + version: "18", + solution_template: "SELECT solution FROM Solution;" + }, + %{ + slug: "mongodb", + name: "mongodb", + version: "8.0", + solution_template: "db.solution.find();" + }, + %{ + slug: "mysql", + name: "mysql", + version: "8.4.6", + solution_template: "SELECT solution FROM Solution;" + } + ] + end + + def get_langs_with_templates(game) when is_nil(game.task) and is_nil(game.sql_task) and is_nil(game.css_task), do: [] + + def get_langs_with_templates(game) do + Languages.meta() + |> Map.take(Languages.get_lang_slugs()) + |> Map.values() + |> Enum.map(fn meta -> + %{ + slug: meta.slug, + name: meta.name, + version: meta.version, + solution_template: CodeCheck.generate_solution_template(game.task, meta), + arguments_generator_template: Map.get(meta, :arguments_generator_template, "") + } + end) + end +end diff --git a/apps/codebattle/lib/codebattle_web/views/api/lobby_view.ex b/apps/codebattle/lib/codebattle_web/views/api/lobby_view.ex new file mode 100644 index 000000000..a1db63821 --- /dev/null +++ b/apps/codebattle/lib/codebattle_web/views/api/lobby_view.ex @@ -0,0 +1,50 @@ +defmodule CodebattleWeb.Api.LobbyView do + use CodebattleWeb, :view + + alias Codebattle.Game + alias Codebattle.Tournament + alias CodebattleWeb.Api.GameView + + def render_lobby_params(current_user) do + tournament_params = render_tournament_params(current_user) + + user_tournaments = + Tournament.Context.get_user_tournaments(%{ + from: DateTime.utc_now(), + to: DateTime.add(DateTime.utc_now(), 1 * 24 * 60 * 60), + user: current_user + }) + + %{games: games} = + Game.Context.get_completed_games( + %{}, + %{page_size: 20, total: false, page_number: 1} + ) + + completed_games = GameView.render_completed_games(games) + + Map.merge(tournament_params, %{ + active_games: render_active_games(current_user), + tournaments: [], + user_tournaments: user_tournaments, + completed_games: completed_games + }) + end + + def render_tournament_params(current_user) do + %{ + live_tournaments: Tournament.Context.get_live_tournaments_for_user(current_user), + season_tournaments: Tournament.Context.get_one_upcoming_tournament_for_each_grade() + } + end + + def render_active_games(current_user) do + %{is_tournament: false} + |> Game.Context.get_active_games() + |> Enum.filter(&can_user_see_game?(&1, current_user)) + end + + def can_user_see_game?(game, user) do + game.visibility_type == "public" || Game.Helpers.player?(game, user.id) + end +end diff --git a/apps/codebattle/lib/codebattle_web/views/api/task_view.ex b/apps/codebattle/lib/codebattle_web/views/api/task_view.ex new file mode 100644 index 000000000..4982ee236 --- /dev/null +++ b/apps/codebattle/lib/codebattle_web/views/api/task_view.ex @@ -0,0 +1,20 @@ +defmodule CodebattleWeb.Api.TaskView do + use CodebattleWeb, :view + + def render_task(task) do + %{ + id: task.id, + name: task.name, + description_en: task.description_en, + description_ru: task.description_ru, + level: task.level, + origin: task.origin, + creator_id: task.creator_id, + tags: task.tags + } + end + + def render_tasks(tasks) do + Enum.map(tasks, &render_task/1) + end +end diff --git a/services/app/apps/codebattle/lib/codebattle_web/views/api/user_view.ex b/apps/codebattle/lib/codebattle_web/views/api/user_view.ex similarity index 100% rename from services/app/apps/codebattle/lib/codebattle_web/views/api/user_view.ex rename to apps/codebattle/lib/codebattle_web/views/api/user_view.ex diff --git a/apps/codebattle/lib/codebattle_web/views/clan_view.ex b/apps/codebattle/lib/codebattle_web/views/clan_view.ex new file mode 100644 index 000000000..c9a8adce3 --- /dev/null +++ b/apps/codebattle/lib/codebattle_web/views/clan_view.ex @@ -0,0 +1,25 @@ +defmodule CodebattleWeb.ClanView do + use CodebattleWeb, :view + + def sort_link(conn, label, field, current_sort, current_order) do + next_order = next_order(field, current_sort, current_order) + + link("#{label} #{sort_marker(field, current_sort, current_order)}", + to: Routes.clan_path(conn, :index, sort: field, order: next_order), + class: "cb-text" + ) + end + + def format_inserted_at(nil), do: "-" + + def format_inserted_at(%NaiveDateTime{} = datetime) do + Calendar.strftime(datetime, "%Y-%m-%d %H:%M") + end + + defp next_order(field, current_sort, "asc") when field == current_sort, do: "desc" + defp next_order(_field, _current_sort, _current_order), do: "asc" + + defp sort_marker(field, current_sort, "asc") when field == current_sort, do: "^" + defp sort_marker(field, current_sort, "desc") when field == current_sort, do: "v" + defp sort_marker(_field, _current_sort, _current_order), do: "" +end diff --git a/apps/codebattle/lib/codebattle_web/views/css_battle_builder_view.ex b/apps/codebattle/lib/codebattle_web/views/css_battle_builder_view.ex new file mode 100644 index 000000000..81ef24269 --- /dev/null +++ b/apps/codebattle/lib/codebattle_web/views/css_battle_builder_view.ex @@ -0,0 +1,3 @@ +defmodule CodebattleWeb.CssBattleBuilderView do + use CodebattleWeb, :view +end diff --git a/services/app/apps/codebattle/lib/codebattle_web/views/error_helpers.ex b/apps/codebattle/lib/codebattle_web/views/error_helpers.ex similarity index 94% rename from services/app/apps/codebattle/lib/codebattle_web/views/error_helpers.ex rename to apps/codebattle/lib/codebattle_web/views/error_helpers.ex index 966fbe2a5..8b5d056e5 100644 --- a/services/app/apps/codebattle/lib/codebattle_web/views/error_helpers.ex +++ b/apps/codebattle/lib/codebattle_web/views/error_helpers.ex @@ -3,7 +3,10 @@ defmodule CodebattleWeb.ErrorHelpers do Conveniences for translating and building error messages. """ - use Phoenix.HTML + use PhoenixHTMLHelpers + + import Phoenix.HTML.Form + import PhoenixHTMLHelpers.Tag @doc """ Generates tag for inlined form input errors. diff --git a/services/app/apps/codebattle/lib/codebattle_web/views/error_view.ex b/apps/codebattle/lib/codebattle_web/views/error_view.ex similarity index 100% rename from services/app/apps/codebattle/lib/codebattle_web/views/error_view.ex rename to apps/codebattle/lib/codebattle_web/views/error_view.ex diff --git a/services/app/apps/codebattle/lib/codebattle_web/views/event_view.ex b/apps/codebattle/lib/codebattle_web/views/event_view.ex similarity index 88% rename from services/app/apps/codebattle/lib/codebattle_web/views/event_view.ex rename to apps/codebattle/lib/codebattle_web/views/event_view.ex index 0922e9779..1674f7c03 100644 --- a/services/app/apps/codebattle/lib/codebattle_web/views/event_view.ex +++ b/apps/codebattle/lib/codebattle_web/views/event_view.ex @@ -13,6 +13,6 @@ defmodule CodebattleWeb.EventView do def format_datetime(%DateTime{} = datetime, timezone) do datetime |> DateTime.shift_zone!(timezone) - |> Timex.format!("%Y-%m-%d %H:%M %Z", :strftime) + |> Calendar.strftime("%Y-%m-%d %H:%M %Z") end end diff --git a/services/app/apps/codebattle/lib/codebattle_web/views/feedback_view.ex b/apps/codebattle/lib/codebattle_web/views/feedback_view.ex similarity index 100% rename from services/app/apps/codebattle/lib/codebattle_web/views/feedback_view.ex rename to apps/codebattle/lib/codebattle_web/views/feedback_view.ex diff --git a/services/app/apps/codebattle/lib/codebattle_web/views/form_helpers.ex b/apps/codebattle/lib/codebattle_web/views/form_helpers.ex similarity index 92% rename from services/app/apps/codebattle/lib/codebattle_web/views/form_helpers.ex rename to apps/codebattle/lib/codebattle_web/views/form_helpers.ex index a1171756e..4d26ab513 100644 --- a/services/app/apps/codebattle/lib/codebattle_web/views/form_helpers.ex +++ b/apps/codebattle/lib/codebattle_web/views/form_helpers.ex @@ -17,10 +17,10 @@ defmodule CodebattleWeb.FormHelpers do phx-feedback-for={input_name(@form, @field)} class={[@class, if(@form.errors[@field], do: "show-errors", else: "")]} > - <%= render_slot(@inner_block) %> + {render_slot(@inner_block)} <%= for error <- Keyword.get_values(@form.errors, @field) do %> <% end %>
diff --git a/apps/codebattle/lib/codebattle_web/views/game_view.ex b/apps/codebattle/lib/codebattle_web/views/game_view.ex new file mode 100644 index 000000000..534e9aa48 --- /dev/null +++ b/apps/codebattle/lib/codebattle_web/views/game_view.ex @@ -0,0 +1,19 @@ +defmodule CodebattleWeb.GameView do + use CodebattleWeb, :view + + import Codebattle.Game.Helpers + + def user_name(%Codebattle.User{name: name}), do: name || "" + + def player_name(%Codebattle.Game.Player{name: name}), do: name || "" + + def result(%Codebattle.Game{users: users, user_games: user_games}) do + Enum.map_join(users, ", ", fn u -> + "#{user_name(u)} #{Enum.find(user_games, fn ug -> ug.user_id == u.id end).result}" + end) + end + + def csrf_token do + Plug.CSRFProtection.get_csrf_token() + end +end diff --git a/apps/codebattle/lib/codebattle_web/views/github_stars_helpers.ex b/apps/codebattle/lib/codebattle_web/views/github_stars_helpers.ex new file mode 100644 index 000000000..0e2b30a39 --- /dev/null +++ b/apps/codebattle/lib/codebattle_web/views/github_stars_helpers.ex @@ -0,0 +1,47 @@ +defmodule CodebattleWeb.GithubStarsHelpers do + @moduledoc false + + use Phoenix.Component + + alias Codebattle.GithubStarsCache + + attr(:class, :string, default: nil) + + def github_stars_badge(assigns) do + ~H""" + + + + Stars + + {github_stars_count_text()} + + """ + end + + def github_stars_count_text, do: format_count(GithubStarsCache.get_stars_count()) + + defp format_count(count) when count >= 1_000_000 do + "#{(count / 1_000_000) |> Float.round(1) |> trim_trailing_zero()}M" + end + + defp format_count(count) when count >= 1_000 do + "#{(count / 1_000) |> Float.round(1) |> trim_trailing_zero()}k" + end + + defp format_count(count), do: Integer.to_string(count) + + defp trim_trailing_zero(value) do + value + |> :erlang.float_to_binary(decimals: 1) + |> String.replace_suffix(".0", "") + end +end diff --git a/apps/codebattle/lib/codebattle_web/views/group_tournament_view.ex b/apps/codebattle/lib/codebattle_web/views/group_tournament_view.ex new file mode 100644 index 000000000..1bd57f716 --- /dev/null +++ b/apps/codebattle/lib/codebattle_web/views/group_tournament_view.ex @@ -0,0 +1,7 @@ +defmodule CodebattleWeb.GroupTournamentView do + use CodebattleWeb, :view + + def csrf_token do + Plug.CSRFProtection.get_csrf_token() + end +end diff --git a/services/app/apps/codebattle/lib/codebattle_web/views/invite_view.ex b/apps/codebattle/lib/codebattle_web/views/invite_view.ex similarity index 100% rename from services/app/apps/codebattle/lib/codebattle_web/views/invite_view.ex rename to apps/codebattle/lib/codebattle_web/views/invite_view.ex diff --git a/apps/codebattle/lib/codebattle_web/views/layout_view.ex b/apps/codebattle/lib/codebattle_web/views/layout_view.ex new file mode 100644 index 000000000..93d9b5df8 --- /dev/null +++ b/apps/codebattle/lib/codebattle_web/views/layout_view.ex @@ -0,0 +1,170 @@ +defmodule CodebattleWeb.LayoutView do + use CodebattleWeb, :view + + import CodebattleWeb.LobbyLoadingHelpers + import CodebattleWeb.Router.Helpers + import Inertia.HTML + + def inertia_shared_props_json(conn) do + conn.assigns + |> Map.get(:frontend_shared_props, %{}) + |> Jason.encode!() + end + + @google_fonts_href "https://fonts.googleapis.com/css2?family=Source+Code+Pro:wght@400;500;600;800&family=Montserrat:wght@400;700&display=swap" + + @doc """ + Non-render-blocking Google Fonts loading for the document head. + + Previously the two font families were pulled in via `@import` inside the CSS + bundle, which forces the browser to download and parse the stylesheet before it + can even request the fonts (a render-blocking request chain). Preconnecting and + loading the combined stylesheet asynchronously (`media="print"` + `onload`) + removes fonts from the critical path; `
-
-
- {editable ? ( - <> -

- Description: -

- -
- Edit the JSON representation of the stages. Make sure to keep valid JSON format. -
-
- - -
- - - - <% end %> - """ - end -end diff --git a/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/create_form.ex b/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/create_form.ex deleted file mode 100644 index 312b9da8a..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/create_form.ex +++ /dev/null @@ -1,347 +0,0 @@ -defmodule CodebattleWeb.Live.Tournament.CreateFormComponent do - @moduledoc false - use CodebattleWeb, :live_component - - import CodebattleWeb.ErrorHelpers - - @impl true - def mount(socket) do - {:ok, assign(socket, initialized: false)} - end - - @impl true - def render(assigns) do - assigns = - assigns - |> assign( - :default_rounds_config_json, - """ - [{"award": "red"}, {"award": "red"}, {"award": "blue"}] - """ - ) - |> assign(:default_game_passwords_json, ~S(["12341234", "33322233", "11112222"])) - - ~H""" -
-

Create a new tournament

- <.form - :let={f} - for={@changeset} - phx-change="validate" - phx-submit="create" - class="col-12 col-md-10 col-lg-10 col-xl-10 offset-md-1 offset-lg-1 offset-xl-1" - > -
- <%= render_base_errors(@changeset.errors[:base]) %> -
-
-
- <%= label(f, :name) %> - <%= text_input(f, :name, - class: "form-control", - value: f.params["name"] || "My fancy tournament", - maxlength: "42", - required: true - ) %> - <%= error_tag(f, :name) %> -
-
- <%= label(f, :type) %> - <%= select(f, :type, Codebattle.Tournament.public_types(), class: "custom-select") %> - <%= error_tag(f, :type) %> -
-
-
-
- <%= label(f, :description) %> - <%= textarea(f, :description, - class: "form-control", - value: - f.params["description"] || - "Markdown description. [stream_link](https://codebattle.hexlet.io)", - maxlength: "7531", - rows: 20, - cols: 50, - required: true - ) %> - <%= error_tag(f, :description) %> -
-
-
-
- - <%= datetime_local_input(f, :starts_at, - class: "form-control", - required: true, - min: - DateTime.now!(@user_timezone) - |> DateTime.truncate(:second) - |> Timex.format!("%Y-%m-%dT%H:%M", :strftime), - value: f.params["starts_at"] || DateTime.add(DateTime.now!(@user_timezone), 5, :minute) - ) %> - <%= error_tag(f, :starts_at) %> -
-
- <%= label(f, :access_type) %> - <%= select(f, :access_type, Codebattle.Tournament.access_types(), class: "custom-select") %> - <%= error_tag(f, :access_type) %> -
-
- <%= label(f, :task_strategy) %> - <%= select(f, :task_strategy, Codebattle.Tournament.task_strategies(), - class: "custom-select", - value: f.params["task_strategy"] || f.data.task_strategy - ) %> - <%= error_tag(f, :task_strategy) %> -
-
- <%= label(f, :score_strategy) %> - <%= select(f, :score_strategy, Codebattle.Tournament.score_strategies(), - class: "custom-select", - value: f.params["score_strategy"] || f.data.score_strategy - ) %> - <%= error_tag(f, :score_strategy) %> -
-
-
-
- <%= checkbox(f, :use_chat, class: "form-check-input") %> - <%= label(f, :use_chat, class: "form-check-label") %> - <%= error_tag(f, :use_chat) %> -
-
- <%= checkbox(f, :use_timer, class: "form-check-input") %> - <%= label(f, :use_timer, class: "form-check-label") %> - <%= error_tag(f, :use_timer) %> -
-
-
-
- <%= label(f, :task_provider) %> - <%= select(f, :task_provider, Codebattle.Tournament.task_providers(), - class: "custom-select", - value: f.params["task_provider"] || f.data.task_provider - ) %> - <%= error_tag(f, :task_provider) %> -
- <%= if (f.params["task_provider"] == "level" || is_nil(f.params["task_provider"])) do %> -
- <%= label(f, :level) %> - <%= select(f, :level, Codebattle.Tournament.levels(), - class: "custom-select", - value: f.params["level"] || f.data.level - ) %> - <%= error_tag(f, :level) %> -
- <% end %> - <%= if (f.params["task_provider"] == "task_pack") do %> -
- <%= label(f, :task_pack_name) %> - <%= select(f, :task_pack_name, @task_pack_names, - class: "custom-select", - value: f.params["task_pack_name"] || f.data.task_pack_name - ) %> - <%= error_tag(f, :task_pack_name) %> -
- <% end %> - <%= if (f.params["task_provider"] == "task_pack_per_round") do %> -
- <%= label(f, :task_pack_name) %> - <%= text_input(f, :task_pack_name, - class: "form-control", - value: f.params["task_pack_name"] || f.data.task_pack_name, - placeholder: "all_easy,all_medium" - ) %> - <%= error_tag(f, :task_pack_names) %> -
- <% end %> - <%= if (f.params["task_provider"] == "tags") do %> -
- <%= label(f, :level) %> - <%= select(f, :level, Codebattle.Tournament.levels(), - class: "custom-select", - value: f.params["level"] || f.data.level - ) %> - <%= error_tag(f, :level) %> -
- <% end %> -
-
- <%= if (f.params["task_provider"] == "tags") do %> -
- <%= label(f, :tags) %> - <%= text_input(f, :tags, - value: f.params["tags"], - class: "form-control", - placeholder: "strings,math" - ) %> - <%= error_tag(f, :tags) %> -
- <% end %> -
- -
-
- <%= label(f, :event_id) %> - <%= number_input( - f, - :event_id, - class: "form-control", - value: f.params["event_id"] - ) %> - <%= error_tag(f, :event_id) %> -
-
- -
-
-
- <%= label(f, :players_limit) %> - <%= select( - f, - :players_limit, - [2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384], - value: f.params["players_limit"] || 64, - class: "custom-select" - ) %> - <%= error_tag(f, :players_limit) %> -
-
-
-
- <%= label(f, :match_timeout_seconds) %> - <%= number_input( - f, - :match_timeout_seconds, - class: "form-control", - value: f.params["match_timeout_seconds"] || "177", - min: "7", - max: "10000" - ) %> -
-
- <%= label(f, :break_duration_seconds) %> - <%= number_input( - f, - :break_duration_seconds, - class: "form-control", - value: f.params["break_duration_seconds"] || "42", - min: "0", - max: "100000" - ) %> -
-
-
- <%= if f.params["type"] == "team" do %> -
-
- <%= label(f, :team_1_name) %> - <%= text_input(f, :team_1_name, - maxlength: "17", - class: "form-control", - value: f.params["team_1_name"] || "Backend" - ) %> -
-
- <%= label(f, :team_2_name) %> - <%= text_input(f, :team_2_name, - maxlength: "17", - class: "form-control", - value: f.params["team_2_name"] || "Frontend" - ) %> -
-
- <%= label(f, :rounds_to_win) %> - <%= select(f, :rounds_to_win, [1, 2, 3, 4, 5], - value: f.params["rounds_to_win"] || 3, - class: "custom-select" - ) %> - <%= error_tag(f, :rounds_to_win) %> -
-
- <% end %> - <%= if f.params["type"] in ["arena", "swiss"] do %> -
-
- <%= label(f, :rounds_limit) %> - <%= select(f, :rounds_limit, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 137, 200], - class: "custom-select" - ) %> - <%= error_tag(f, :rounds_limit) %> -
-
-
-
- <%= label(f, :ranking_type) %> - <%= select(f, :ranking_type, Codebattle.Tournament.ranking_types(), - class: "custom-select", - value: f.params["ranking_type"] || f.data.ranking_type - ) %> - <%= error_tag(f, :ranking_type) %> -
-
- <% end %> - <%= if f.params["type"] in ["arena", "squad"] do %> -
-
- <%= label(f, :round_timeout_seconds) %> - <%= number_input( - f, - :round_timeout_seconds, - class: "form-control", - value: f.params["round_timeout_seconds"] || "177", - min: "100", - max: "10000" - ) %> - <%= error_tag(f, :round_timeout_seconds) %> -
-
- <% end %> - <%= if f.params["type"] in ["arena"] do %> -
-
- <%= checkbox(f, :use_clan, class: "form-check-input") %> - <%= label(f, :use_clan, class: "form-check-label") %> - <%= error_tag(f, :use_clan) %> -
-
- <%= checkbox(f, :use_event_ranking, class: "form-check-input") %> - <%= label(f, :use_event_ranking, class: "form-check-label") %> - <%= error_tag(f, :use_event_ranking) %> -
-
- <% end %> - <%= if (f.params["type"] == "show") do %> -
- <%= label(f, :game_passwords_json) %> - <%= textarea(f, :game_passwords_json, - class: "form-control", - value: f.params["game_passwords_json"] || @default_game_passwords_json, - maxlength: "9350", - rows: "10" - ) %> - <%= error_tag(f, :game_passwords_json) %> -
-
- <%= label(f, :rounds_config_json) %> - <%= textarea(f, :rounds_config_json, - class: "form-control", - value: f.params["rounds_config_json"] || @default_rounds_config_json, - maxlength: "9350", - rows: "10" - ) %> - <%= error_tag(f, :rounds_config_json) %> -
- <% end %> - <%= submit("Create", - phx_disable_with: "Creating...", - class: "btn btn-primary rounded-lg my-4" - ) %> - -
- """ - end - - def render_base_errors(nil), do: nil - def render_base_errors(errors), do: elem(errors, 0) -end diff --git a/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/edit_form.ex b/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/edit_form.ex deleted file mode 100644 index 9ce8edb1d..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/edit_form.ex +++ /dev/null @@ -1,256 +0,0 @@ -defmodule CodebattleWeb.Live.Tournament.EditFormComponent do - @moduledoc false - use CodebattleWeb, :live_component - - import CodebattleWeb.ErrorHelpers - - @impl true - def mount(socket) do - {:ok, assign(socket, initialized: false)} - end - - @impl true - def render(assigns) do - ~H""" -
-

Edit tournament

-

- Creator: - - <%= @tournament.creator.name %> - -

- - <.form - :let={f} - for={@changeset} - phx-change="validate" - phx-submit="update" - class="col-12 col-md-8 col-lg-8 col-xl-8 offset-md-2 offset-lg-2 offset-xl-2" - > - <%= hidden_input(f, :tournament_id, value: @tournament.id) %> -
- <%= render_base_errors(@changeset.errors[:base]) %> -
-
-
- <%= label(f, :name) %> - <%= text_input(f, :name, - class: "form-control", - maxlength: "42", - required: true - ) %> - <%= error_tag(f, :name) %> -
-
- <%= label(f, :type) %> - <%= select(f, :type, Codebattle.Tournament.public_types(), class: "custom-select") %> - <%= error_tag(f, :type) %> -
-
-
-
- <%= label(f, :description) %> - <%= textarea(f, :description, - class: "form-control", - maxlength: "7531", - rows: 20, - cols: 50, - required: true - ) %> - <%= error_tag(f, :description) %> -
-
-
-
- - <%= datetime_local_input(f, :starts_at, - class: "form-control", - value: - DateTime.from_naive!( - Timex.parse!(f.params["starts_at"], "{ISO:Extended}"), - @user_timezone - ), - required: true - ) %> - <%= error_tag(f, :starts_at) %> -
-
- <%= label(f, :access_type) %> - <%= select(f, :access_type, Codebattle.Tournament.access_types(), class: "custom-select") %> - <%= error_tag(f, :access_type) %> -
-
- <%= label(f, :task_strategy) %> - <%= select(f, :task_strategy, Codebattle.Tournament.task_strategies(), - class: "custom-select" - ) %> - <%= error_tag(f, :task_strategy) %> -
-
-
-
- <%= checkbox(f, :use_chat, class: "form-check-input") %> - <%= label(f, :use_chat, class: "form-check-label") %> - <%= error_tag(f, :use_chat) %> -
-
- <%= checkbox(f, :use_clan, class: "form-check-input") %> - <%= label(f, :use_clan, class: "form-check-label") %> - <%= error_tag(f, :use_clan) %> -
-
- <%= checkbox(f, :use_event_ranking, class: "form-check-input") %> - <%= label(f, :use_event_ranking, class: "form-check-label") %> - <%= error_tag(f, :use_event_ranking) %> -
-
- <%= checkbox(f, :use_timer, class: "form-check-input") %> - <%= label(f, :use_timer, class: "form-check-label") %> - <%= error_tag(f, :use_timer) %> -
-
-
-
- <%= label(f, :task_provider) %> - <%= select(f, :task_provider, Codebattle.Tournament.task_providers(), - class: "custom-select" - ) %> - <%= error_tag(f, :task_provider) %> -
- <%= if (f.params["task_provider"] == "level") do %> -
- <%= label(f, :level) %> - <%= select(f, :level, Codebattle.Tournament.levels(), class: "custom-select") %> - <%= error_tag(f, :level) %> -
- <% end %> - <%= if (f.params["task_provider"] == "task_pack") do %> -
- <%= label(f, :task_pack_name) %> - <%= select(f, :task_pack_name, @task_pack_names, - class: "custom-select", - value: f.params["task_pack_name"] || f.data.task_pack_name - ) %> - <%= error_tag(f, :task_pack_name) %> -
- <% end %> - <%= if (f.params["task_provider"] == "task_pack_per_round") do %> -
- <%= label(f, :task_pack_name) %> - <%= text_input(f, :task_pack_name, - class: "form-control", - placeholder: "all_easy,all_medium" - ) %> - <%= error_tag(f, :task_pack_names) %> -
- <% end %> -
- -
-
-
- <%= label(f, :players_limit) %> - <%= select( - f, - :players_limit, - [2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384], - class: "custom-select" - ) %> - <%= error_tag(f, :players_limit) %> -
-
-
-
- <%= label(f, :match_timeout_seconds) %> - <%= number_input( - f, - :match_timeout_seconds, - class: "form-control", - min: "7", - max: "10000" - ) %> - <%= error_tag(f, :break_duration_seconds) %> -
-
- <%= label(f, :round_timeout_seconds) %> - <%= number_input( - f, - :round_timeout_seconds, - class: "form-control", - max: "10000" - ) %> - <%= error_tag(f, :break_duration_seconds) %> -
-
- <%= label(f, :event_id) %> - <%= number_input( - f, - :event_id, - class: "form-control", - max: "10000" - ) %> - <%= error_tag(f, :event_id) %> -
-
- <%= label(f, :break_duration_seconds) %> - <%= number_input( - f, - :break_duration_seconds, - class: "form-control", - min: "0", - max: "1957" - ) %> - <%= error_tag(f, :break_duration_seconds) %> -
-
-
-
-
-
- <%= label(f, :ranking_type) %> - <%= select(f, :ranking_type, Codebattle.Tournament.ranking_types(), - class: "custom-select", - value: f.params["ranking_type"] || f.data.ranking_type - ) %> - <%= error_tag(f, :ranking_type) %> -
-
- <%= label(f, :score_strategy) %> - <%= select(f, :score_strategy, Codebattle.Tournament.score_strategies(), - class: "custom-select" - ) %> - <%= error_tag(f, :score_strategy) %> -
-
-
- -
-
- <%= label(f, :meta_json) %> - <%= textarea(f, :meta_json, - class: "form-control", - value: f.params["meta_json"] || "{}" - ) %> - <%= error_tag(f, :meta_json) %> -
-
- - <%= submit("Update", - phx_disable_with: "Updating...", - class: "btn btn-primary rounded-lg my-4" - ) %> - - Back to tournament - - -
- """ - end - - def render_base_errors(nil), do: nil - def render_base_errors(errors), do: elem(errors, 0) -end diff --git a/services/app/apps/codebattle/lib/codebattle_web/live/event/leaderboard_view.ex b/services/app/apps/codebattle/lib/codebattle_web/live/event/leaderboard_view.ex deleted file mode 100644 index 48a42030a..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/live/event/leaderboard_view.ex +++ /dev/null @@ -1,50 +0,0 @@ -defmodule CodebattleWeb.Live.Event.LeaderboardView do - use CodebattleWeb, :live_view - use Gettext, backend: CodebattleWeb.Gettext - - @impl true - def mount(_params, session, socket) do - {:ok, - assign(socket, - current_user: session["current_user"], - leaderboard_list: session["leaderboard"] - )} - end - - @impl true - def render(assigns) do - ~H""" -
- - - - - - - - - - - <%= for item <- @leaderboard_list do %> - - - - - - - - <% end %> - -
<%= gettext("Place") %><%= gettext("Score") %><%= gettext("Clan players count") %><%= gettext("Clan") %>
- <%= item.place %> - - <%= item.score %> - - <%= item.players_count %> - - <%= item.clan_name %> -
-
- """ - end -end diff --git a/services/app/apps/codebattle/lib/codebattle_web/live/tournament/edit_view.ex b/services/app/apps/codebattle/lib/codebattle_web/live/tournament/edit_view.ex deleted file mode 100644 index 9fded7205..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/live/tournament/edit_view.ex +++ /dev/null @@ -1,93 +0,0 @@ -defmodule CodebattleWeb.Live.Tournament.EditView do - use CodebattleWeb, :live_view - use Timex - - import Ecto.Changeset - - alias Codebattle.Tournament - alias CodebattleWeb.Live.Tournament.EditFormComponent - - require Logger - - @impl true - def mount(_params, session, socket) do - user_timezone = get_in(socket.private, [:connect_params, "timezone"]) || "UTC" - tournament = session["tournament"] - - {:ok, - assign(socket, - current_user: session["current_user"], - user_timezone: user_timezone, - tournament: tournament, - changeset: - Codebattle.Tournament.changeset(tournament, %{ - type: tournament.type, - task_provider: tournament.task_provider, - starts_at: tournament.starts_at |> DateTime.shift_zone!(user_timezone) |> to_string(), - meta_json: Jason.encode!(tournament.meta) - }) - )} - end - - @impl true - def render(assigns) do - ~H""" -
- <.live_component - id="create-form" - module={EditFormComponent} - tournament={@tournament} - user_timezone={@user_timezone} - changeset={@changeset} - langs={Runner.Languages.get_lang_slugs()} - task_pack_names={@current_user |> Codebattle.TaskPack.list_visible() |> Enum.map(& &1.name)} - /> -
- """ - end - - @impl true - def handle_event("validate", %{"tournament" => params}, socket) do - user_timezone = socket.assigns.user_timezone - tournament = socket.assigns.tournament - - changeset = - Tournament.Context.validate( - Map.put(params, "user_timezone", user_timezone), - tournament - ) - - case apply_action(changeset, :validate) do - {:ok, tournament} -> - {:noreply, - assign(socket, - tournament: tournament, - changeset: changeset - )} - - {:error, changeset} -> - {:noreply, - assign(socket, - tournament: tournament, - changeset: changeset - )} - end - end - - @impl true - def handle_event("update", %{"tournament" => params}, socket) do - user_timezone = socket.assigns.user_timezone - tournament = Tournament.Context.get!(params["tournament_id"]) - - case Tournament.Context.update( - tournament, - Map.put(params, "user_timezone", user_timezone) - ) do - {:ok, tournament} -> - {:noreply, redirect(socket, to: "/tournaments/#{tournament.id}")} - - {:error, %Ecto.Changeset{} = changeset} -> - {:noreply, assign(socket, changeset: changeset)} - end - end -end diff --git a/services/app/apps/codebattle/lib/codebattle_web/live/tournament/index_view.ex b/services/app/apps/codebattle/lib/codebattle_web/live/tournament/index_view.ex deleted file mode 100644 index edd7b531a..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/live/tournament/index_view.ex +++ /dev/null @@ -1,125 +0,0 @@ -defmodule CodebattleWeb.Live.Tournament.IndexView do - use CodebattleWeb, :live_view - use Timex - - import CodebattleWeb.TournamentView - - alias Codebattle.Tournament - alias CodebattleWeb.Live.Tournament.CreateFormComponent - - @impl true - def mount(_params, session, socket) do - user_timezone = get_in(socket.private, [:connect_params, "timezone"]) || "UTC" - - Codebattle.PubSub.subscribe("tournaments") - - current_user = session["current_user"] - - {:ok, - assign(socket, - current_user: current_user, - user_timezone: user_timezone, - tournaments: session["tournaments"], - langs: Runner.Languages.get_lang_slugs(), - changeset: Codebattle.Tournament.changeset(%Codebattle.Tournament{}) - )} - end - - @impl true - def render(assigns) do - ~H""" -
-

Tournaments

-
- - - - - - - - - - - - - <%= for tournament <- @tournaments do %> - - - - - - - - - <% end %> - -
nametypelevelstatestarts_atactions
<%= tournament.name %><%= tournament.type %> - {tournament.level} - <%= tournament.state %> - <%= format_datetime(tournament.starts_at, @user_timezone) %> - - <%= link("Show", - to: Routes.tournament_path(@socket, :show, tournament.id), - class: "btn btn-success text-white rounded-lg mt-2" - ) %> -
-
-
- -
- <.live_component - id="create-form" - module={CreateFormComponent} - changeset={@changeset} - user_timezone={@user_timezone} - langs={@langs} - task_pack_names={@current_user |> Codebattle.TaskPack.list_visible() |> Enum.map(& &1.name)} - /> -
- """ - end - - @impl true - def handle_event(_event, _params, %{assigns: %{current_user: %{is_guest: true}}} = socket) do - {:noreply, socket} - end - - @impl true - def handle_event("validate", %{"tournament" => params}, socket) do - creator = socket.assigns.current_user - - changeset = - Tournament.Context.validate(Map.put(params, "creator", creator)) - - {:noreply, assign(socket, changeset: changeset)} - end - - @impl true - def handle_event("create", %{"tournament" => params}, socket) do - params = - Map.merge( - params, - %{ - "creator" => socket.assigns.current_user, - "user_timezone" => socket.assigns.user_timezone - } - ) - - case Tournament.Context.create(params) do - {:ok, tournament} -> - {:noreply, redirect(socket, to: "/tournaments/#{tournament.id}")} - - {:error, %Ecto.Changeset{} = changeset} -> - {:noreply, assign(socket, changeset: changeset)} - end - end - - @impl true - def handle_info(%{topic: "tournaments"}, socket) do - user = socket.assigns.current_user - {:noreply, assign(socket, tournaments: Tournament.Context.list_live_and_finished(user))} - end - - def handle_info(_, socket), do: {:noreply, socket} -end diff --git a/services/app/apps/codebattle/lib/codebattle_web/live/tournament/timer_view.ex b/services/app/apps/codebattle/lib/codebattle_web/live/tournament/timer_view.ex deleted file mode 100644 index 8d44bb788..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/live/tournament/timer_view.ex +++ /dev/null @@ -1,106 +0,0 @@ -defmodule CodebattleWeb.Live.Tournament.TimerView do - use CodebattleWeb, :live_view - use Timex - - require Logger - - @timer_tick_frequency to_timeout(second: 1) - - @impl true - def mount(_params, session, socket) do - tournament = session["tournament"] - - Codebattle.PubSub.subscribe(topic_name(tournament)) - - :timer.send_interval(@timer_tick_frequency, self(), :timer_tick) - - {:ok, - assign(socket, - current_user: session["current_user"], - now: NaiveDateTime.utc_now(:second), - tournament: tournament - )} - end - - @impl true - def render(assigns) do - ~H""" -
- <%= render_remaining_time( - @tournament.break_state, - @tournament.last_round_started_at, - @tournament.round_timeout_seconds, - @now - ) %> -
- """ - end - - @impl true - def handle_info(:timer_tick, socket) do - {:noreply, assign(socket, now: NaiveDateTime.utc_now(:second))} - end - - def handle_info(%{topic: _topic, event: "tournament:updated", payload: payload}, socket) do - {:noreply, assign(socket, tournament: payload.tournament)} - end - - def handle_info(event, socket) do - Logger.debug("CodebattleWeb.Live.Tournament.ShowView unexpected event #{inspect(event)}") - {:noreply, socket} - end - - defp topic_name(tournament), do: "tournament:#{tournament.id}" - - defp render_remaining_time("on", _last_round_started_at, _round_timeout_seconds, _now) do - render_break(%{}) - end - - defp render_remaining_time(_break_state, nil, _round_timeout_seconds, _now) do - render_break(%{}) - end - - defp render_remaining_time("off", last_round_started_at, round_timeout_seconds, now) do - datetime = NaiveDateTime.add(last_round_started_at, round_timeout_seconds) - time_map = get_time_units_map(datetime, now) - - cond do - time_map.hours > 0 -> - "#{render_num(time_map.hours)}::#{render_num(time_map.minutes)}" - - time_map.minutes > 0 -> - "#{render_num(time_map.minutes)}:#{render_num(time_map.seconds)}" - - time_map.seconds > 0 -> - "00:#{render_num(time_map.seconds)}" - - true -> - render_break(%{}) - end - end - - defp render_num(num), do: String.pad_leading(to_string(num), 2, "0") - - defp get_time_units_map(datetime, now) do - days = round(Timex.diff(datetime, now, :days)) - hours = round(Timex.diff(datetime, now, :hours) - days * 24) - minutes = round(Timex.diff(datetime, now, :minutes) - days * 24 * 60 - hours * 60) - - seconds = - round( - Timex.diff(datetime, now, :seconds) - days * 24 * 60 * 60 - hours * 60 * 60 - - minutes * 60 - ) - - %{ - days: days, - hours: hours, - minutes: minutes, - seconds: seconds - } - end - - defp render_break(_assigns) do - "00:00" - end -end diff --git a/services/app/apps/codebattle/lib/codebattle_web/plugs/assign_current_user.ex b/services/app/apps/codebattle/lib/codebattle_web/plugs/assign_current_user.ex deleted file mode 100644 index 912059960..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/plugs/assign_current_user.ex +++ /dev/null @@ -1,42 +0,0 @@ -defmodule CodebattleWeb.Plugs.AssignCurrentUser do - @moduledoc false - import Phoenix.Controller - import Plug.Conn - - alias Codebattle.User - alias CodebattleWeb.Router.Helpers, as: Routes - - @spec init(Keyword.t()) :: Keyword.t() - def init(opts), do: opts - - @spec call(Plug.Conn.t(), Keyword.t()) :: Plug.Conn.t() - def call(conn, _opts) do - user_id = get_session(conn, :user_id) - - case user_id do - nil -> - assign(conn, :current_user, User.build_guest()) - - id -> - case User.get(id) do - nil -> - conn - |> clear_session() - |> put_flash(:danger, "You must be logged in to access that page") - |> redirect(to: Routes.session_path(conn, :new)) - |> halt() - - %User{subscription_type: :banned} -> - html = Phoenix.View.render_to_string(CodebattleWeb.LayoutView, "banned.html", conn: conn) - - conn - |> put_resp_content_type("text/html") - |> send_resp(403, html) - |> halt() - - user -> - assign(conn, :current_user, user) - end - end - end -end diff --git a/services/app/apps/codebattle/lib/codebattle_web/plugs/assign_gon.ex b/services/app/apps/codebattle/lib/codebattle_web/plugs/assign_gon.ex deleted file mode 100644 index bd25af30a..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/plugs/assign_gon.ex +++ /dev/null @@ -1,55 +0,0 @@ -defmodule CodebattleWeb.Plugs.AssignGon do - @moduledoc false - - import PhoenixGon.Controller - import Plug.Conn - - @spec init(Keyword.t()) :: Keyword.t() - def init(opts), do: opts - - @spec call(Plug.Conn.t(), Keyword.t()) :: Plug.Conn.t() - def call(conn, _opts) do - current_user = conn.assigns.current_user - - user_token = Phoenix.Token.sign(conn, "user_token", current_user.id) - - conn - |> assign(:ticker_text, nil) - |> put_gon( - sentry_data_source_name: Application.get_env(:sentry_fe, :dsn), - user_token: user_token, - current_user: prepare_user(current_user), - rollbar_api_key: Application.get_env(:codebattle, Codebattle.Plugs)[:rollbar_api_key] - ) - end - - defp prepare_user(user) do - user - |> Map.take([ - :achievements, - :clan, - :clan_id, - :discord_avatar, - :discord_id, - :discord_name, - :editor_mode, - :editor_theme, - :games_played, - :github_id, - :github_name, - :id, - :inserted_at, - :is_bot, - :is_guest, - :category, - :lang, - :name, - :performance, - :rank, - :rating, - :subscription_type, - :sound_settings - ]) - |> Map.put(:is_admin, Codebattle.User.admin?(user)) - end -end diff --git a/services/app/apps/codebattle/lib/codebattle_web/plugs/locale.ex b/services/app/apps/codebattle/lib/codebattle_web/plugs/locale.ex deleted file mode 100644 index 15152d17f..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/plugs/locale.ex +++ /dev/null @@ -1,29 +0,0 @@ -defmodule CodebattleWeb.Plugs.Locale do - @moduledoc """ - I18n configuration - """ - import PhoenixGon.Controller - import Plug.Conn - - def init(_opts), do: nil - - def call(conn, _opts) do - locale = - if FunWithFlags.enabled?(:enforce_default_locale) do - Application.get_env(:codebattle, :default_locale) - else - conn.params["locale"] || get_session(conn, :locale) || - Application.get_env(:codebattle, :default_locale) - end - - put_locale(conn, locale) - end - - defp put_locale(conn, locale) do - Gettext.put_locale(CodebattleWeb.Gettext, locale) - - conn - |> put_gon(locale: locale) - |> put_session(:locale, locale) - end -end diff --git a/services/app/apps/codebattle/lib/codebattle_web/plugs/require_auth.ex b/services/app/apps/codebattle/lib/codebattle_web/plugs/require_auth.ex deleted file mode 100644 index d92c41560..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/plugs/require_auth.ex +++ /dev/null @@ -1,25 +0,0 @@ -defmodule CodebattleWeb.Plugs.RequireAuth do - @moduledoc false - use Gettext, backend: CodebattleWeb.Gettext - - import Phoenix.Controller - import Plug.Conn - - alias CodebattleWeb.Router.Helpers, as: Routes - - def init(options), do: options - - def call(conn, _) do - if conn.assigns.current_user.is_guest do - next_path = String.replace(conn.request_path, "join", "") - url = Routes.session_path(conn, :new, next: next_path) - - conn - |> put_flash(:danger, gettext("You must be logged in to access that page")) - |> redirect(to: url) - |> halt() - else - conn - end - end -end diff --git a/services/app/apps/codebattle/lib/codebattle_web/plugs/token_auth.ex b/services/app/apps/codebattle/lib/codebattle_web/plugs/token_auth.ex deleted file mode 100644 index d75d3ae8d..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/plugs/token_auth.ex +++ /dev/null @@ -1,20 +0,0 @@ -defmodule CodebattleWeb.Plugs.TokenAuth do - @moduledoc false - import Phoenix.Controller - import Plug.Conn - - def init(options), do: options - - def call(conn, _) do - key = Application.get_env(:codebattle, :api_key) - - if key && key == List.first(get_req_header(conn, "x-auth-key")) do - conn - else - conn - |> put_status(:unauthorized) - |> json(%{error: "oiblz"}) - |> halt() - end - end -end diff --git a/services/app/apps/codebattle/lib/codebattle_web/router.ex b/services/app/apps/codebattle/lib/codebattle_web/router.ex deleted file mode 100644 index 922ddf24a..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/router.ex +++ /dev/null @@ -1,277 +0,0 @@ -defmodule CodebattleWeb.Router do - use CodebattleWeb, :router - use Plug.ErrorHandler - - import Phoenix.LiveDashboard.Router - - alias CodebattleWeb.Plugs.AssignCurrentUser - alias CodebattleWeb.Plugs.MaintenanceMode - alias CodebattleWeb.Plugs.RescrictAccess - - require Logger - - pipeline :admins_only do - plug(AssignCurrentUser) - plug(CodebattleWeb.Plugs.AdminOnly) - end - - pipeline :require_auth do - plug(CodebattleWeb.Plugs.RequireAuth) - end - - pipeline :require_api_auth do - plug(CodebattleWeb.Plugs.ApiRequireAuth) - end - - pipeline :browser do - plug(:accepts, ["html"]) - plug(:fetch_session) - plug(:fetch_flash) - plug(:fetch_live_flash) - plug(AssignCurrentUser) - plug(MaintenanceMode) - plug(RescrictAccess) - plug(:protect_from_forgery) - plug(:put_secure_browser_headers) - plug(PhoenixGon.Pipeline) - plug(CodebattleWeb.Plugs.AssignGon) - plug(CodebattleWeb.Plugs.Locale) - end - - pipeline :api do - plug(:accepts, ["json"]) - plug(:fetch_session) - plug(AssignCurrentUser) - plug(MaintenanceMode) - plug(RescrictAccess) - plug(:protect_from_forgery) - plug(:put_secure_browser_headers) - end - - pipeline :ext_api do - plug(:accepts, ["json"]) - plug(:put_secure_browser_headers) - end - - pipeline :empty_layout do - plug(:put_layout, {CodebattleWeb.LayoutView, :empty}) - end - - pipeline :public_api do - plug(:accepts, ["json"]) - end - - pipeline :mounted_apps do - plug(:accepts, ["html"]) - plug(:fetch_session) - plug(:put_secure_browser_headers) - end - - scope "/ext_api", CodebattleWeb.ExtApi, as: :ext_api do - pipe_through([:ext_api]) - post("/users", UserController, :create) - post("/tasks", TaskController, :create) - post("/task_packs", TaskPackController, :create) - end - - scope "/", CodebattleWeb do - get("/health", HealthController, :index) - end - - scope "/admin" do - pipe_through([:browser, :admins_only]) - live_dashboard("/dashboard", metrics: CodebattleWeb.Telemetry) - live("/users", CodebattleWeb.Live.Admin.User.IndexView, :index) - live("/users/:id", CodebattleWeb.Live.Admin.UserShowView, :show) - end - - scope "/auth", CodebattleWeb do - pipe_through(:browser) - get("/token", AuthController, :token) - post("/dev_login", DevLoginController, :create) - get("/:provider", AuthController, :request) - get("/:provider/callback", AuthController, :callback) - - # for binding - get("/:provider/bind", AuthBindController, :request) - get("/:provider/callback/bind", AuthBindController, :callback) - delete("/:provider", AuthBindController, :unbind) - end - - scope "/public_api", CodebattleWeb.Api, as: :api do - pipe_through(:public_api) - - scope "/v1", V1, as: :v1 do - get("/events/:id/leaderboard", Event.LeaderboardController, :show) - end - end - - scope "/api", CodebattleWeb.Api, as: :api do - pipe_through(:api) - - scope "/v1", V1, as: :v1 do - scope("/games") do - get("/completed", GameController, :completed) - end - - get("/:user_id/activity", ActivityController, :show) - get("/game_activity", GameActivityController, :show) - get("/playbook/:id", PlaybookController, :show) - get("/user/:id/stats", UserController, :stats) - get("/user/:id/simple_stats", UserController, :simple_stats) - get("/user/premium_requests", UserController, :premium_requests) - post("/user/:id/send_premium_request", UserController, :send_premium_request) - get("/user/current", UserController, :current) - resources("/users", UserController, only: [:index, :show, :create]) - resources("/reset_password", ResetPasswordController, only: [:create], singleton: true) - resources("/session", SessionController, only: [:create], singleton: true) - resources("/settings", SettingsController, only: [:show, :update], singleton: true) - resources("/tasks", TaskController) - post("/tasks/build", TaskController, :build) - post("/tasks/check", TaskController, :check) - get("/tasks/:name/unique", TaskController, :unique) - post("/playbooks/approve", PlaybookController, :approve) - post("/playbooks/reject", PlaybookController, :reject) - get("/events/:id/leaderboard", Event.LeaderboardController, :show) - end - - scope "/v1", V1, as: :v1 do - pipe_through(:require_api_auth) - - resources("/feedback", FeedbackController, only: [:index, :create]) - get("/:user_id/activity", ActivityController, :show) - - scope("/games") do - resources("/:game_id/user_game_reports", UserGameReportController, only: [:create]) - end - end - end - - scope "/", CodebattleWeb do - # Use the default browser stack - pipe_through(:browser) - - get("/robots.txt", RootController, :robots) - get("/sitemap.xml", RootController, :sitemap) - get("/feedback/rss.xml", RootController, :feedback) - - get("/", RootController, :index) - get("/maintenance", RootController, :maintenance) - get("/waiting", RootController, :waiting) - - resources("/session", SessionController, singleton: true, only: [:delete, :new, :create]) - get("/session/external/signup", SessionController, :external_signup) - get("/remind_password", SessionController, :remind_password) - - resources("/tournaments", TournamentController, only: [:index, :show]) - - scope "/tournaments" do - get("/:id/admin", Tournament.AdminController, :show) - get("/:id/image", Tournament.ImageController, :show, as: :tournament_image) - get("/:id/player/:player_id", Tournament.PlayerController, :show, as: :tournament_player) - end - - scope "/tournaments" do - pipe_through(:empty_layout) - get("/:id/timer", LiveViewTournamentController, :show_timer, as: :tournament_timer) - end - - resources("/clans", ClanController, only: [:index, :show]) - - resources("/events", EventController) - get("/e/:slug", PublicEventController, :show) - post("/e/:slug/stage", PublicEventController, :stage) - - resources("/users", UserController, only: [:new, :index, :show]) - get("/settings", UserController, :edit, as: :user_setting) - resources("/feedback", FeedbackController, only: [:index]) - - resources("/task_packs", TaskPackController) do - patch("/activate", TaskPackController, :activate, as: :activate) - patch("/disable", TaskPackController, :disable, as: :disable) - end - - resources("/raw_tasks", RawTaskController) - - resources("/tasks", TaskController) do - patch("/activate", TaskController, :activate, as: :activate) - patch("/disable", TaskController, :disable, as: :disable) - end - - resources("/games", GameController, only: [:show, :delete]) do - get("/image", Game.ImageController, :show, as: :image) - end - - scope "/games" do - post("/training", GameController, :create_training) - post("/:id/join", GameController, :join) - end - - # only for dev-admin liveView experiments - resources("/live_view_tournaments", LiveViewTournamentController, only: [:index, :show, :edit]) - end - - scope "/feature-flags" do - pipe_through([:mounted_apps, :admins_only]) - forward("/", FunWithFlags.UI.Router, namespace: "feature-flags") - end - - def handle_errors(conn, %{reason: %Ecto.NoResultsError{}}) do - conn = put_status(conn, :not_found) - - case Enum.find(conn.req_headers, fn {header, _} -> header == "accept" end) do - {"accept", value} -> - if String.contains?(value, "json") do - conn - |> json(%{error: "NOT_FOUND"}) - |> halt() - else - conn - |> put_resp_content_type("text/html") - |> put_view(CodebattleWeb.ErrorView) - |> render("404.html") - |> halt() - end - - _ -> - # Default to HTML for browser requests if no Accept header - conn - |> put_resp_content_type("text/html") - |> put_view(CodebattleWeb.ErrorView) - |> render("404.html") - |> halt() - end - end - - def handle_errors(conn, %{reason: %Phoenix.Router.NoRouteError{}}) do - conn = put_status(conn, :not_found) - - case Enum.find(conn.req_headers, fn {header, _} -> header == "accept" end) do - {"accept", value} -> - if String.contains?(value, "json") do - conn - |> json(%{error: "NOT_FOUND"}) - |> halt() - else - conn - |> put_resp_content_type("text/html") - |> put_view(CodebattleWeb.ErrorView) - |> render("404.html") - |> halt() - end - - _ -> - # Default to HTML for browser requests if no Accept header - conn - |> put_resp_content_type("text/html") - |> put_view(CodebattleWeb.ErrorView) - |> render("404.html") - |> halt() - end - end - - def handle_errors(conn, %{kind: _kind, reason: reason}) do - Logger.error(inspect(reason)) - send_resp(conn, conn.status, "SOMETHING_WENT_WRONG, reason: #{inspect(reason)}") - end -end diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/clan/index.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/clan/index.html.heex deleted file mode 100644 index 6cfe9b6db..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/clan/index.html.heex +++ /dev/null @@ -1,30 +0,0 @@ -
-

Clans

-
- - - - - - - - - - - <%= for clan <- @clans do %> - - - - - - - <% end %> - -
namelong_namecreatoractions
<%= clan.name %><%= clan.long_name %><%= clan.creator && clan.creator.name %> - <%= link("Show", - to: Routes.clan_path(@conn, :show, clan.id), - class: "btn btn-sm btn-primary" - ) %> -
-
-
diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/clan/show.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/clan/show.html.heex deleted file mode 100644 index 21e1952d4..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/clan/show.html.heex +++ /dev/null @@ -1,39 +0,0 @@ -
-

Clan

-
-
-
-

Clan Details

-

Name: <%= @clan.name %>

- <%= if @clan.long_name && @clan.long_name != "" do %> -

Long Name: <%= @clan.long_name %>

- <% end %> -

Creation Date: <%= NaiveDateTime.to_date(@clan.inserted_at) %>

-
-
-

Creator

-

Name: <%= @clan.creator.name %>

-
-
- -

Clan Members

-
- - - - - - - - - <%= for user <- Enum.sort_by(@clan.users, & &1.id) do %> - - - - - <% end %> - -
NameJoined Date
<%= user.name %><%= NaiveDateTime.to_date(user.inserted_at) %>
-
-
-
diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/error/404_page.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/error/404_page.html.heex deleted file mode 100644 index be4c352aa..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/error/404_page.html.heex +++ /dev/null @@ -1,2 +0,0 @@ -

404

-

<%= @msg %>

diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/event/_form.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/event/_form.html.heex deleted file mode 100644 index dd03bcf10..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/event/_form.html.heex +++ /dev/null @@ -1,99 +0,0 @@ -<%= f = form_for(@changeset, @action, class: "col-8 offset-2") %> -
-
- Slug - Slug for an Event should be unique -
- <%= text_input(f, :slug, - class: "form-control form-control-lg", - maxlength: "57", - required: false - ) %> - <%= error_tag(f, :slug) %> -
-
-
- Title -
- <%= text_input(f, :title, - class: "form-control form-control-lg", - maxlength: "157", - required: false - ) %> - <%= error_tag(f, :title) %> -
-
-
- Description -
- <%= textarea(f, :description, class: "form-control form-control-lg") %> - <%= error_tag(f, :description) %> -
-
- <%= label(f, :type) %> - <%= select(f, :type, Codebattle.Event.types(), class: "form-control form-control-lg") %> - <%= error_tag(f, :type) %> -
-
- - <%= datetime_local_input(f, :starts_at, - class: "form-control", - required: true, - value: f.params["starts_at"] || DateTime.add(DateTime.now!(@user.timezone), 5, :minute) - ) %> - <%= error_tag(f, :starts_at) %> -
-
-
- Ticker Text -
- <%= text_input(f, :ticker_text, class: "form-control form-control-lg") %> - <%= error_tag(f, :ticker_text) %> -
-
-
- Personal Tournament ID -
- <%= number_input(f, :personal_tournament_id, class: "form-control form-control-lg") %> - <%= error_tag(f, :personal_tournament_id) %> -
- -
-

Event Stages

-
-
- Stages (JSON format) -
- <%= textarea(f, :stages_json, - class: "form-control form-control-lg", - value: Jason.encode_to_iodata!(@changeset.data.stages || [], pretty: true), - rows: 15 - ) %> - <%= error_tag(f, :stages_json) %> -
-

Edit stages in JSON format. Each stage should include:

-
    -
  • slug: Unique identifier for the stage
  • -
  • name: Display name
  • -
  • - status: One of pending, passed, - active -
  • -
  • type: One of tournament, entrance
  • -
  • playing_type: One of single, global
  • -
  • - Optional: action_button_text, confirmation_text, dates, - tournament_id -
  • -
-
-
-
- -
- <%= submit("Save", - phx_disable_with: "Saving...", - class: "btn btn-success text-white mb-2 rounded-lg" - ) %> - <%= link("Back", to: Routes.event_path(@conn, :index), class: "btn btn-link ml-auto") %> -
diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/event/edit.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/event/edit.html.heex deleted file mode 100644 index f2587200e..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/event/edit.html.heex +++ /dev/null @@ -1,4 +0,0 @@ -
-

Edit Event

- <%= render("_form.html", Map.put(assigns, :action, Routes.event_path(@conn, :update, @event))) %> -
diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/event/index.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/event/index.html.heex deleted file mode 100644 index 6d0c7226a..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/event/index.html.heex +++ /dev/null @@ -1,55 +0,0 @@ -
-

Events

- <%= link("Create new event", - to: Routes.event_path(@conn, :new), - class: "btn btn-success text-white mt-2 rounded-lg" - ) %> -
- - - - - - - - - - - - <%= for event <- @events do %> - - - - - - - - - <% end %> - -
slugtypetitlestarts_atdescription
<%= event.slug %><%= event.type %><%= event.title %><%= format_datetime(event.starts_at) %> - <%= event.description && String.slice(event.description, 1..10) %> - -
- <%= link("Preview", - to: "/e/#{event.slug}", - class: "btn btn-sm btn-info rounded-lg" - ) %> - <%= link("Show", - to: Routes.event_path(@conn, :show, event.id), - class: "btn btn-sm btn-info rounded-lg" - ) %> - <%= link("Edit", - to: Routes.event_path(@conn, :edit, event.id), - class: "btn btn-sm btn-primary rounded-lg ml-2" - ) %> - <%= link("Delete", - to: Routes.event_path(@conn, :delete, event.id), - method: :delete, - data: [confirm: "Are you sure you want to delete this event?"], - class: "btn btn-sm btn-danger rounded-lg ml-2" - ) %> -
-
-
-
diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/event/new.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/event/new.html.heex deleted file mode 100644 index 13b2cc434..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/event/new.html.heex +++ /dev/null @@ -1,4 +0,0 @@ -
-

Create Event

- <%= render("_form.html", Map.put(assigns, :action, Routes.event_path(@conn, :create))) %> -
diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/event/show.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/event/show.html.heex deleted file mode 100644 index 949e29d1f..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/event/show.html.heex +++ /dev/null @@ -1,107 +0,0 @@ -
-

- <%= @event.title %> -

- -

Event Details

-
-
-
-
-

Slug: <%= @event.slug %>

-

Type: <%= @event.type %>

-

Title: <%= @event.title %>

-

Ticker Text: <%= @event.ticker_text %>

-
-
-

Created By: <%= @event.creator_id %>

-

- Starts At: <%= @event.starts_at && format_datetime(@event.starts_at) %> -

-

Personal Tournament ID: <%= @event.personal_tournament_id %>

-
-
-
-
-

Description:

-
- <%= @event.description %> -
-
-
-
-
- -

Event Stages

-
-
- <%= if @event.stages && length(@event.stages) > 0 do %> -
- - - - - - - - - - - - - - - - <%= for stage <- @event.stages do %> - - - - - - - - - - - - <% end %> - -
NameSlugDatesStatusTypePlaying TypeButton TextConfirmation TextTournament ID
<%= stage.name %><%= stage.slug %><%= stage.dates %> - "badge-warning" - :active -> "badge-success" - :passed -> "badge-secondary" - _ -> "badge-light" - end}"}> - <%= stage.status %> - - - - <%= stage.type %> - - - - <%= stage.playing_type %> - - <%= stage.action_button_text %> - <%= if stage.confirmation_text && String.length(stage.confirmation_text) > 200 do %> - <%= String.slice(stage.confirmation_text, 0, 200) %> - ... - <% else %> - <%= stage.confirmation_text %> - <% end %> - <%= stage.tournament_id %>
-
- <% else %> -
- No stages configured for this event yet. Event stages will be automatically configured when needed. -
- <% end %> -
-
- -
- <%= link("Edit", to: Routes.event_path(@conn, :edit, @event), class: "btn btn-primary") %> - <%= link("Back", to: Routes.event_path(@conn, :index), class: "btn btn-link ml-auto") %> -
-
diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/game/game_over.html.slim b/services/app/apps/codebattle/lib/codebattle_web/templates/game/game_over.html.slim deleted file mode 100644 index 1af8ca73a..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/game/game_over.html.slim +++ /dev/null @@ -1,4 +0,0 @@ -.container-fluid - .container.bg-white.shadow-sm.py-4.mb-3 - h3.text-center.mb-4 = gettext "Game over" - p.lead = "The winner is #{user_name(get_winner(assigns[:fsm]))}" diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/game/game_result.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/game/game_result.html.heex deleted file mode 100644 index 7ed3f830b..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/game/game_result.html.heex +++ /dev/null @@ -1,6 +0,0 @@ -
-

<%= gettext("Game status") %>

-

<%= "State: #{@game.state}" %>

-

<%= "Result: #{result(@game)}" %>

-

<%= "Date: #{@game.updated_at}" %>

-
diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/game/join.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/game/join.html.heex deleted file mode 100644 index c0a4fc411..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/game/join.html.heex +++ /dev/null @@ -1,14 +0,0 @@ -
-

<%= gettext("Join the game") %>

-

- <%= "Player #{player_name(get_first_player(@game))} is waiting for an opponent" %> -

- -
diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/game/show.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/game/show.html.heex deleted file mode 100644 index d72d93e62..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/game/show.html.heex +++ /dev/null @@ -1,15 +0,0 @@ -<%= if load_jitsi?(@user, get_first_player(@game), get_second_player(@game)) do %> - -<% end %> - -
-
- <%= if Application.get_env(:codebattle, :html_debug_mode) do %> - - <% end %> -
- - diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/game/solo_show.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/game/solo_show.html.heex deleted file mode 100644 index bec211d09..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/game/solo_show.html.heex +++ /dev/null @@ -1,8 +0,0 @@ -
-<%= if Application.get_env(:codebattle, :html_debug_mode) do %> - -<% end %> - - diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/game/stairway.html.slim b/services/app/apps/codebattle/lib/codebattle_web/templates/game/stairway.html.slim deleted file mode 100644 index 6717f29b8..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/game/stairway.html.slim +++ /dev/null @@ -1,5 +0,0 @@ -/ TODO(add-stairways): remove template after frontend template is done -#stairway-game -#modal-root style="position: absolute; top: 0; left: 0;" -javascript: - window.csrf_token = "<%= csrf_token() %>" \ No newline at end of file diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/layout/app.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/layout/app.html.heex deleted file mode 100644 index 17ccabf79..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/layout/app.html.heex +++ /dev/null @@ -1,384 +0,0 @@ - - - - - - - - - - - - - - - - - - <%= render_tags_all(assigns[:meta_tags] || %{}) %> - - - - - <%= Application.get_env(:codebattle, :app_title) %> - - <%= if FunWithFlags.enabled?(:use_external_js) do %> - - <% end %> - - - - - - <%= if FunWithFlags.enabled?(:use_external_js) do %> - - <% end %> - -
- <%= unless FunWithFlags.enabled?(:hide_header) do %> -
-
- -
-
- <% end %> -
-
- <%= for {type, message} <- @flash || [] do %> - - <% end %> -
-
- <%= unless FunWithFlags.enabled?(:hide_extension_popup) do %> -
- <% end %> - <%= if @ticker_text do %> -
- <%= @ticker_text %> - <%= @ticker_text %> -
- <% end %> -
-
- <%= @inner_content %> -
-
- <%= unless FunWithFlags.enabled?(:hide_footer) do %> - - <% end %> -
-
- <%= render_gon_script(@conn) %> - - diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/layout/empty.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/layout/empty.html.heex deleted file mode 100644 index 35176848c..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/layout/empty.html.heex +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - - - - - - - - - - <%= render_tags_all(assigns[:meta_tags] || %{}) %> - - <%= Application.get_env(:codebattle, :app_title) %> - - - - - - <%= @inner_content %> - <%= render_gon_script(@conn) %> - - diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/layout/external.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/layout/external.html.heex deleted file mode 100644 index 0e3a85f88..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/layout/external.html.heex +++ /dev/null @@ -1,179 +0,0 @@ - - - - - - - - - - - - - - - - - - - - <%= render_tags_all(assigns[:meta_tags] || %{}) %> - - <%= Application.get_env(:codebattle, :app_title) %> - - - - - - -
- <%= if assigns[:show_header] do %> -
- -
- <% end %> - <%= if @ticker_text do %> -
-
- <%= for _ <- 1..20 do %> - <%= @ticker_text %> - <% end %> -
-
- <% end %> - - <%= @inner_content %> -
- - <%= render_gon_script(@conn) %> - - diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/layout/landing.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/layout/landing.html.heex deleted file mode 100644 index 520f9b8bd..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/layout/landing.html.heex +++ /dev/null @@ -1,79 +0,0 @@ - - - - - - - - - - - - - - - - - - - - <%= render_tags_all(assigns[:meta_tags] || %{}) %> - - - - <%= Application.get_env(:codebattle, :app_title) %> - - - - <%= if FunWithFlags.enabled?(:use_external_js) do %> - - <% end %> - - - - <%= if FunWithFlags.enabled?(:use_external_js) do %> - - <% end %> - <%= @inner_content %> - - diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/public_event/show.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/public_event/show.html.heex deleted file mode 100644 index 9924a01f9..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/public_event/show.html.heex +++ /dev/null @@ -1,6 +0,0 @@ -
-
-
- diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/raw_task/_form.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/raw_task/_form.html.heex deleted file mode 100644 index c372fb3d5..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/raw_task/_form.html.heex +++ /dev/null @@ -1,132 +0,0 @@ -<%= f = form_for(@changeset, @action, class: ~c"col-8 offset-2") %> -
- <%= render_base_errors(@changeset.errors[:base]) %> -
-
- Name - Name for task, should be unique - <%= text_input(f, :name, - class: "form-control form-control-lg", - maxlength: "37", - required: false - ) %> - <%= error_tag(f, :name) %> -
-
- <%= label(f, :level) %> - <%= select(f, :level, Codebattle.Task.levels(), class: "form-control form-control-lg") %> - <%= error_tag(f, :level) %> -
-
- <%= label(f, :visibility) %> - <%= select(f, :visibility, Codebattle.Task.visibility_types(), - class: "form-control form-control-lg" - ) %> - <%= error_tag(f, :visibility) %> -
-
-
- Tags(what's your task about), you can create your own. - - Existing_tags: <%= Codebattle.Task.list_all_tags() |> Enum.join(", ") %> - - Example: math,regex,asdf -
- <%= text_input(f, :tags, value: render_tags(f.data), class: "form-control - form-control-lg", maxlength: "37", required: false) %> - <%= error_tag( - f, - :tags - ) %> -
-
-
- Examples in markdown (some examples of using solution function) - Example: 2 == solution(1,1) -
- <%= textarea(f, :examples, class: "form-control form-control-lg", required: false) %> - <%= error_tag(f, :examples) %> -
-
- <%= label(f, :description_en) %> - <%= textarea(f, :description_en, - class: "form-control form-control-lg", - required: false - ) %> - <%= error_tag( - f, - :description_en - ) %> -
-
- <%= label(f, :description_ru) %> - <%= textarea(f, :description_ru, - class: "form-control form-control-lg", - required: false - ) %> - <%= error_tag( - f, - :description_ru - ) %> -
-
-
- Asserts JSON list of objects - Example: - [{"arguments":[1,1],"expected":2}, - {"arguments":[3,7],"expected":10}] -
- <%= textarea(f, :asserts, - value: Jason.encode!(@changeset.data.asserts), - class: "form-control form-control-lg", - required: false - ) %> - <%= error_tag( - f, - :asserts - ) %> -
- -
-
- - Input_signature (json with function type signature)  - - See: example - - - Example: - - [{"argument_name":"a","type":{"name":"integer"}},{"argument_name":"b","type":{"name":"integer"}}] - -
- <%= textarea(f, :input_signature, - value: Jason.encode!(@changeset.data.input_signature), - class: "form-control - form-control-lg" - ) %> <%= error_tag(f, :input_signature) %> -
- -
-
- - Output_signature (json with output type)  - - See: url - - - Example: - {"type":{"name":"integer"}} -
- - <%= textarea(f, :output_signature, - value: Jason.encode!(@changeset.data.output_signature), - class: "form-control - form-control-lg" - ) %> <%= error_tag(f, :output_signature) %> -
- -
- <%= submit("Save", phx_disable_with: "Saving...", class: "btn btn-success mb-2") %> - <%= link("Back", to: Routes.task_path(@conn, :index), class: "ml-auto back-link") %> -
diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/raw_task/edit.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/raw_task/edit.html.heex deleted file mode 100644 index c885d0417..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/raw_task/edit.html.heex +++ /dev/null @@ -1,4 +0,0 @@ -
-

Edit task

- <%= render("_form.html", Map.put(assigns, :action, Routes.raw_task_path(@conn, :update, @task))) %> -
diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/raw_task/show.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/raw_task/show.html.heex deleted file mode 100644 index 543851ff5..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/raw_task/show.html.heex +++ /dev/null @@ -1,81 +0,0 @@ -
-

- <%= @task.name %> -

-

Params

-
- <%= if @task.origin == "github" do %> - - <%= "Origin: #{@task.origin}" %> - - <% else %> - Origin: <%= @task.origin %> - <% end %> - Visibility: <%= @task.visibility %> - State: <%= @task.state %> - <%= if @task.creator_id do %> - - Creator: - - User - - - <% end %> - -
- Level: - {@task.level} -
-
-

Tags

-
- <%= render_tags(@task) %> -
-

Description

-
- <%= raw(render_markdown(@task.description_en)) %> - <%= raw(render_markdown(@task.description_ru)) %> -
-

Examples

-
- <%= raw(render_markdown(@task.examples)) %> -
-

Input Signature

-
<%= Jason.encode!(@task.input_signature) %>
-

Ouptut Signature

-
<%= Jason.encode!(@task.output_signature) %>
- - <%= if Codebattle.Task.can_access_task?(@task, @current_user) do %> -

Asserts

-

<%= render_asserts(@task) %>

- <% end %> - -
- <%= if Codebattle.Task.can_access_task?(@task, @current_user) do %> - <%= link("Edit", - to: Routes.raw_task_path(@conn, :edit, @task), - class: "btn btn-success mt-2" - ) %> - <% end %> - <%= if Codebattle.Task.can_delete_task?(@task, @current_user) do %> - <%= link("Delete", - to: Routes.task_path(@conn, :delete, @task), - class: "btn btn-danger mt-2", - method: :delete, - data: [confirm: "Delete task?"] - ) %> - <% end %> - <%= link("Back", to: Routes.task_path(@conn, :index), class: "ml-auto") %> -
-
diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/root/_contributors_codebattle.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/root/_contributors_codebattle.html.heex deleted file mode 100644 index 3a87a8f0c..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/root/_contributors_codebattle.html.heex +++ /dev/null @@ -1,891 +0,0 @@ - -
- vtm9 -
-
- -
- ReDBrother -
-
- -
- imamatory -
-
- -
- solar05 -
-
- -
- lazycoder9 -
-
- -
- PeresvetS -
-
- -
- Guryanov-Maksim -
-
- -
- krivtsov -
-
- -
- VladimirAfanasievFS -
-
- -
- mimikria96 -
-
- -
- igor-i -
-
- -
- Abbath -
-
- -
- ushachev -
-
- -
- possesion -
-
- -
- v1valasvegan -
-
- -
- nunsez -
-
- -
- PlugIN73 -
-
- -
- skhrv -
-
- -
- thepry -
-
- -
- voitd -
-
- -
- zipofar -
-
- -
- MityaDementiy -
-
- -
- jougene -
-
- -
- disheg -
-
- -
- rexemtoxa -
-
- -
- valerr -
-
- -
- amshkv -
-
- -
- greybutton -
-
- -
- vicimpa -
-
- -
- Yoffic -
-
- -
- ayshvab -
-
- -
- enmalafeev -
-
- -
- kjubybot -
-
- -
- Galbator1x -
-
- -
- Hubble999 -
-
- -
- 21aLeX -
-
- -
- aenglisc -
-
- -
- x0xl0ma -
-
- -
- CryFromTheHeart -
-
- -
- emp7yhead -
-
- -
- RomaSub -
-
- -
- jurassic-period -
-
- -
- seth2810 -
-
- -
- ilyar -
-
- -
- grozwalker -
-
- -
- glebmanov -
-
- -
- deadit -
-
- -
- IoannP -
-
- -
- malikin -
-
- -
- yanushok -
-
- -
- denikeev -
-
- -
- CalledByThe4ire -
-
- -
- mettled -
-
- -
- romanoffivan -
-
- -
- eldarik -
-
- -
- fey -
-
- -
- morphizm -
-
- -
- YuriySho -
-
- -
- twogog -
-
- -
- glagius -
-
- -
- aarefiev -
-
- -
- Surtt -
-
- -
- philatm -
-
- -
- egorsmth -
-
- -
- kaldown -
-
- -
- mjh-sakh -
-
- -
- Pyplee -
-
- -
- mmolostvova -
-
- -
- letzabelin -
-
- -
- rizhik356 -
-
- -
- GordienkoEvgeny -
-
- -
- ivanlemeshev -
-
- -
- AnastasiaKv -
-
- -
- mokevnin -
-
- -
- patapiks -
-
- -
- Aallyycoop -
-
- -
- valeriySeregin -
-
- -
- natalialukashova -
-
- -
- MONDAYMIND -
-
- -
- SmartRW -
-
- -
- GusinieIstorii -
-
- -
- irastypain -
-
- -
- puku -
-
- -
- ilya-shakirov -
-
- -
- imleykin -
-
- -
- GPopov9 -
-
- -
- devality -
-
- -
- rustamgasanov -
-
- -
- richpeach-bot -
-
- -
- po1inakoroleva -
-
- -
- tysky -
-
- -
- avshukan -
-
- -
- irkinwork -
-
- -
- viktorkasap -
-
- -
- v-kolesnikov -
-
- -
- vadimfilimonov -
-
- -
- staskjs -
-
- -
- sonchig271 -
-
- -
- kanigreg -
-
diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/root/index.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/root/index.html.heex deleted file mode 100644 index 7e8a731ab..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/root/index.html.heex +++ /dev/null @@ -1,4 +0,0 @@ -
- diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/root/landing.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/root/landing.html.heex deleted file mode 100644 index 3fc7f2717..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/root/landing.html.heex +++ /dev/null @@ -1,392 +0,0 @@ -

Codebattle

-
-
- - -
-
-
-

Have fun and improve your skills

-

Beat the challenge faster than your opponent using your ❤ language

-
-
-

A place where your fingers become arms

-
-
-
- - No registration required -
-
-
-
-
- -
-
-
-
-

- {{Description}} -

-
-

- It's a game for developers. It's very simple: solve the coding challenge faster than your opponent using your ❤ language. -

-

- We help beginner and experienced developers spend time with fun, gain new knowledge and grow professionally. -

-

- You can battle in single player mode with bots or against your friends. -

-

- Participate in monthly individual or team tournaments with prizes or create your own to find the best developer in your team. -

-
-
-
-

- {{Languages}} -

-
- python - php - java - cpp - ruby - haskell - kotlin - javascript - go - elixir - csharp - clojure - typescript - dart - rust - swift -
-
-
-
-
-
-
-
-
-
-

- 256 -

- Task.all.count() -
-
-
-
-

- >5400 -

- User.all.count() -
-
-
-
-

- >56_000 -

- Game.all.count() -
-
-
-
-
-

{{USER::TYPES}}

-
-
-
-
- beginner -

For beginners who want to pump their skills

-
-
- experienced -

For experienced who want to break records

-
-
- friend -

For friends who want to battle each other

-
-
- enthusiast -

For those who are in love with programming

-
-
-
-
-
-
-
-
-

{{Algorithm}}

-
-
- algorithm -
-
-
-
-

{{Comments}}

-
-
-
- Journalist -
-

Journalist

-

Middle frontend engineer

-
-
-
- comment -
-
-
-
-
-

Rosa Robot

-

UI/UX Senior

-
- rosa -
-
- comment -
-
-
-
- comment -
-
- SHERSHNYAGA -
-

SHERSHNYAGA

-

Senior frontend dev

-
-
-
-
-
- comment -
-
-
-

Engineer

-

Beginner

-
- Engineer -
-
-
-
-
-
-
-

{{Contributors}}

-
- - -
- <%= render("_contributors_codebattle.html") %> -
-
- #elixir - #phoenix - #live_view - #es6 - #react - #redux - #bootstrap - #k8s - #docker -
-
- -
- -
- <%= render("_contributors_asserts.html") %> -
-
- #clojure -
-
- -
- -
- <%= render("_contributors_extension.html") %> -
- #es6 - #react -
-
-
- -
-
-
-
-
-
-

- What now? -

-

- Start to code on your ❤ language -

-
- -
-
-
-
-
-
-
- diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/session/external_oauth.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/session/external_oauth.html.heex deleted file mode 100644 index c0f7ff43d..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/session/external_oauth.html.heex +++ /dev/null @@ -1,27 +0,0 @@ -
-
-
-
-
- <%= Application.get_env(:codebattle, :external)[:app_name] %> -
- -

- <%= raw(Application.get_env(:codebattle, :external)[:app_slogan]) %> -

- - - - -
-
- -<%= if body = Codebattle.Customization.get("external_oauth_body") do %> -
- <%= raw(body) %> -
-<% end %> diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/session/external_signup.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/session/external_signup.html.heex deleted file mode 100644 index ecf7dfd03..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/session/external_signup.html.heex +++ /dev/null @@ -1,25 +0,0 @@ -
-
-
-
-
- <%= Application.get_env(:codebattle, :external)[:app_name] %> -
- -

- <%= raw(Application.get_env(:codebattle, :external)[:app_slogan]) %> -

- - - - <%= link to: Application.get_env(:codebattle, :free_users_redirect_url), class: "btn btn-yellow mb-4" do %> - <%= Application.get_env(:codebattle, :external)[:app_signup_button] %> - <% end %> - - <%= link to: Routes.session_path(@conn, :delete), method: "delete", class: "btn btn-gray" do %> - <%= Application.get_env(:codebattle, :external)[:app_relogin_button] %> - <% end %> -
-
diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/session/index.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/session/index.html.heex deleted file mode 100644 index b4a6a6369..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/session/index.html.heex +++ /dev/null @@ -1,4 +0,0 @@ -
- diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/session/local_password.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/session/local_password.html.heex deleted file mode 100644 index bbebecdcb..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/session/local_password.html.heex +++ /dev/null @@ -1,44 +0,0 @@ -
-
- <%= if header = Codebattle.Customization.get("login_header") do %> -
- <%= raw(header) %> -
- <% end %> - - <%= if body = Codebattle.Customization.get("login_body") do %> -
- <%= raw(body) %> -
- <% end %> -
-
- -
- -
- <%= form_for @conn, Routes.session_path(@conn, :create), [as: :session], fn f -> %> -
- <%= label(f, :name, gettext("Name"), class: "form-label") %> - <%= text_input(f, :name, class: "form-control", placeholder: gettext("Enter your name")) %> -
-
- <%= label(f, :password, gettext("Password"), class: "form-label") %> - <%= password_input(f, :password, - class: "form-control", - placeholder: gettext("Enter your password") - ) %> -
-
- <%= submit(gettext("Log in"), class: "btn btn-primary w-100") %> -
- <% end %> -
-
diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/task/index.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/task/index.html.heex deleted file mode 100644 index 896a2bd25..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/task/index.html.heex +++ /dev/null @@ -1,76 +0,0 @@ -
-

Tasks

- <%= link("Create new task", - to: CodebattleWeb.Router.Helpers.task_path(@conn, :new), - class: "btn btn-success text-white mt-2 rounded-lg" - ) %> - <%= link("Task packs", - to: CodebattleWeb.Router.Helpers.task_pack_path(@conn, :index), - class: "btn btn-info mt-2 ml-2 rounded-lg" - ) %> -
- - - - - - - - - - - - - - - - <%= for task <- @tasks do %> - - - - - - - - - - - - <% end %> - -
idnameleveltagsoriginstatevisibilityupdated_atactions
<%= task.id %><%= task.name %> - {task.level} - <%= Enum.join(task.tags, ", ") %><%= task.origin %><%= task.state %><%= task.visibility %><%= format_datetime(task.updated_at) %> -
- <%= if !Codebattle.User.admin?(@current_user) do %> - <%= link("Show", - to: CodebattleWeb.Router.Helpers.task_path(@conn, :show, task.id), - class: "btn btn-sm btn-info rounded-lg" - ) %> - <% end %> - <%= if Codebattle.User.admin?(@current_user) do %> - <%= link("Show", - to: CodebattleWeb.Router.Helpers.task_path(@conn, :show, task.id), - class: "btn btn-sm btn-info rounded-left" - ) %> - <%= button("Activate", - to: - CodebattleWeb.Router.Helpers.task_activate_path(@conn, :activate, task.id), - method: "patch", - class: "btn btn-sm btn-success text-white" - ) %> - <%= button("Disable", - to: CodebattleWeb.Router.Helpers.task_disable_path(@conn, :disable, task.id), - method: "patch", - class: "btn btn-sm btn-danger rounded-right" - ) %> - <%= button("Delete", - to: CodebattleWeb.Router.Helpers.task_path(@conn, :delete, task.id), - method: "delete", - class: "btn btn-sm btn-danger rounded-right" - ) %> - <% end %> -
-
-
-
diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/task/new.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/task/new.html.heex deleted file mode 100644 index 6c29805ee..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/task/new.html.heex +++ /dev/null @@ -1,10 +0,0 @@ -
-
- <%= if Application.get_env(:codebattle, :html_debug_mode) do %> - - <% end %> -
- - diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/task_pack/_form.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/task_pack/_form.html.heex deleted file mode 100644 index 40f07fbc9..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/task_pack/_form.html.heex +++ /dev/null @@ -1,44 +0,0 @@ -<%= f = form_for(@changeset, @action, class: ~c"col-8 offset-2") %> -
- <%= render_base_errors(@changeset.errors[:base]) %> -
-
-
- Name - Name for task pack, should be unique -
- <%= text_input(f, :name, - class: "form-control form-control-lg", - maxlength: "37", - required: false - ) %> - <%= error_tag(f, :name) %> -
-
- <%= label(f, :visibility) %> - <%= select(f, :visibility, Codebattle.TaskPack.visibility_types(), - class: "form-control form-control-lg" - ) %> - <%= error_tag(f, :visibility) %> -
-
-
- Task_ids -
-
- Example: 1,37,42 -
- <%= text_input(f, :task_ids, - value: render_task_ids(f.data), - class: "form-control form-control-lg", - required: true - ) %> - <%= error_tag(f, :task_ids) %> -
-
- <%= submit("Save", - phx_disable_with: "Saving...", - class: "btn btn-success text-white mb-2 rounded-lg" - ) %> - <%= link("Back", to: Routes.task_pack_path(@conn, :index), class: "btn btn-link ml-auto") %> -
diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/task_pack/edit.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/task_pack/edit.html.heex deleted file mode 100644 index f6183cccc..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/task_pack/edit.html.heex +++ /dev/null @@ -1,7 +0,0 @@ -
-

Edit task pack

- <%= render( - "_form.html", - Map.put(assigns, :action, Routes.task_pack_path(@conn, :update, @task_pack)) - ) %> -
diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/task_pack/index.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/task_pack/index.html.heex deleted file mode 100644 index 4c539a7bf..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/task_pack/index.html.heex +++ /dev/null @@ -1,70 +0,0 @@ -
-

Task Packs

- <%= link("Create new task pack", - to: CodebattleWeb.Router.Helpers.task_pack_path(@conn, :new), - class: "btn btn-success mt-2 text-white rounded-lg" - ) %> - <%= link("Tasks", - to: CodebattleWeb.Router.Helpers.task_path(@conn, :index), - class: "btn btn-info mt-2 ml-2 rounded-lg" - ) %> -
- - - - - - - - - - - - <%= for task_pack <- @task_packs do %> - - - - - - - - <% end %> - -
namestatevisibilitytask_idsactions
<%= task_pack.name %><%= task_pack.state %><%= task_pack.visibility %><%= render_task_ids(task_pack) %> -
- <%= if !Codebattle.User.admin?(@current_user) do %> - <%= link("Show", - to: CodebattleWeb.Router.Helpers.task_pack_path(@conn, :show, task_pack.id), - class: "btn btn-sm btn-info rounded-lg" - ) %> - <% end %> - <%= if Codebattle.User.admin?(@current_user) do %> - <%= link("Show", - to: CodebattleWeb.Router.Helpers.task_pack_path(@conn, :show, task_pack.id), - class: "btn btn-sm btn-info rounded-left" - ) %> - <%= button("Activate", - to: - CodebattleWeb.Router.Helpers.task_pack_activate_path( - @conn, - :activate, - task_pack.id - ), - method: "patch", - class: "btn btn-sm btn-success text-white" - ) %> - <%= button("Disable", - to: - CodebattleWeb.Router.Helpers.task_pack_disable_path( - @conn, - :disable, - task_pack.id - ), - method: "patch", - class: "btn btn-sm btn-danger rounded-right" - ) %> - <% end %> -
-
-
-
diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/task_pack/new.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/task_pack/new.html.heex deleted file mode 100644 index 17997d0ad..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/task_pack/new.html.heex +++ /dev/null @@ -1,5 +0,0 @@ -
-

Create your own task pack

-

Use it for tournaments to play with tasks that you really want

- <%= render("_form.html", Map.put(assigns, :action, Routes.task_pack_path(@conn, :create))) %> -
diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/task_pack/show.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/task_pack/show.html.heex deleted file mode 100644 index 4bf71fc2e..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/task_pack/show.html.heex +++ /dev/null @@ -1,75 +0,0 @@ -
-

- <%= @task_pack.name %> -

-

Params

-
- Visibility: <%= @task_pack.visibility %> - State: <%= @task_pack.state %> - <%= if @task_pack.creator_id do %> - Creator_id: <%= @task_pack.creator_id %> - <% end %> -
- -

Tasks

-
- - - - - - - - - - - - - - - - <%= for {task_id, index} <- Enum.with_index(@task_pack.task_ids) do %> - <%= if task = Enum.find(@tasks, fn task -> task.id == task_id end) do %> - - - - - - - - - - - - <% else %> - Task not found for id = <%= task_id %> - <% end %> - <% end %> - -
indexidnameleveltagsoriginstatetimevisibility
<%= index %><%= task.id %> - <%= link(task.name, - to: Routes.raw_task_path(@conn, :show, task.id), - class: "ml-auto" - ) %> - <%= task.level %><%= Enum.join(task.tags, ", ") %><%= task.origin %><%= task.state %><%= task.time_to_solve_sec %><%= task.visibility %>
-
-
- <%= if Codebattle.TaskPack.can_access_task_pack?(@task_pack, @current_user) do %> - <%= link("Edit", - to: Routes.task_pack_path(@conn, :edit, @task_pack), - class: "btn btn-success mt-2" - ) %> - <% end %> - - <%= if Codebattle.TaskPack.can_access_task_pack?(@task_pack, @current_user) do %> - <%= link("Delete", - to: Routes.task_pack_path(@conn, :delete, @task_pack), - class: "btn btn-danger mt-2", - method: :delete, - data: [confirm: "Delete task pack?"] - ) %> - <% end %> - - <%= link("Back", to: Routes.task_pack_path(@conn, :index), class: "ml-auto") %> -
-
diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/tournament/admin.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/tournament/admin.html.heex deleted file mode 100644 index e7d4940ea..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/tournament/admin.html.heex +++ /dev/null @@ -1,4 +0,0 @@ -
- diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/tournament/show.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/tournament/show.html.heex deleted file mode 100644 index e7f9eacc7..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/tournament/show.html.heex +++ /dev/null @@ -1,4 +0,0 @@ -
- diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/user/index.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/user/index.html.heex deleted file mode 100644 index 21fa08fef..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/user/index.html.heex +++ /dev/null @@ -1,3 +0,0 @@ -
-
-
diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/user/show.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/user/show.html.heex deleted file mode 100644 index e67561f5d..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/user/show.html.heex +++ /dev/null @@ -1,3 +0,0 @@ -
-
-
diff --git a/services/app/apps/codebattle/lib/codebattle_web/views/api/game_view.ex b/services/app/apps/codebattle/lib/codebattle_web/views/api/game_view.ex deleted file mode 100644 index 7264fc10a..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/views/api/game_view.ex +++ /dev/null @@ -1,92 +0,0 @@ -defmodule CodebattleWeb.Api.GameView do - use CodebattleWeb, :view - - import Codebattle.Game.Helpers - - alias Codebattle.CodeCheck - alias Runner.Languages - - def render_game(game, score) do - %{ - id: get_game_id(game), - inserted_at: Map.get(game, :inserted_at), - award: game.award, - langs: get_langs_with_templates(game.task), - level: game.level, - locked: game.locked, - mode: game.mode, - players: game.players, - rematch_initiator_id: Map.get(game, :rematch_initiator_id), - rematch_state: Map.get(game, :rematch_state, "none"), - score: score, - starts_at: Map.get(game, :starts_at), - state: game.state, - status: game.state, - task: game.task, - timeout_seconds: game.timeout_seconds, - tournament_id: Map.get(game, :tournament_id), - type: game.type, - waiting_room_name: game.waiting_room_name, - use_chat: game.use_chat, - use_timer: game.use_timer, - visibility_type: game.visibility_type - } - end - - def render_completed_games(games) do - Enum.map(games, &render_completed_game/1) - end - - def render_completed_game(game) do - %{ - id: game.id, - players: render_players(game), - finishes_at: game.finishes_at, - duration: game.duration_sec || game.timeout_seconds, - level: game.level - } - end - - # defp get_duration(%{starts_at: nil}), do: 100 - # defp get_duration(%{finishes_at: nil}), do: 100 - - # defp get_duration(%{starts_at: starts_at, finishes_at: finishes_at}) do - # NaiveDateTime.diff(finishes_at, starts_at) - # end - - defp render_players(game) do - game - |> Map.get(:players, []) - |> Enum.sort(&(&1.creator > &2.creator)) - |> Enum.map(fn player -> - player - |> Map.take([ - :id, - :is_bot, - :is_guest, - :name, - :rank, - :rating, - :rating_diff, - :result, - :creator - ]) - |> Map.put(:lang, player.editor_lang) - end) - end - - def get_langs_with_templates(task) do - Languages.meta() - |> Map.take(Languages.get_lang_slugs()) - |> Map.values() - |> Enum.map(fn meta -> - %{ - slug: meta.slug, - name: meta.name, - version: meta.version, - solution_template: CodeCheck.generate_solution_template(task, meta), - arguments_generator_template: Map.get(meta, :arguments_generator_template, "") - } - end) - end -end diff --git a/services/app/apps/codebattle/lib/codebattle_web/views/api/lobby_view.ex b/services/app/apps/codebattle/lib/codebattle_web/views/api/lobby_view.ex deleted file mode 100644 index a80bffc6a..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/views/api/lobby_view.ex +++ /dev/null @@ -1,35 +0,0 @@ -defmodule CodebattleWeb.Api.LobbyView do - use CodebattleWeb, :view - - alias Codebattle.Game - alias Codebattle.Tournament - alias CodebattleWeb.Api.GameView - - def render_lobby_params(current_user) do - tournaments = Tournament.Context.list_live_and_finished(current_user) - - %{games: games} = - Game.Context.get_completed_games( - %{}, - %{page_size: 20, total: false, page_number: 1} - ) - - completed_games = GameView.render_completed_games(games) - - %{ - active_games: render_active_games(current_user), - tournaments: tournaments, - completed_games: completed_games - } - end - - def render_active_games(current_user) do - %{is_tournament: false} - |> Game.Context.get_active_games() - |> Enum.filter(&can_user_see_game?(&1, current_user)) - end - - def can_user_see_game?(game, user) do - game.visibility_type == "public" || Game.Helpers.player?(game, user) - end -end diff --git a/services/app/apps/codebattle/lib/codebattle_web/views/api/task_view.ex b/services/app/apps/codebattle/lib/codebattle_web/views/api/task_view.ex deleted file mode 100644 index 0413ad495..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/views/api/task_view.ex +++ /dev/null @@ -1,18 +0,0 @@ -defmodule CodebattleWeb.Api.TaskView do - use CodebattleWeb, :view - - def render_task(task) do - %{ - id: task.id, - name: task.name, - level: task.level, - origin: task.origin, - creator_id: task.creator_id, - tags: task.tags - } - end - - def render_tasks(tasks) do - Enum.map(tasks, &render_task/1) - end -end diff --git a/services/app/apps/codebattle/lib/codebattle_web/views/clan_view.ex b/services/app/apps/codebattle/lib/codebattle_web/views/clan_view.ex deleted file mode 100644 index 1c95e071f..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/views/clan_view.ex +++ /dev/null @@ -1,3 +0,0 @@ -defmodule CodebattleWeb.ClanView do - use CodebattleWeb, :view -end diff --git a/services/app/apps/codebattle/lib/codebattle_web/views/game_view.ex b/services/app/apps/codebattle/lib/codebattle_web/views/game_view.ex deleted file mode 100644 index 783961a20..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/views/game_view.ex +++ /dev/null @@ -1,33 +0,0 @@ -defmodule CodebattleWeb.GameView do - use CodebattleWeb, :view - - import Codebattle.Game.Helpers - - def user_name(%Codebattle.User{name: name, rating: rating}) do - case {name, rating} do - {nil, nil} -> "" - _ -> "#{name}(#{rating})" - end - end - - def player_name(%Codebattle.Game.Player{name: name, rating: rating}) do - case {name, rating} do - {nil, nil} -> "" - _ -> "#{name}(#{rating})" - end - end - - def result(%Codebattle.Game{users: users, user_games: user_games}) do - Enum.map_join(users, ", ", fn u -> - "#{user_name(u)} #{Enum.find(user_games, fn ug -> ug.user_id == u.id end).result}" - end) - end - - def load_jitsi?(user, player1, player2) do - Codebattle.User.admin?(user) || player1.id == user.id || player2.id == user.id - end - - def csrf_token do - Plug.CSRFProtection.get_csrf_token() - end -end diff --git a/services/app/apps/codebattle/lib/codebattle_web/views/layout_view.ex b/services/app/apps/codebattle/lib/codebattle_web/views/layout_view.ex deleted file mode 100644 index f00e4edda..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/views/layout_view.ex +++ /dev/null @@ -1,81 +0,0 @@ -defmodule CodebattleWeb.LayoutView do - use CodebattleWeb, :view - - import CodebattleWeb.Router.Helpers - import PhoenixGon.View - - @app_version Application.compile_env(:codebattle, :app_version) - @colors [ - "2AE881", - "73CCFE", - "B6A4FF", - "FF621E", - "FF9C41", - "FFE500" - ] - - def get_next_path(conn) do - next = conn.params["next"] - - case next do - "" -> conn.request_path - nil -> conn.request_path - _ -> next - end - end - - def app_short_version do - case @app_version do - "" -> "undefined" - version -> String.slice(version, 0, 7) - end - end - - def github_commit_link do - case @app_version do - "" -> "/" - version -> "https://github.com/hexlet-codebattle/codebattle/commit/#{version}" - end - end - - def deployed_at do - Application.get_env(:codebattle, :deployed_at) - end - - def collab_logo(%{collab_logo: logo}) when not is_nil(logo), do: logo - - def collab_logo(_user) do - Application.get_env(:codebattle, :collab_logo) - end - - def collab_logo_minor(_user) do - Application.get_env(:codebattle, :collab_logo_minor) - end - - def user_rank(user) do - # if Application.get_env(:codebattle, :use_event_rank) do - # # TODO: add user rating from event - # 0 - # else - user.rank - # end - end - - def user_rating(user) do - # if Application.get_env(:codebattle, :use_event_rating) do - # # TODO: add user rating from event - # 0 - # else - user.rating - # end - end - - def avatar_url(user) do - user.avatar_url || - "https://ui-avatars.com/api/?name=#{user.name}&background=#{get_background_color(user)}&color=ffffff" - end - - defp get_background_color(user) do - Enum.at(@colors, rem(String.length(user.name), length(@colors))) - end -end diff --git a/services/app/apps/codebattle/lib/codebattle_web/views/raw_task_view.ex b/services/app/apps/codebattle/lib/codebattle_web/views/raw_task_view.ex deleted file mode 100644 index ff3c97233..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/views/raw_task_view.ex +++ /dev/null @@ -1,20 +0,0 @@ -defmodule CodebattleWeb.RawTaskView do - use CodebattleWeb, :view - - def render_base_errors(nil), do: nil - def render_base_errors(errors), do: elem(errors, 0) - - def render_tags(task), do: Enum.join(task.tags, ", ") - - def render_asserts(task) do - Jason.encode!(task.asserts) - end - - def render_markdown(nil), do: "" - def render_markdown(""), do: "" - def render_markdown(text), do: Earmark.as_html!(text, compact_output: true) - - def csrf_token do - Plug.CSRFProtection.get_csrf_token() - end -end diff --git a/services/app/apps/codebattle/lib/codebattle_web/views/root_view.ex b/services/app/apps/codebattle/lib/codebattle_web/views/root_view.ex deleted file mode 100644 index 88bcd454f..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/views/root_view.ex +++ /dev/null @@ -1,44 +0,0 @@ -defmodule CodebattleWeb.RootView do - use CodebattleWeb, :view - - import CodebattleWeb.Router.Helpers - - alias Codebattle.Feedback - - def csrf_token do - Plug.CSRFProtection.get_csrf_token() - end - - def user_name(%Codebattle.User{name: name, rating: rating}) do - case {name, rating} do - {nil, nil} -> "" - _ -> "#{name}(#{rating})" - end - end - - def feedback do - Enum.map(Feedback.get_all(), &item/1) - end - - defp item(%{title: title, description: description, pubDate: pub_date, link: link, guid: guid}) do - """ - - #{title} - - #{pub_date} - #{link} - #{guid} - - """ - end - - def get_next_path(conn) do - next = conn.params["next"] - - case next do - "" -> conn.request_path - nil -> conn.request_path - _ -> next - end - end -end diff --git a/services/app/apps/codebattle/lib/codebattle_web/views/task_pack_view.ex b/services/app/apps/codebattle/lib/codebattle_web/views/task_pack_view.ex deleted file mode 100644 index 91ebae5bb..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/views/task_pack_view.ex +++ /dev/null @@ -1,16 +0,0 @@ -defmodule CodebattleWeb.TaskPackView do - use CodebattleWeb, :view - - def render_base_errors(nil), do: nil - def render_base_errors(errors), do: elem(errors, 0) - - def render_task_ids(task), do: Enum.join(task.task_ids, ", ") - - def render_asserts(task) do - task.asserts |> String.split("\n", trim: false) |> Enum.intersperse(Phoenix.HTML.Tag.tag(:br)) - end - - def render_markdown(nil), do: "" - def render_markdown(""), do: "" - def render_markdown(text), do: Earmark.as_html!(text, compact_output: true) -end diff --git a/services/app/apps/codebattle/lib/codebattle_web/views/task_view.ex b/services/app/apps/codebattle/lib/codebattle_web/views/task_view.ex deleted file mode 100644 index c84823e5c..000000000 --- a/services/app/apps/codebattle/lib/codebattle_web/views/task_view.ex +++ /dev/null @@ -1,35 +0,0 @@ -defmodule CodebattleWeb.TaskView do - use CodebattleWeb, :view - - def render_base_errors(nil), do: nil - def render_base_errors(errors), do: elem(errors, 0) - - def render_tags(task), do: Enum.join(task.tags, ", ") - - def render_asserts(task) do - Jason.encode!(task.asserts) - end - - def render_markdown(nil), do: "" - def render_markdown(""), do: "" - def render_markdown(text), do: Earmark.as_html!(text, compact_output: true) - - def csrf_token do - Plug.CSRFProtection.get_csrf_token() - end - - def format_datetime(d, tz \\ "UTC") - def format_datetime(nil, _time_zone), do: "none" - - def format_datetime(%NaiveDateTime{} = datetime, timezone) do - datetime - |> DateTime.from_naive!("UTC") - |> format_datetime(timezone) - end - - def format_datetime(%DateTime{} = datetime, timezone) do - datetime - |> DateTime.shift_zone!(timezone) - |> Timex.format!("%Y-%m-%d %H:%M %Z", :strftime) - end -end diff --git a/services/app/apps/codebattle/lib/mix/get_contributors.ex b/services/app/apps/codebattle/lib/mix/get_contributors.ex deleted file mode 100644 index 0a04cec43..000000000 --- a/services/app/apps/codebattle/lib/mix/get_contributors.ex +++ /dev/null @@ -1,48 +0,0 @@ -defmodule Mix.Tasks.GetContributors do - @shortdoc "Get contributors for landing" - - @moduledoc false - - use Mix.Task - - @repos %{ - codebattle: ~c"https://api.github.com/repos/hexlet-codebattle/codebattle/contributors?per_page=1000", - asserts: ~c"https://api.github.com/repos/hexlet-codebattle/battle_asserts/contributors?per_page=1000", - extension: ~c"https://api.github.com/repos/hexlet-codebattle/chrome_extension/contributors?per_page=1000" - } - - def run(_) do - {:ok, _started} = Application.ensure_all_started(:req) - - Enum.each(@repos, fn {repo_name, url} -> - content = - url - |> Req.get!() - |> Map.get(:body) - |> Jason.decode!() - |> Enum.filter(fn params -> params["type"] == "User" end) - |> Enum.sort_by(fn params -> params["contributions"] end) - |> Enum.reverse() - |> Enum.map(&Map.take(&1, ["html_url", "login", "contributions", "avatar_url"])) - |> Enum.map_join("", fn params -> template(params) end) - - File.cwd!() - |> Path.join("apps/codebattle/lib/codebattle_web/templates/root/_contributors_#{repo_name}.html.heex") - |> File.write!(content) - end) - end - - defp template(params) do - """ - -
- #{params[ -
-
- """ - end -end diff --git a/services/app/apps/codebattle/lib/mix/tasks/asserts/upload.ex b/services/app/apps/codebattle/lib/mix/tasks/asserts/upload.ex deleted file mode 100644 index ca818c3eb..000000000 --- a/services/app/apps/codebattle/lib/mix/tasks/asserts/upload.ex +++ /dev/null @@ -1,12 +0,0 @@ -defmodule Mix.Tasks.Asserts.Upload do - @shortdoc "Upload asserts from battle_asserts repo" - - @moduledoc false - - use Mix.Task - - def run(_) do - {:ok, _started} = Application.ensure_all_started(:codebattle) - Codebattle.TasksImporter.run_sync() - end -end diff --git a/services/app/apps/codebattle/lib/utils.ex b/services/app/apps/codebattle/lib/utils.ex deleted file mode 100644 index 702150b74..000000000 --- a/services/app/apps/codebattle/lib/utils.ex +++ /dev/null @@ -1,62 +0,0 @@ -defmodule Utils do - @moduledoc false - def blank?(x) when is_binary(x) do - String.trim(x) == "" - end - - def blank?(x) do - x in [%{}, {}, [], nil, false] - end - - def present?(x), do: not blank?(x) - - def presence(x) do - if present?(x) do - x - end - end - - # Thx to https://github.com/reeesga/elixir-rotate-lists/blob/master/lib/list_rotation.ex - # - def left_rotate(l, n \\ 1) - def left_rotate([], _), do: [] - def left_rotate(l, 0), do: l - def left_rotate([h | t], 1), do: t ++ [h] - def left_rotate(l, n) when n > 0, do: left_rotate(left_rotate(l, 1), n - 1) - def left_rotate(l, n), do: right_rotate(l, -n) - - def right_rotate(l, n \\ 1) - - def right_rotate(l, n) when n > 0 do - l |> Enum.reverse() |> left_rotate(n) |> Enum.reverse() - end - - def right_rotate(l, n), do: left_rotate(l, -n) - - def sanitize_jsonb(json_string) when is_binary(json_string) do - json_string - |> remove_null_bytes() - |> replace_invalid_unicode_escape_sequences() - end - - def sanitize_jsonb(_), do: "" - - # Remove null bytes from JSON string - defp remove_null_bytes(json_string) do - String.replace(json_string, <<0>>, "") - end - - # Replace invalid Unicode escape sequences with placeholders - defp replace_invalid_unicode_escape_sequences(json_string) do - Regex.replace(~r/\\u([0-9A-Fa-f]{4})/, json_string, fn _, match -> - code_point = String.to_integer(match, 16) - - if code_point < 128 do - <> - else - # Replace with placeholder for invalid sequences - "?" - end - end) - end -end diff --git a/services/app/apps/codebattle/mix.exs b/services/app/apps/codebattle/mix.exs deleted file mode 100644 index 7cb199267..000000000 --- a/services/app/apps/codebattle/mix.exs +++ /dev/null @@ -1,111 +0,0 @@ -defmodule Codebattle.MixProject do - use Mix.Project - - def project do - [ - app: :codebattle, - version: "0.1.0", - build_path: "../../_build", - config_path: "../../config/config.exs", - deps_path: "../../deps", - lockfile: "../../mix.lock", - elixir: "~> 1.14", - elixirc_paths: elixirc_paths(Mix.env()), - start_permanent: Mix.env() == :prod, - aliases: aliases(), - deps: deps(), - test_coverage: [tool: ExCoveralls, threshold: 60], - elixirc_options: [warnings_as_errors: false] - ] - end - - # Configuration for the OTP application. - # - # Type `mix help compile.app` for more information. - def application do - [ - mod: {Codebattle.Application, []}, - extra_applications: [:runtime_tools, :logger, :os_mon], - included_applications: [:runner, :phoenix_gon] - ] - end - - # Specifies which paths to compile per environment. - defp elixirc_paths(:test), do: ["lib", "test/support"] - defp elixirc_paths(_), do: ["lib"] - - # Specifies your project dependencies. - # - # Type `mix help deps` for examples and options. - defp deps do - [ - {:runner, in_umbrella: true, runtime: false}, - {:phoenix_gon, in_umbrella: true}, - {:bandit, "~> 1.0"}, - {:bcrypt_elixir, "~> 2.0"}, - {:cowboy, "~> 2.8"}, - {:delta, github: "slab/delta-elixir"}, - {:diff_match_patch, github: "vtm9/diff_match_patch", override: true}, - {:earmark, "~> 1.4"}, - {:ecto_psql_extras, "~> 0.2"}, - {:ecto_sql, "~> 3.6"}, - {:envy, "~> 1.1.1"}, - {:exfake, "~> 1.0.0"}, - {:finch, "~> 0.16"}, - {:fun_with_flags, "~> 1.11"}, - {:fun_with_flags_ui, "~> 1.0"}, - {:gettext, "~> 0.18"}, - {:chromic_pdf, "~> 1.17"}, - {:jason, "~> 1.2"}, - {:nimble_csv, "~> 1.1"}, - {:phoenix, "~> 1.7"}, - {:phoenix_client, github: "vtm9/phoenix_client"}, - {:phoenix_ecto, "~> 4.4"}, - {:phoenix_html, "~> 3.2"}, - {:phoenix_live_dashboard, "~> 0.8.0"}, - {:phoenix_live_view, "~> 0.20"}, - {:phoenix_meta_tags, "~> 0.1.8"}, - {:phoenix_view, "~> 2.0"}, - {:plug, "~> 1.14"}, - {:plug_cowboy, "~> 2.7"}, - {:postgrex, ">= 0.0.0"}, - {:recon, "~> 2.5"}, - {:req, "~> 0.5.0"}, - {:sentry, "~> 10.0"}, - {:statistics, "~> 0.6"}, - {:telemetry_metrics, "~> 0.6"}, - {:telemetry_poller, "~> 1.0"}, - {:timex, "~> 3.6"}, - {:typed_struct, "~> 0.3"}, - {:yaml_elixir, "~> 2.4"}, - - # dev_and_test - {:credo, "~> 1.6", only: [:dev, :test], runtime: false}, - {:styler, "~> 1.4", only: [:dev, :test], runtime: false}, - {:mix_audit, "~> 2.1", only: [:dev, :test], runtime: false}, - # dev - {:phoenix_live_reload, "~> 1.3", only: :dev}, - - # test - {:ex_machina, "~> 2.4", only: :test}, - {:excoveralls, "~> 0.13", only: :test}, - {:floki, "~> 0.29", only: :test}, - {:mock, "~> 0.3.5", only: :test}, - {:phoenix_integration, "~> 0.8", only: :test} - ] - end - - # Aliases are shortcuts or tasks specific to the current project. - # For example, to create, migrate and run the seeds file at once: - # - # $ mix ecto.setup - # - # See the documentation for `Mix` for more info on aliases. - defp aliases do - [ - "ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"], - "ecto.reset": ["ecto.drop", "ecto.setup"], - test: ["ecto.create --quiet", "ecto.migrate", "test"] - ] - end -end diff --git a/services/app/apps/codebattle/package.json b/services/app/apps/codebattle/package.json deleted file mode 100644 index aa5b23ffc..000000000 --- a/services/app/apps/codebattle/package.json +++ /dev/null @@ -1,176 +0,0 @@ -{ - "repository": {}, - "license": "MIT", - "browserslist": [ - "> 0.25%" - ], - "scripts": { - "test": "jest", - "test-watch": "jest --watchAll", - "watch": "webpack-dev-server --config ./webpack/webpack.dev.config.js", - "profile": "webpack --config ./webpack/webpack.build.config.js --profile --json > stats.json && webpack-bundle-analyzer stats.json ./priv/static/assets/", - "profile:build": "webpack --config ./webpack/webpack.build.config.js --profile --json > stats.json", - "profile:visualize": "npx webpack-bundle-analyzer stats.json", - "build": "webpack --config ./webpack/webpack.build.config.js", - "lint": "eslint --ext js,jsx ./assets/js", - "lint-fix": "eslint --fix --ext js,jsx ./assets/js" - }, - "jest": { - "verbose": true, - "testEnvironment": "jsdom", - "transform": { - "^.+\\.(js|jsx|ts|tsx|mjs)$": "babel-jest" - }, - "moduleNameMapper": { - "^monaco-editor$": "/node_modules/@monaco-editor/react", - "^.+\\.(css|styl|less|sass|scss|po|png|jpg|ttf|woff|woff2)$": "jest-transform-stub", - "^@/components(.*)$": "/assets/js/widgets/components$1", - "^@/lib(.*)$": "/assets/js/widgets/lib$1", - "^@/machines(.*)$": "/assets/js/widgets/machines$1", - "^@/middlewares(.*)$": "/assets/js/widgets/middlewares$1", - "^@/pages(.*)$": "/assets/js/widgets/pages$1", - "^@/selectors(.*)$": "/assets/js/widgets/selectors$1", - "^@/slices(.*)$": "/assets/js/widgets/slices$1", - "^@/utils(.*)$": "/assets/js/widgets/utils$1", - "^axios$": "/node_modules/axios/dist/node/axios.cjs" - }, - "testPathIgnorePatterns": [ - "/helpers/" - ], - "transformIgnorePatterns": [ - "/node_modules/(?!(monaco-editor|@monaco-editor|monaco-vim)/)" - ] - }, - "dependencies": { - "@babel/runtime": "^7.21.0", - "@ebay/nice-modal-react": "^1.2.13", - "@emoji-mart/data": "^1.1.2", - "@emoji-mart/react": "^1.1.1", - "@fortawesome/fontawesome-free": "^5.15.1", - "@fortawesome/fontawesome-svg-core": "^1.2.32", - "@fortawesome/free-regular-svg-icons": "^6.5.1", - "@fortawesome/free-solid-svg-icons": "^6.2.0", - "@fortawesome/react-fontawesome": "^0.1.13", - "@inline-svg-unique-id/react": "^1.2.3", - "@monaco-editor/react": "^4.6.0", - "@reduxjs/toolkit": "^1.6.2", - "@sentry/react": "^8.4.0", - "@xstate/inspect": "^0.8.0", - "@xstate/react": "^3.2.2", - "@xstate/test": "^1.0.0-alpha.1", - "axios": "^1.6.0", - "bad-words-next": "^3.1.1", - "bootstrap": "^4.6.2", - "calcite-react": "^0.56.2", - "chart.js": "^4.4.3", - "classnames": "^2.2.6", - "copy-to-clipboard": "^3.3.1", - "core-js": "3.29.0", - "emoji-mart": "^5.5.2", - "formik": "^2.2.5", - "howler": "^2.2.1", - "humps": "^2.0.1", - "i18next": "^19.8.4", - "jquery": "^3.5.1", - "katex": "^0.16.21", - "lodash": "^4.17.21", - "mini-css-extract-plugin": "^2.7.3", - "moment": "^2.29.4", - "monaco-editor": "^0.52.2", - "monaco-editor-webpack-plugin": "^7.1.0", - "monaco-themes": "^0.4.4", - "monaco-vim": "^0.4.2", - "nprogress": "^0.2.0", - "path-browserify": "^1.0.1", - "phoenix": "^1.6.6", - "phoenix_html": "^3.2.0", - "phoenix_live_view": "^0.18.6", - "popper.js": "^1.16.1", - "process": "^0.11.10", - "prop-types": "^15.5.10", - "qs": "^6.9.4", - "quill-delta": "^4.2.2", - "react": "^18.2.0", - "react-bootstrap": "^1.6.7", - "react-calendar-heatmap": "^1.8.1", - "react-chartjs-2": "^5.2.0", - "react-contexify": "^6.0.0", - "react-devicons": "^2.14.0", - "react-dom": "^18.2.0", - "react-feather": "^2.0.10", - "react-hotkeys": "^2.0.0", - "react-hotkeys-hook": "^4.4.1", - "react-joyride": "^2.5.5", - "react-js-pagination": "^3.0.3", - "react-loading": "^2.0.3", - "react-markdown": "^9.0.1", - "react-player-controls": "^1.1.0", - "react-redux": "^8.1.2", - "react-select": "^5.7.4", - "react-slack-feedback": "^2.1.1", - "react-split": "^2.0.14", - "react-stay-scrolled": "^9.0.0", - "react-toastify": "^6.1.0", - "react-transition-group": "^4.4.1", - "recharts": "^2.1.16", - "redux-persist": "^6.0.0", - "rehype-katex": "^7.0.0", - "remark-math": "^6.0.0", - "rollbar": "^2.19.4", - "rollbar-redux-middleware": "^0.2.0", - "sass": "^1.44.0", - "set-value": "^4.0.1", - "styled-components": "^5.2.1", - "xstate": "^4.37.2", - "yup": "^0.29.3" - }, - "devDependencies": { - "@babel/cli": "^7.21.0", - "@babel/core": "^7.21.0", - "@babel/eslint-parser": "^7.22.10", - "@babel/plugin-proposal-decorators": "^7.21.0", - "@babel/plugin-transform-runtime": "^7.21.0", - "@babel/preset-env": "^7.20.2", - "@babel/preset-react": "^7.18.6", - "@pmmmwh/react-refresh-webpack-plugin": "^0.5.11", - "@testing-library/jest-dom": "^5.17.0", - "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.4.3", - "babel-jest": "^29.6.2", - "babel-loader": "^9.1.3", - "babel-plugin-lodash": "^3.3.4", - "babel-plugin-react-inline-svg-unique-id": "^1.4.0", - "babel-plugin-transform-import-meta": "^2.2.1", - "copy-webpack-plugin": "^11.0.0", - "css-loader": "^6.8.1", - "css-minimizer-webpack-plugin": "^5.0.1", - "eslint": "^7.14.0", - "eslint-config-airbnb": "^18.2.1", - "eslint-plugin-import": "2.22.1", - "eslint-plugin-jest": "^23.13.2", - "eslint-plugin-jsx": "0.1.0", - "eslint-plugin-jsx-a11y": "^6.4.1", - "eslint-plugin-react": "^7.21.5", - "eslint-plugin-react-hooks": "^4.2.0", - "exports-loader": "^4.0.0", - "file-loader": "^6.2.0", - "i18next-po-loader": "^1.0.0", - "image-webpack-loader": "^8.1.0", - "jest": "^26.6.3", - "jest-transform-stub": "^2.0.0", - "postcss": "^8.4.31", - "postcss-loader": "^7.3.3", - "react-refresh": "^0.14.0", - "resolve-url-loader": "^5.0.0", - "sass-loader": "^13.3.2", - "terser-webpack-plugin": "^5.3.9", - "url-loader": "^4.1.1", - "webpack": "^5.94.0", - "webpack-bundle-analyzer": "^4.9.0", - "webpack-cli": "^5.1.4", - "webpack-dev-server": "^4.15.1", - "webpack-merge": "^5.9.0" - }, - "version": "0.0.0", - "proxy": "http://localhost:8080" -} diff --git a/services/app/apps/codebattle/priv/checker.go b/services/app/apps/codebattle/priv/checker.go deleted file mode 100644 index 1ee07fd0a..000000000 --- a/services/app/apps/codebattle/priv/checker.go +++ /dev/null @@ -1,384 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "io" - "os" - "sync" - "time" -) - -// Pre-allocate buffer for JSON marshaling -var jsonBufferPool = sync.Pool{ - New: func() interface{} { - buf := make([]byte, 0, 4096) // Pre-allocate 4KB buffer - return &buf - }, -} - -type result struct { - Type string `json:"type"` - Value any `json:"value"` - Time string `json:"time"` - Output string `json:"output,omitempty"` -} - -func main() { - // Disable GC during execution for better performance - // debug.SetGCPercent(-1) - // defer debug.SetGCPercent(100) - - // Pre-allocate all needed variables - var ( - start_ time.Time - result_ result - reader_ *os.File - writer_ *os.File - err_ error - - stdout_ = os.Stdout - encoder_ = json.NewEncoder(os.Stdout) - // Pre-allocate results slice with exact capacity needed - results_ = make([]result, 0, 10) - ) - - // Set result type once - result_.Type = "result" - - var a1 int = 1 - - var b1 int = 1 - - // Create pipe for capturing stdout - reader_, writer_, err_ = os.Pipe() - if err_ != nil { - fmt.Fprintf(os.Stderr, "Error creating pipe: %v", err_) - } else { - os.Stdout = writer_ - } - - // Measure execution time with high precision - start_ = time.Now() - result_.Value = solution(a1, b1) - elapsed_ := time.Since(start_) - result_.Time = fmt.Sprintf("%.7f", float64(elapsed_.Nanoseconds())/float64(time.Second)) - - // Clean up pipe and capture output - if writer_ != nil { - writer_.Close() - } - if reader_ != nil { - outBytes_, err_ := io.ReadAll(reader_) - if err_ == nil { - result_.Output = string(outBytes_) - } - reader_.Close() - } - - // Add result to results slice - results_ = append(results_, result_) - - var a2 int = 2 - - var b2 int = 2 - - // Create pipe for capturing stdout - reader_, writer_, err_ = os.Pipe() - if err_ != nil { - fmt.Fprintf(os.Stderr, "Error creating pipe: %v", err_) - } else { - os.Stdout = writer_ - } - - // Measure execution time with high precision - start_ = time.Now() - result_.Value = solution(a2, b2) - elapsed_ := time.Since(start_) - result_.Time = fmt.Sprintf("%.7f", float64(elapsed_.Nanoseconds())/float64(time.Second)) - - // Clean up pipe and capture output - if writer_ != nil { - writer_.Close() - } - if reader_ != nil { - outBytes_, err_ := io.ReadAll(reader_) - if err_ == nil { - result_.Output = string(outBytes_) - } - reader_.Close() - } - - // Add result to results slice - results_ = append(results_, result_) - - var a3 int = 1 - - var b3 int = 2 - - // Create pipe for capturing stdout - reader_, writer_, err_ = os.Pipe() - if err_ != nil { - fmt.Fprintf(os.Stderr, "Error creating pipe: %v", err_) - } else { - os.Stdout = writer_ - } - - // Measure execution time with high precision - start_ = time.Now() - result_.Value = solution(a3, b3) - elapsed_ := time.Since(start_) - result_.Time = fmt.Sprintf("%.7f", float64(elapsed_.Nanoseconds())/float64(time.Second)) - - // Clean up pipe and capture output - if writer_ != nil { - writer_.Close() - } - if reader_ != nil { - outBytes_, err_ := io.ReadAll(reader_) - if err_ == nil { - result_.Output = string(outBytes_) - } - reader_.Close() - } - - // Add result to results slice - results_ = append(results_, result_) - - var a4 int = 3 - - var b4 int = 2 - - // Create pipe for capturing stdout - reader_, writer_, err_ = os.Pipe() - if err_ != nil { - fmt.Fprintf(os.Stderr, "Error creating pipe: %v", err_) - } else { - os.Stdout = writer_ - } - - // Measure execution time with high precision - start_ = time.Now() - result_.Value = solution(a4, b4) - elapsed_ := time.Since(start_) - result_.Time = fmt.Sprintf("%.7f", float64(elapsed_.Nanoseconds())/float64(time.Second)) - - // Clean up pipe and capture output - if writer_ != nil { - writer_.Close() - } - if reader_ != nil { - outBytes_, err_ := io.ReadAll(reader_) - if err_ == nil { - result_.Output = string(outBytes_) - } - reader_.Close() - } - - // Add result to results slice - results_ = append(results_, result_) - - var a5 int = 5 - - var b5 int = 1 - - // Create pipe for capturing stdout - reader_, writer_, err_ = os.Pipe() - if err_ != nil { - fmt.Fprintf(os.Stderr, "Error creating pipe: %v", err_) - } else { - os.Stdout = writer_ - } - - // Measure execution time with high precision - start_ = time.Now() - result_.Value = solution(a5, b5) - elapsed_ := time.Since(start_) - result_.Time = fmt.Sprintf("%.7f", float64(elapsed_.Nanoseconds())/float64(time.Second)) - - // Clean up pipe and capture output - if writer_ != nil { - writer_.Close() - } - if reader_ != nil { - outBytes_, err_ := io.ReadAll(reader_) - if err_ == nil { - result_.Output = string(outBytes_) - } - reader_.Close() - } - - // Add result to results slice - results_ = append(results_, result_) - - var a6 int = 10 - - var b6 int = 0 - - // Create pipe for capturing stdout - reader_, writer_, err_ = os.Pipe() - if err_ != nil { - fmt.Fprintf(os.Stderr, "Error creating pipe: %v", err_) - } else { - os.Stdout = writer_ - } - - // Measure execution time with high precision - start_ = time.Now() - result_.Value = solution(a6, b6) - elapsed_ := time.Since(start_) - result_.Time = fmt.Sprintf("%.7f", float64(elapsed_.Nanoseconds())/float64(time.Second)) - - // Clean up pipe and capture output - if writer_ != nil { - writer_.Close() - } - if reader_ != nil { - outBytes_, err_ := io.ReadAll(reader_) - if err_ == nil { - result_.Output = string(outBytes_) - } - reader_.Close() - } - - // Add result to results slice - results_ = append(results_, result_) - - var a7 int = 20 - - var b7 int = 2 - - // Create pipe for capturing stdout - reader_, writer_, err_ = os.Pipe() - if err_ != nil { - fmt.Fprintf(os.Stderr, "Error creating pipe: %v", err_) - } else { - os.Stdout = writer_ - } - - // Measure execution time with high precision - start_ = time.Now() - result_.Value = solution(a7, b7) - elapsed_ := time.Since(start_) - result_.Time = fmt.Sprintf("%.7f", float64(elapsed_.Nanoseconds())/float64(time.Second)) - - // Clean up pipe and capture output - if writer_ != nil { - writer_.Close() - } - if reader_ != nil { - outBytes_, err_ := io.ReadAll(reader_) - if err_ == nil { - result_.Output = string(outBytes_) - } - reader_.Close() - } - - // Add result to results slice - results_ = append(results_, result_) - - var a8 int = 10 - - var b8 int = 2 - - // Create pipe for capturing stdout - reader_, writer_, err_ = os.Pipe() - if err_ != nil { - fmt.Fprintf(os.Stderr, "Error creating pipe: %v", err_) - } else { - os.Stdout = writer_ - } - - // Measure execution time with high precision - start_ = time.Now() - result_.Value = solution(a8, b8) - elapsed_ := time.Since(start_) - result_.Time = fmt.Sprintf("%.7f", float64(elapsed_.Nanoseconds())/float64(time.Second)) - - // Clean up pipe and capture output - if writer_ != nil { - writer_.Close() - } - if reader_ != nil { - outBytes_, err_ := io.ReadAll(reader_) - if err_ == nil { - result_.Output = string(outBytes_) - } - reader_.Close() - } - - // Add result to results slice - results_ = append(results_, result_) - - var a9 int = 30 - - var b9 int = 2 - - // Create pipe for capturing stdout - reader_, writer_, err_ = os.Pipe() - if err_ != nil { - fmt.Fprintf(os.Stderr, "Error creating pipe: %v", err_) - } else { - os.Stdout = writer_ - } - - // Measure execution time with high precision - start_ = time.Now() - result_.Value = solution(a9, b9) - elapsed_ := time.Since(start_) - result_.Time = fmt.Sprintf("%.7f", float64(elapsed_.Nanoseconds())/float64(time.Second)) - - // Clean up pipe and capture output - if writer_ != nil { - writer_.Close() - } - if reader_ != nil { - outBytes_, err_ := io.ReadAll(reader_) - if err_ == nil { - result_.Output = string(outBytes_) - } - reader_.Close() - } - - // Add result to results slice - results_ = append(results_, result_) - - var a10 int = 50 - - var b10 int = 1 - - // Create pipe for capturing stdout - reader_, writer_, err_ = os.Pipe() - if err_ != nil { - fmt.Fprintf(os.Stderr, "Error creating pipe: %v", err_) - } else { - os.Stdout = writer_ - } - - // Measure execution time with high precision - start_ = time.Now() - result_.Value = solution(a10, b10) - elapsed_ := time.Since(start_) - result_.Time = fmt.Sprintf("%.7f", float64(elapsed_.Nanoseconds())/float64(time.Second)) - - // Clean up pipe and capture output - if writer_ != nil { - writer_.Close() - } - if reader_ != nil { - outBytes_, err_ := io.ReadAll(reader_) - if err_ == nil { - result_.Output = string(outBytes_) - } - reader_.Close() - } - - // Add result to results slice - results_ = append(results_, result_) - - // Reset stdout and encode results - os.Stdout = stdout_ - if err_ = encoder_.Encode(results_); err_ != nil { - fmt.Fprintln(stdout_, "Marshaler error") - } -} diff --git a/services/app/apps/codebattle/priv/gettext/en/LC_MESSAGES/default.po b/services/app/apps/codebattle/priv/gettext/en/LC_MESSAGES/default.po deleted file mode 100644 index 55f5aed2f..000000000 --- a/services/app/apps/codebattle/priv/gettext/en/LC_MESSAGES/default.po +++ /dev/null @@ -1,438 +0,0 @@ -## `msgid`s in this file come from POT (.pot) files. -## -## Do not add, change, or remove `msgid`s manually here as -## they're tied to the ones in the corresponding POT file -## (with the same domain). -## -## Use `mix gettext.extract --merge` or `mix gettext.merge` -## to merge POT files into PO files. -msgid "" -msgstr "" -"Language: en\n" - -#: lib/codebattle_web/templates/page/index.html.slim:1 -msgid "Welcome to %{name}!" -msgstr "Welcome to %{name}!" - -#: lib/codebattle_web/templates/page/index.html.slim:1 -msgid "%{name}: game for programmers." -msgstr "%{name}: game for programmers." - -#, fuzzy -#: lib/codebattle_web/templates/page/index.html.slim:6 -#: lib/codebattle_web/templates/game/index.html.slim:11 -msgid "Create a game" -msgstr "Create game" - -#: lib/codebattle_web/templates/user/index.html.slim:1 -msgid "List of games" -msgstr "List of games" - -#: lib/codebattle_web/templates/page/index.html.slim:16 -msgid "Lobby chat" -msgstr "Lobby chat" - -#: lib/codebattle_web/templates/page/index.html.slim:18 -msgid "Type a message..." -msgstr "Type a message..." - -#: lib/codebattle_web/templates/page/index.html.slim:25 -msgid "Online users" -msgstr "Online users" - -#: lib/codebattle_web/templates/layout/app.html.slim:26 -msgid "Logout" -msgstr "Logout" - -#: lib/codebattle_web/templates/layout/app.html.slim:13 -msgid "Sign in with %{name}" -msgstr "Sign in with %{name}" - -#: lib/codebattle_web/templates/game/index.html.slim:1 -msgid "Listing games" -msgstr "Listing games" - -#: lib/codebattle_web/templates/user/index.html.slim:1 -msgid "Total: " -msgstr "Total: " - -#: lib/codebattle_web/templates/game/index.html.slim:2 -msgid "Users rating: " -msgstr "Users rating: " - -#: lib/codebattle_web/templates/game/index.html.slim:17 -msgid "id: %{id}, state: %{state}, players: %{players} " -msgstr "id: %{id}, state: %{state}, players: %{players} " - -#: lib/codebattle_web/templates/game/index.html.slim:19 -msgid "Join" -msgstr "Join" - -#: lib/codebattle_web/templates/game/index.html.slim:21 -msgid "Show" -msgstr "Show" - -#: lib/codebattle_web/templates/game/index.html.slim:25 -msgid "Main page" -msgstr "Main page" - -#: lib/codebattle_web/templates/game/show.html.slim:1 -msgid "Game: %{id}" -msgstr "Game: %{id}" - -#: lib/codebattle_web/templates/game/show.html.slim:2 -msgid "State: %{state}" -msgstr "State: %{state}" - -#: lib/codebattle_web/templates/game/show.html.slim:4 -msgid "The winner is: %{name}" -msgstr "The winner is: %{name}" - -#: lib/codebattle_web/templates/game/show.html.slim:5 -msgid "Players" -msgstr "Players" - -#: lib/codebattle_web/templates/game/show.html.slim:13 -msgid "Check result" -msgstr "Check result" - -#: lib/codebattle_web/templates/game/show.html.slim:15 -msgid "Waiting for an opponent" -msgstr "Waiting for an opponent" - -#: lib/codebattle_web/templates/game/show.html.slim:21 -msgid "Back to the list of games" -msgstr "Back to the list of games" - -#: lib/codebattle_web/templates/game/show.html.slim:31 -msgid "Game chat" -msgstr "Game chat" - -#: lib/codebattle_web/templates/user/index.html.slim:12 -msgid "%{index}) name: %{name}, rating: %{rating}" -msgstr "%{index}) name: %{name}, rating: %{rating}" - -#: lib/codebattle_web/controllers/session_controller.ex:6 -msgid "You have been logged out!" -msgstr "You have been logged out!" - -#: lib/codebattle_web/controllers/auth_controller.ex:15 -msgid "Failed to authenticate." -msgstr "Failed to authenticate." - -#: lib/codebattle_web/controllers/auth_controller.ex:30 -msgid "Successfully authenticated" -msgstr "Successfully authenticated" - -#: lib/codebattle_web/controllers/game_controller.ex:41 -msgid "Game not found" -msgstr "Game not found" - -#: lib/codebattle_web/controllers/game_controller.ex:27 -msgid "Game has been created" -msgstr "Game has been created" - -#: lib/codebattle_web/controllers/game_controller.ex:53 -msgid "Yay, you won the game!" -msgstr "Yay, you won the game!" - -#: lib/codebattle_web/channels/game_channel.ex:116 -msgid "You lost the game" -msgstr "You lost the game" - -#: lib/codebattle_web/views/error_view.ex:8 -msgid "Page not found" -msgstr "Page not found" - -#: lib/codebattle_web/views/error_view.ex:13 -msgid "Internal server error" -msgstr "Internal server error" - -#: lib/codebattle_web/plugs/require_auth.ex:12 -msgid "You must be logged in to access that page" -msgstr "You must be logged in to access that page" - -#: assets/js/socket.js:49 -msgid "joined to" -msgstr "joined to" - -#: assets/js/socket.js:49 -msgid "left" -msgstr "left" - -#: assets/js/socket.js:52 -msgid "channel" -msgstr "channel" - -#, elixir-format -#: lib/codebattle_web/templates/game/game_over.html.slim:1 -msgid "Game over" -msgstr "Game over" - -#, elixir-format -#: lib/codebattle_web/templates/game/game_result.html.slim:1 -msgid "Game status" -msgstr "Game status" - -#, elixir-format -#: lib/codebattle_web/templates/game/join.html.slim:1 -msgid "Join the game" -msgstr "Join the game" - -#, elixir-format -#: lib/codebattle_web/templates/layout/app.html.slim:13 -msgid "Sign Out" -msgstr "Sign Out" - -msgid "Sign up" -msgstr "Sign up" - -#, elixir-format -#: lib/codebattle_web/controllers/auth_controller.ex:23 -#: lib/codebattle_web/controllers/dev_login_controller.ex:15 -msgid "Successfully authenticated." -msgstr "Successfully authenticated." - -#, elixir-format -#: lib/codebattle_web/templates/layout/app.html.slim:13 -msgid "Users rating" -msgstr "Users rating" - -#, elixir-format -#: lib/codebattle_web/controllers/game_controller.ex:28 -msgid "You are in a different game" -msgstr "You are in a different game" - -#, elixir-format -#: lib/codebattle_web/channels/game_channel.ex:57 -msgid "gave up!" -msgstr "gave up!" - -#, elixir-format -#: lib/codebattle_web/channels/game_channel.ex:162 -msgid "won the game!" -msgstr "won the game!" - -#, elixir-format -#: lib/codebattle_web/templates/layout/app.html.slim:13 -msgid "Hexlet" -msgstr "Hexlet" - -#, elixir-format -#: lib/codebattle_web/templates/layout/app.html.slim:13 -msgid "My Profile" -msgstr "My Profile" - -#, elixir-format -#: lib/codebattle_web/templates/layout/app.html.slim:13 -msgid "Settings" -msgstr "Settings" - -#, elixir-format -#: lib/codebattle_web/templates/layout/app.html.slim:13 -msgid "Tg#codebattle" -msgstr "Tg#codebattle" - -#, elixir-format -#: lib/codebattle_web/templates/layout/app.html.slim:13 -msgid "SourceCode" -msgstr "SourceCode" - -# JSX -msgid "Task: " -msgstr "Task: " - -msgid "Found a mistake? Have something to add? Pull Requests are welcome: " -msgstr "Found a mistake? Have something to add? Pull Requests are welcome: " - -msgid "Run your code!" -msgstr "Run your code!" - -msgid "Solution cannot be executed" -msgstr "The solution cannot be executed" - -msgid "Tests failed" -msgstr "Tests failed" - -msgid "You passed %{successCount} from %{assertsCount} asserts. (%{percent}%)" -msgstr "Passed %{successCount} from %{assertsCount} asserts. (%{percent}%)" - -msgid "Yay! All tests passed!!111" -msgstr "Yay! All tests passed!!111" - -msgid "Success Test Message" -msgstr "Yay! All tests passed!" - -msgid "Failure Test Message" -msgstr "Oh no, some test has failed!" - -msgid "Win Game Message" -msgstr "You have won the game!" - -msgid "Win Training Message" -msgstr "Congratulations! If you want to fight with real players for a place in the ranking, you need to sign up" - -msgid "Lose Game Message" -msgstr "Your opponent has won the game" - -msgid "Press Check solution or Give up" -msgstr "Press 'Check solution' or 'Give up'" - -msgid "Give up" -msgstr "Give up" - -msgid "Сheck" -msgstr "Check" - -msgid "Сheck status:" -msgstr "Check status:" - -msgid "execution time: %{time} ms" -msgstr "execution time: %{time} ms" - -msgid "Receive:" -msgstr "Receive:" - -msgid "Expected:" -msgstr "Expected:" - -msgid "Arguments:" -msgstr "Arguments:" - -msgid "Oops" -msgstr "Oops" - -msgid "Sort by:" -msgstr "Sort by:" - -msgid "Rank" -msgstr "Rank" - -msgid "Rating" -msgstr "Rating" - -msgid "Games played" -msgstr "Games played" - -msgid "Joined" -msgstr "Joined" - -msgid "Codebattle Intro" -msgstr "Read a simple task and solve it faster than your opponent in live time. Play with bots, friends and other players. Also you can fight in great tournaments." - -msgid "Codebattle Intro Title" -msgstr "Welcome to Codebattle. Show your skill!" - -msgid "Start simple battle" -msgstr "Start simple battle" - -msgid "Start battle" -msgstr "Start battle" - -msgid "Try again" -msgstr "Try again" - -msgid "Back to Home" -msgstr "Back to Home" - -msgid "%{name} (bot)" -msgstr "%{name} (bot)" - -msgid "%{name} (you)" -msgstr "%{name} (you)" - -msgid "Fight" -msgstr "Fight" - -#, elixir-format -#: lib/codebattle_web/support/notifications.ex:13 -msgid "Oh no, the time is out! Both players lost ;(" -msgstr "Oh no, the time is out! Both players lost ;(" - -msgid "Timeout - no timeout" -msgstr "No timeout" - -msgid "Timeout 60 seconds" -msgstr "1 min" - -msgid "Timeout 120 seconds" -msgstr "2 min" - -msgid "Timeout 180 seconds" -msgstr "3 min" - -msgid "Timeout 300 seconds" -msgstr "5 min" - -msgid "Timeout 480 seconds" -msgstr "8 min" - -msgid "Timeout 780 seconds" -msgstr "13 min" - -msgid "Timeout 1260 seconds" -msgstr "21 min" - -msgid "Timeout 2040 seconds" -msgstr "34 min" - -msgid "Timeout 3300 seconds" -msgstr "55 min" - -msgid "random task (%{total} available)" -msgstr "random task (%{total} available)" - -msgid "Settings changed successfully" -msgstr "Your settings has been changed" - -msgid "Something went wrong" -msgstr "Oops, something has gone wrong" - -msgid "arena_task_stats" -msgid_plural "%{count} tasks left" -msgstr[0] "%{count} task left" -msgstr[1] "%{count} tasks left" -msgstr[2] "%{count} tasks left" - -msgid "Active match" -msgstr "Асtive" - -# Participant Dashboard Translations -msgid "Participant Dashboard" -msgstr "Participant Dashboard" - -msgid "Login" -msgstr "Login" - -msgid "University" -msgstr "University" - -msgid "Category" -msgstr "Category" - -msgid "Overall Standing" -msgstr "Overall Standing" - -msgid "Category Standing" -msgstr "Category Standing" - -msgid "Qualification" -msgstr "Qualification" - -msgid "Semifinal Qualification" -msgstr "Semifinal Qualification" - -msgid "Semifinal" -msgstr "Semifinal" - -msgid "Final Qualification" -msgstr "Final Qualification" - -msgid "Final" -msgstr "Final" - -msgid "Failed" -msgstr "Failed" - -msgid "Go to" -msgstr "Go to" diff --git a/services/app/apps/codebattle/priv/gettext/ru/LC_MESSAGES/default.po b/services/app/apps/codebattle/priv/gettext/ru/LC_MESSAGES/default.po deleted file mode 100644 index 138eda013..000000000 --- a/services/app/apps/codebattle/priv/gettext/ru/LC_MESSAGES/default.po +++ /dev/null @@ -1,1017 +0,0 @@ -## `msgid`s in this file come from POT (.pot) files. -## -## Do not add, change, or remove `msgid`s manually here as -## they're tied to the ones in the corresponding POT file -## (with the same domain). -## -## Use `mix gettext.extract --merge` or `mix gettext.merge` -## to merge POT files into PO files. -msgid "" -msgstr "" -"Language: ru\n" - -#: lib/codebattle_web/templates/page/index.html.slim:1 -msgid "Welcome to %{name}!" -msgstr "Добро пожаловать в %{name}" - -#: lib/codebattle_web/templates/page/index.html.slim:1 -msgid "%{name}: game for programmers." -msgstr "%{name}: игра для программистов." - -#, fuzzy -#: lib/codebattle_web/templates/page/index.html.slim:6 -#: lib/codebattle_web/templates/game/index.html.slim:11 -msgid "Create a game" -msgstr "Создать игру" - -#: lib/codebattle_web/templates/user/index.html.slim:1 -msgid "List of games" -msgstr "Список игр" - -#: lib/codebattle_web/templates/page/index.html.slim:16 -msgid "Lobby chat" -msgstr "Общий чат" - -#: lib/codebattle_web/templates/page/index.html.slim:18 -msgid "Type a message..." -msgstr "Введите сообщение..." - -#: lib/codebattle_web/templates/page/index.html.slim:25 -msgid "Online users" -msgstr "Пользователи в сети" - -#: lib/codebattle_web/templates/layout/app.html.slim:26 -msgid "Logout" -msgstr "Выход" - -msgid "Log in" -msgstr "Войти" - -msgid "Name" -msgstr "Имя" - -msgid "Password" -msgstr "Пароль" - -msgid "Enter your name" -msgstr "Введите ваше имя" - -msgid "Enter your password" -msgstr "Введите ваш пароль" - - -#: lib/codebattle_web/templates/layout/app.html.slim:13 -msgid "Sign in with %{name}" -msgstr "Войти через %{name}" - -#: lib/codebattle_web/templates/game/index.html.slim:1 -msgid "Listing games" -msgstr "Список игр" - -#: lib/codebattle_web/templates/user/index.html.slim:1 -msgid "Total: " -msgstr "Общее количество: " - -#: lib/codebattle_web/templates/game/index.html.slim:2 -msgid "Users rating: " -msgstr "Рейтинг пользователей: " - -#: lib/codebattle_web/templates/game/index.html.slim:17 -msgid "id: %{id}, state: %{state}, players: %{players} " -msgstr "id: %{id}, состояние: %{state}, игроки: %{players} " - -#: lib/codebattle_web/templates/game/index.html.slim:19 -msgid "Join" -msgstr "Присоединиться" - -#: lib/codebattle_web/templates/game/index.html.slim:21 -msgid "Show" -msgstr "Наблюдать" - -msgid "Continue" -msgstr "Продолжать" - -#: lib/codebattle_web/templates/game/index.html.slim:25 -msgid "Main page" -msgstr "Главная страница" - -#: lib/codebattle_web/templates/game/show.html.slim:1 -msgid "Game: %{id}" -msgstr "Игра: %{id}" - -#: lib/codebattle_web/templates/game/show.html.slim:2 -msgid "State: %{state}" -msgstr "Состояние: %{state}" - -#: lib/codebattle_web/templates/game/show.html.slim:4 -msgid "The winner is: %{name}" -msgstr "Победитель: %{name}" - -#: lib/codebattle_web/templates/game/show.html.slim:5 -msgid "Players" -msgstr "Игроки" - -#: lib/codebattle_web/templates/game/show.html.slim:13 -msgid "Check result" -msgstr "Проверить результат" - - - -#: lib/codebattle_web/templates/game/show.html.slim:15 -msgid "Waiting for an opponent" -msgstr "Ожидание соперника" - -msgid "You are following ID: %{followId}" -msgstr "Вы подписаны на ID: %{followId}" - -#: lib/codebattle_web/templates/game/show.html.slim:21 -msgid "Back to the list of games" -msgstr "Вернуться к списку игр" - -#: lib/codebattle_web/templates/game/show.html.slim:31 -msgid "Game chat" -msgstr "Игровой чат" - -#: lib/codebattle_web/templates/user/index.html.slim:12 -msgid "%{index}) name: %{name}, rating: %{rating}" -msgstr "%{index}) имя: %{name}, рейтинг: %{rating}" - -#: lib/codebattle_web/controllers/session_controller.ex:6 -msgid "You have been logged out!" -msgstr "Вы успешно вышли из системы!" - -#: lib/codebattle_web/controllers/session_controller.ex:29 -msgid "Welcome to Codebattle!" -msgstr "Добро пожаловать в Codebattle!" - -#: lib/codebattle_web/controllers/session_controller.ex:24 -msgid "Invalid name or password" -msgstr "Неверное имя пользователя или пароль" - -#: lib/codebattle_web/controllers/auth_controller.ex:15 -msgid "Failed to authenticate." -msgstr "Ошибка аутентификации." - -#: lib/codebattle_web/controllers/auth_controller.ex:30 -msgid "Successfully authenticated" -msgstr "Успешная аутентификация." - -#: lib/codebattle_web/controllers/game_controller.ex:41 -msgid "Game not found" -msgstr "Игра не найдена" - -#: lib/codebattle_web/controllers/game_controller.ex:27 -msgid "Game has been created" -msgstr "Игра успешно создана" - -#: lib/codebattle_web/controllers/game_controller.ex:53 -msgid "Yay, you won the game!" -msgstr "Ура, Вы победили!" - -#: lib/codebattle_web/channels/game_channel.ex:116 -msgid "You lost the game" -msgstr "Вы проиграли игру." - -#: lib/codebattle_web/views/error_view.ex:8 -msgid "Page not found" -msgstr "Страница не найдена" - -#: lib/codebattle_web/views/error_view.ex:13 -msgid "Internal server error" -msgstr "Внутренняя ошибка сервера" - -#: lib/codebattle_web/plugs/require_auth.ex:12 -msgid "You must be logged in to access that page" -msgstr "Для просмотра этой страницы Вам нужно войти" - -#: assets/js/socket.js:49 -msgid "joined to" -msgstr "Вошёл в" - -#: assets/js/socket.js:49 -msgid "left" -msgstr "Покинул" - -#: assets/js/socket.js:52 -msgid "channel" -msgstr "канал" - -#, elixir-format -#: lib/codebattle_web/templates/game/game_over.html.slim:1 -msgid "Game over" -msgstr "Игра окончена" - -#, elixir-format -#: lib/codebattle_web/templates/game/game_result.html.slim:1 -msgid "Game status" -msgstr "Статус игры" - -#, elixir-format -#: lib/codebattle_web/templates/game/join.html.slim:1 -msgid "Join the game" -msgstr "Вы подключились к игре" - -#, elixir-format -#: lib/codebattle_web/templates/layout/app.html.slim:13 -msgid "Sign Out" -msgstr "Выйти" - -msgid "Sign up" -msgstr "Регистрация" - -#, elixir-format -#: lib/codebattle_web/controllers/auth_controller.ex:23 -#: lib/codebattle_web/controllers/dev_login_controller.ex:15 -msgid "Successfully authenticated." -msgstr "Успешная аутентификация." - -#, elixir-format -#: lib/codebattle_web/templates/layout/app.html.slim:13 -msgid "Users rating" -msgstr "Рейтинг пользователей" - -#, elixir-format -#: lib/codebattle_web/controllers/game_controller.ex:28 -msgid "You are in a different game" -msgstr "Вы уже участвуете в другой игре" - -#, elixir-format -#: lib/codebattle_web/channels/game_channel.ex:57 -msgid "gave up!" -msgstr "" - -#, elixir-format -#: lib/codebattle_web/channels/game_channel.ex:162 -msgid "won the game!" -msgstr "Вы победили в игре!" - -#, elixir-format -#: lib/codebattle_web/templates/layout/app.html.slim:13 -msgid "Hexlet" -msgstr "Хекслет" - -#, elixir-format -#: lib/codebattle_web/templates/layout/app.html.slim:13 -msgid "My Profile" -msgstr "Мой Профиль" - -#, elixir-format -msgid "Tasks" -msgstr "Задачи" - -#, elixir-format -msgid "Tournaments" -msgstr "Турниры" - -msgid "Tournament" -msgstr "Турнир" - -#, elixir-format -msgid "Join Discord" -msgstr "Чат Discord" - -#, elixir-format -#: lib/codebattle_web/templates/layout/app.html.slim:13 -msgid "Settings" -msgstr "Настройки" - -#, elixir-format -#: lib/codebattle_web/templates/layout/app.html.slim:13 -msgid "Tg#codebattle" -msgstr "Чат телеграмм" - -#, elixir-format -#: lib/codebattle_web/templates/layout/app.html.slim:13 -msgid "SourceCode" -msgstr "Исходный Код" - -# JSX -msgid "Pause" -msgstr "Приостановить" - -msgid "Unpause" -msgstr "Возобновить" - -msgid "Unfollow" -msgstr "Прекратить" - -msgid "Task: " -msgstr "Задача: " - -msgid "Won:" -msgstr "Побед:" - -msgid "Lost:" -msgstr "Поражений:" - -msgid "GaveUp:" -msgstr "Сдался:" - -msgid "Task" -msgstr "Задача" - -msgid "Editor" -msgstr "Редактор" - -msgid "Output" -msgstr "Тесты" - -msgid "Send" -msgstr "Отправить" - -msgid "Notification" -msgstr "Нотификация" - -msgid "Run" -msgstr "Запустить" - -msgid "Charging..." -msgstr "Заряжается..." - -msgid "Running..." -msgstr "Запускается..." - -msgid "Show guide" -msgstr "Гайд" - -msgid "Reset solution" -msgstr "Сбросить решение" - -msgid "Check solution" -msgstr "Проверить решение" - -msgid "Expand" -msgstr "Развернуть описание" - -msgid "Found a mistake? Have something to add? Pull Requests are welcome: " -msgstr "Нашли ошибку? Вам есть что добавить к описанию? Мы будем рады вашим Pull Requests: " - -msgid "Run your code!" -msgstr "Запустите Ваш код!" - -msgid "Solution cannot be executed" -msgstr "Решение не может быть выполнено" - -msgid "Tests failed" -msgstr "Тесты не пройдены" - -msgid "You passed %{successCount} from %{assertsCount} asserts. (%{percent}%)" -msgstr "Прошли %{successCount} из %{assertsCount} тестов. (%{percent}%)" - -msgid "Yay! All tests passed!!111" -msgstr "Поздравляю! Все тесты пройдены!!111" - -msgid "Success Test Message" -msgstr "Поздравляю! Тесты пройдены!" - -msgid "Failure Test Message" -msgstr "О нет, тесты не пройдены!" - -msgid "Win Game Message" -msgstr "Поздравляю! Вы победили!" - -msgid "Win Training Message" -msgstr "Поздравляю! Если вы хотите сражаться с живыми игроками за место в рейтинге - зарегистрируйтесь!" - -msgid "Time is up. There are no winners in the game" -msgstr "Время вышло. Никто не выиграл эту битву" - -msgid "Lose Game Message" -msgstr "К сожалению, Ваш оппонент выиграл эту битву" - -msgid "Press Check solution or press Give up" -msgstr "Нажмите 'Проверить решение' или 'Сдаться'" - -msgid "Give up" -msgstr "Сдаться" - -msgid "Сheck" -msgstr "Отправить решение" - -msgid "Сheck status:" -msgstr "Статус проверки:" - -msgid "execution time: %{time} ms" -msgstr "время выполнения: %{time} ms" - -msgid "Receive:" -msgstr "Получено:" - -msgid "Expected:" -msgstr "Ожидалось:" - -msgid "Arguments:" -msgstr "Аргументы:" - -#, fuzzy -msgid "Oops" -msgstr "Упс!" - -msgid "Sort by:" -msgstr "Сортировать по:" - -msgid "Rank" -msgstr "Ранг" - -msgid "Rating" -msgstr "Рейтинг" - -msgid "Games played" -msgstr "Сыгранные игры" - -msgid "Joined" -msgstr "Дата регистрации" - -msgid "Codebattle Intro" -msgstr "Прочтите описание простой задачи и решите её быстрее вашего оппонента в реальном времени. Регистрируйтесь и играйте с ботами, друзьями и другими игроками. Так же, Вы можете сражаться в турнирах." - -msgid "Codebattle Intro Title" -msgstr "Добро пожаловать в Codebattle. Продемонстрируй свои умения!" - -msgid "Start simple battle" -msgstr "Начать простое сражение" - -msgid "Start battle" -msgstr "Начать битву" - -msgid "Try again" -msgstr "Начать заново" - -msgid "Back to Home" -msgstr "На главную" - -msgid "Open History" -msgstr "Смотреть историю" - -msgid "%{name} (bot)" -msgstr "%{name} (бот)" - -msgid "%{name} (you)" -msgstr "%{name} (вы)" - -msgid "Fight" -msgstr "Сражаться" - -#, elixir-format -#: lib/codebattle_web/support/notifications.ex:13 -msgid "Oh no, the time is out! Both players lost ;(" -msgstr "О нет, время вышло! Оба игрока проиграли ;(" - -msgid "Timeout - no timeout" -msgstr "Таймер - нет таймера" - -msgid "Timeout 60 seconds" -msgstr "Таймер на 60 секунд" - -msgid "Timeout 120 seconds" -msgstr "Таймер на 120 секунд" - -msgid "Timeout 300 seconds" -msgstr "Таймер на 300 секунд" - -msgid "Timeout 600 seconds" -msgstr "Таймер на 600 секунд" - -msgid "Timeout 1200 seconds" -msgstr "Таймер на 1200 секунд" - -msgid "Timeout 3600 seconds" -msgstr "Таймер на 3600 секунд" - -msgid "Top-3" -msgstr "Топ-3" - -msgid "Total number of teams %{count}" -msgstr "Общее количество команд %{count}" - -msgid "Place" -msgstr "Место" - -msgid "Score" -msgstr "Балл" - -msgid "User" -msgstr "Участник" - -msgid "Duration (sec)" -msgstr "Время (сек)" - -msgid "Clan" -msgstr "Вуз" - -msgid "Count of solutions" -msgstr "Количество успешных решений" - -msgid "Total time for solving task" -msgstr "Общее время решения задачи" - -msgid "Task duration distribution" -msgstr "Распределение по времени решения задачи (Количество решений/сек)" - -msgid "Show task description" -msgstr "Показать описание задачи" - -msgid "%{percent}% (sec)" -msgstr "%{percent}% (сек)" - -msgid "Fastest time to solve task (sec)" -msgstr "Самое быстрое решение (сек)" - -msgid "Slowest time to solve task (sec)" -msgstr "Самое медленное решение (сек)" - -msgid "Event rating" -msgstr "Таблица Участников" - -msgid "Clans rating" -msgstr "Рейтинг вузов" - -msgid "Players rating" -msgstr "Рейтинг участников" - -msgid "Clan players rating" -msgstr "Рейтинг участников вуза" - -msgid "Clan players_count/registrations" -msgstr "Участники/Регистрации" - -msgid "Clan players count" -msgstr "Количество участников" - -msgid "Event stages" -msgstr "Как устроен турнир" - -msgid "Stage %{name}" -msgstr "Тур %{name}" - -msgid "Stage: " -msgstr "Тур: " - -msgid "Games: " -msgstr "Игры: " - -msgid "Stats: " -msgstr "Статистика: " - -msgid "Games" -msgstr "Игры" - -msgid "closed" -msgstr "закрыт" - -msgid "active" -msgstr "активно" - -msgid "soon" -msgstr "скоро" - -msgid "Login" -msgstr "Логин" - -msgid "Tournament description" -msgstr "Описание тура" - -msgid "Open" -msgstr "Открыть" - -msgid "Cancel" -msgstr "Отменить" - -msgid "Close" -msgstr "Закрыть" - -msgid "Leave" -msgstr "Выйти" - -msgid "Teams" -msgstr "Команды" - -msgid "Search opponent" -msgstr "Поиск соперника" - -msgid "Back to tournament" -msgstr "Назад в турнир" - -msgid "Back to tournaments" -msgstr "На главную" - -msgid "Back to event" -msgstr "Вернуться в ЛК" - -msgid "Star us on GitHub" -msgstr "Поддержать нас на GitHub" - -msgid "Star us" -msgstr "Поддержать нас" - -msgid "Restart searching" -msgstr "Вернуться к поиску" - -msgid "Stop searching" -msgstr "Приостановить" - -msgid "Go to active game" -msgstr "К активной игре" - -msgid "arena_task_stats" -msgid_plural "%{count} tasks left" -msgstr[0] "Осталась %{count} задача" -msgstr[1] "Осталось %{count} задачи" -msgstr[2] "Осталось %{count} задач" - -msgid "Searching opponent" -msgstr "Поиск соперника" - -msgid "Congrats! All tasks are solved" -msgstr "Задачи закончились, поздравляем!" - -msgid "The tournament will start: %{duration}" -msgstr "Тур начнется через: %{duration}" - -msgid "The tournament will start soon" -msgstr "Тур скоро начнется" - -msgid "The tournament is cancelled" -msgstr "Игры тура отменены" - -msgid "The tournament is finished" -msgstr "Игры тура завершились" - -msgid "Your opponent is waiting: %{name}" -msgstr "Ваш следующий оппонент: %{name}" - -msgid "Next match will be opened. Show now?" -msgstr "Следующая битва началась. Открыть сейчас?" - -msgid "review" -msgstr "общее" - -msgid "matches" -msgstr "история" - -msgid "Opponent" -msgstr "Соперник" - -msgid "Opponent clan" -msgstr "Вуз соперника" - -msgid "Status" -msgstr "Статус задачи" - -msgid "Open match" -msgstr "Перейти к задаче" - -msgid "You banned" -msgstr "Вы забанены" - -msgid "Active match" -msgstr "Есть активная задача" - -msgid "Waiting" -msgstr "Ожидание" - -msgid "Wait round starts" -msgstr "Ожидайте начала матча" - -msgid "Waiting Participants" -msgstr "Ожидаем участников" - -msgid "Active" -msgstr "Активен" - -msgid "Round break" -msgstr "Перерыв на следующий раунд" - -msgid "Canceled" -msgstr "Отменен" - -msgid "Finished" -msgstr "Завершен" - -msgid "Loading" -msgstr "Загружается" - -msgid "Round ends in " -msgstr "Игры этапа завершатся через " - -msgid "Next round will start in " -msgstr "Следующие игры начнутся через " - -msgid "Draw" -msgstr "Последняя задача в ничью" - -msgid "You lose" -msgstr "Последняя задача проиграна" - -msgid "You win" -msgstr "Последняя задача выиграна" - -msgid "Your place in tournament" -msgstr "Твое место в турнире" - -msgid "Your place" -msgstr "Твое место" - -msgid "Your score" -msgstr "Твой балл" - -msgid "Your clan place" -msgstr "Место твоего вуза" - -msgid "Your clan score" -msgstr "Балл твоего вуза" - -msgid "Statistics" -msgstr "Статистика" - -msgid "Wins" -msgstr "Побед" - -msgid "Wins count" -msgstr "Количество побед" - -msgid "Loses" -msgstr "Поражений" - -msgid "Timeout" -msgstr "Нет победителя" - -msgid "Show match" -msgstr "Показать игру" - -msgid "Show match history" -msgstr "Показать историю игры" - -msgid "Continue match" -msgstr "Продолжить игру" - -msgid "History" -msgstr "История" - -msgid "stored" -msgstr "Сохранена" - -msgid "game_over" -msgstr "Игра завершена" - -msgid "Loading..." -msgstr "Загрузка..." - -msgid "Join the round" -msgstr "Перейти в раунд" - -msgid "Timeout in: %{time}" -msgstr "Завершится через: %{time}" - -msgid "Woohoo, you're Champion!!!!!" -msgstr "Баттл официально затащен!" - -msgid "Loading next game" -msgstr "Ожидайте следующую игру" - -msgid "Tournament is over" -msgstr "Турнир завершен" - -msgid "Round is over, wait for the next round" -msgstr "Задача решена, дождись следующую" - -msgid "If you read this you've lost the game" -msgstr "Ты заслуживаешь победы, продолжай!" - -msgid "I'll be back" -msgstr "Айл би бэк" - -msgid "GG" -msgstr "Чемпион" - -msgid "STDOUT" -msgstr "ВЫВОД" - -msgid "Next game" -msgstr "Следующая задача" - -msgid "Award" -msgstr "Награда" - -msgid "Total entries: %{totalEntries}" -msgstr "Общее количество: %{totalEntries}" - -msgid "We could not verify your solution" -msgstr "Мы не смогли проверить ваше решение" - -msgid "Please try to fix your code and submit it again" -msgstr "Пожалуйста, исправьте ваш код и отправьте его снова" - -msgid "Note that your code may contain an infinite loop or complex calculations" -msgstr "Обратите внимание, что ваш код может содержать бесконечный цикл или сложные вычисления" - -msgid "Rating Panel" -msgstr "Рейтинг участников" - -msgid "Player Panel" -msgstr "Панель участника" - -msgid "Top users by clan ranking" -msgstr "Лучшие игроки в рейтинге вузов" - -msgid "Tasks ranking" -msgstr "Рейтинг задач" - -msgid "Clans bubble distribution" -msgstr "График распределения лучших вузов" - -msgid "Duration distribution and top users by task" -msgstr "Статистика по задаче" - -msgid "Back" -msgstr "Назад" - -msgid "Tournament is paused" -msgstr "Игра этапа завершены" - -msgid "Connection lost, please reload the page" -msgstr "Связь с сервером потеряна, перезагрузите страницу" - -msgid "Show full tournament table" -msgstr "Показать полную турнирную таблицу" - -msgid "Type: %{type}" -msgstr "Тип: %{type}" - -msgid "swiss" -msgstr "Швейцарская система" - -msgid "individual" -msgstr "Олимпийская система" - -msgid "team" -msgstr "Командный турнир" - -msgid "arena" -msgstr "Арена" - -msgid "Tournament waiting_participants" -msgstr "Турнир скоро начнется" - -msgid "Tournament canceled" -msgstr "Турнир отменен" - -msgid "Tournament active" -msgstr "Турнир активен" - -msgid "Tournament finished" -msgstr "Турнир завершен" - -msgid "Starts At" -msgstr "Начало" - -msgid "Game playing" -msgstr "Игра продолжается" - -msgid "Game waiting_opponent" -msgstr "Ожидание соперника" - -msgid "Game state: timeout" -msgstr "Статус: время истекло" - -msgid "Game state: canceled" -msgstr "Статус: игра отменена" - -msgid "Game state: game_over" -msgstr "Статус: игра окончена" - -msgid "Game state: initial" -msgstr "Статус: игра создается" - -msgid "Game state: builder" -msgstr "Статус: игра готовится к запуску" - -msgid "Game state: waiting_opponent" -msgstr "Статус: ожидание соперника" - -msgid "Game state: playing" -msgstr "Статус: игра идет" - -msgid "Level: elementary" -msgstr "Уровень: элементарный" - -msgid "Level: easy" -msgstr "Уровень: легкий" - -msgid "Level: medium" -msgstr "Уровень: средний" - -msgid "Level: hard" -msgstr "Уровень: сложный" - -msgid "Timeout: %{sec} seconds" -msgstr "Время на задачу: %{sec} секунд" - -msgid "undefined" -msgstr "не определено" - -msgid "won" -msgstr "победа" - -msgid "lost" -msgstr "поражение" - -msgid "gave_up" -msgstr "сдался" - -msgid "timeout" -msgstr "время вышло" - -msgid "Game between" -msgstr "Игра между" - -msgid "Game level" -msgstr "Уровень сложности" - -msgid "Play with" -msgstr "Играть с" - -msgid "Try simple battle" -msgstr "Попробовать простую игру" - -msgid "You don't have access to this game" -msgstr "У вас нет доступа к этой игре" - -msgid "Total players" -msgstr "Всего игроков" - -msgid "No players yet" -msgstr "Игроков пока нет" - -msgid "Task Description" -msgstr "Описание задачи" - -msgid "Win" -msgstr "Победа" - -msgid "Lost" -msgstr "Поражение" - -# Participant Dashboard Translations -msgid "Participant Dashboard" -msgstr "Личный кабинет участника" - -msgid "Category" -msgstr "Категория" - -msgid "Overall Standing" -msgstr "Место в общем зачёте" - -msgid "Category Standing" -msgstr "Место в категории" - -msgid "Qualification" -msgstr "Квалификация" - -msgid "Semifinal Entrance" -msgstr "Выход в полуфинал" - -msgid "Semifinal" -msgstr "Полуфинал" - -msgid "Final Entrance" -msgstr "Выход в финал" - -msgid "Final" -msgstr "Финал" - -msgid "Failed" -msgstr "Не прошёл" - -msgid "Go to" -msgstr "Перейти" - -msgid "Report" -msgstr "Пожаловаться" - -msgid "Ban" -msgstr "Забанить" - -msgid "Place in total" -msgstr "Место в общем зачете" - -msgid "Place in category" -msgstr "Место в категории" - -msgid "Time spent" -msgstr "Время на этап" - -msgid "You already passed this stage" -msgstr "Вы уже прошли этот этап" - -msgid "Stage confirmation" -msgstr "Подтверждение этапа" - -msgid "Passed" -msgstr "Прошёл" - -msgid "Not passed" -msgstr "Не прошёл" - -msgid "Ranking" -msgstr "Рейтинг" \ No newline at end of file diff --git a/services/app/apps/codebattle/priv/repo/seeds.exs b/services/app/apps/codebattle/priv/repo/seeds.exs deleted file mode 100644 index 6fcf0d762..000000000 --- a/services/app/apps/codebattle/priv/repo/seeds.exs +++ /dev/null @@ -1,536 +0,0 @@ -alias Codebattle.Clan -alias Codebattle.Event -alias Codebattle.Game -alias Codebattle.Repo -alias Codebattle.TaskPack -alias Codebattle.User -alias Codebattle.UserEvent -alias Codebattle.UserGame - -levels = ["elementary", "easy", "medium", "hard"] - -Enum.each(1..10, fn x -> - for level <- levels do - task_params = %{ - level: level, - name: "task_#{level}_#{x}", - tags: Enum.take_random(["math", "lol", "kek", "asdf", "strings", "hash-maps", "collections"], 3), - origin: "github", - state: "active", - visibility: "public", - description_en: "test sum", - description_ru: "проверка суммирования", - examples: "```\n2 == solution(1,1)\n10 == solution(9,1)\n```", - asserts: [ - %{arguments: [1, 1], expected: 2}, - %{arguments: [2, 2], expected: 4}, - %{arguments: [1, 2], expected: 3}, - %{arguments: [3, 2], expected: 5}, - %{arguments: [5, 1], expected: 6}, - %{arguments: [10, 0], expected: 10}, - %{arguments: [20, 2], expected: 22}, - %{arguments: [10, 2], expected: 12}, - %{arguments: [30, 2], expected: 32}, - %{arguments: [50, 1], expected: 51} - ], - disabled: false, - input_signature: [ - %{argument_name: "a", type: %{name: "integer"}}, - %{argument_name: "b", type: %{name: "integer"}} - ], - output_signature: %{type: %{name: "integer"}} - } - - task = Codebattle.Task.upsert!(task_params) - - playbook_data = %{ - players: [%{id: 2, total_time_ms: 5_000, editor_lang: "ruby", editor_text: ""}], - records: [ - %{"type" => "init", "id" => 2, "editor_text" => "", "editor_lang" => "ruby"}, - %{ - "diff" => %{ - "delta" => [%{"insert" => "def solution()\n\nend"}], - "next_lang" => "ruby", - "time" => 0 - }, - "type" => "update_editor_data", - "id" => 2 - }, - %{ - "diff" => %{ - "delta" => [%{"retain" => 13}, %{"insert" => "a"}], - "next_lang" => "ruby", - "time" => 2058 - }, - "type" => "update_editor_data", - "id" => 2 - }, - %{ - "diff" => %{ - "delta" => [%{"retain" => 14}, %{"insert" => ","}], - "next_lang" => "ruby", - "time" => 145 - }, - "type" => "update_editor_data", - "id" => 2 - }, - %{ - "diff" => %{ - "delta" => [%{"retain" => 15}, %{"insert" => "b"}], - "next_lang" => "ruby", - "time" => 725 - }, - "type" => "update_editor_data", - "id" => 2 - }, - %{ - "diff" => %{ - "delta" => [%{"retain" => 19}, %{"insert" => "\n"}], - "next_lang" => "ruby", - "time" => 620 - }, - "type" => "update_editor_data", - "id" => 2 - }, - %{ - "diff" => %{ - "delta" => [%{"retain" => 18}, %{"insert" => "a"}], - "next_lang" => "ruby", - "time" => 593 - }, - "type" => "update_editor_data", - "id" => 2 - }, - %{ - "diff" => %{ - "delta" => [%{"retain" => 19}, %{"insert" => " "}], - "next_lang" => "ruby", - "time" => 329 - }, - "type" => "update_editor_data", - "id" => 2 - }, - %{ - "diff" => %{ - "delta" => [%{"retain" => 20}, %{"insert" => "+"}], - "next_lang" => "ruby", - "time" => 500 - }, - "type" => "update_editor_data", - "id" => 2 - }, - %{ - "diff" => %{ - "delta" => [%{"retain" => 21}, %{"insert" => " "}], - "next_lang" => "ruby", - "time" => 251 - }, - "type" => "update_editor_data", - "id" => 2 - }, - %{ - "diff" => %{ - "delta" => [%{"retain" => 22}, %{"insert" => "b"}], - "next_lang" => "ruby", - "time" => 183 - }, - "type" => "update_editor_data", - "id" => 2 - }, - %{"type" => "game_over", "id" => 2, "lang" => "ruby"} - ] - } - - Repo.insert!(%Codebattle.Playbook{ - data: playbook_data, - task: task, - game_id: 1, - winner_lang: "ruby", - winner_id: 2, - solution_type: "complete" - }) - end -end) - -creator = %{ - name: "User1_admin#{Timex.format!(DateTime.utc_now(), "%FT%T%:z", :strftime)}", - is_bot: false, - rating: 1300, - email: "admin@user1#{Timex.format!(DateTime.utc_now(), "%FT%T%:z", :strftime)}", - avatar_url: "/assets/images/logo.svg", - lang: "ruby", - inserted_at: TimeHelper.utc_now(), - updated_at: TimeHelper.utc_now() -} - -{:ok, creator} = - %User{} - |> User.changeset(creator) - |> Repo.insert() - -%Codebattle.Tournament{} -|> Codebattle.Tournament.changeset(%{ - name: "Codebattle Hexlet summer tournament 2019", - state: "finished", - creator: creator, - players_limit: 16, - difficulty: "elementary", - starts_at: ~N[2019-08-22 19:33:08.910767] -}) -|> Repo.insert!() - -now = DateTime.utc_now() -one_month_ago = Timex.shift(now, months: -1) -two_weeks_ago = Timex.shift(now, weeks: -2) -five_days_ago = Timex.shift(now, days: -5) -six_hours_ago = Timex.shift(now, hours: -6) - -Enum.each([one_month_ago, two_weeks_ago, five_days_ago, six_hours_ago], fn t -> - game_params = %{ - state: "game_over", - level: "easy", - type: "duo", - mode: "standard", - visibility_type: "public", - starts_at: t |> Timex.to_naive_datetime() |> NaiveDateTime.truncate(:second), - finishes_at: t |> Timex.to_naive_datetime() |> NaiveDateTime.truncate(:second), - inserted_at: TimeHelper.utc_now(), - updated_at: TimeHelper.utc_now() - } - - {:ok, game} = - %Game{} - |> Game.changeset(game_params) - |> Repo.insert() - - user_1_params = %{ - name: "User1_#{Timex.format!(t, "%FT%T%:z", :strftime)}", - is_bot: false, - rating: 1300, - email: "#{Timex.format!(t, "%FT%T%:z", :strftime)}@user1", - avatar_url: "/assets/images/logo.svg", - lang: "ruby", - inserted_at: TimeHelper.utc_now(), - updated_at: TimeHelper.utc_now() - } - - {:ok, user_1} = - %User{} - |> User.changeset(user_1_params) - |> Repo.insert() - - user_2_params = %{ - name: "User2_#{Timex.format!(t, "%FT%T%:z", :strftime)}", - is_bot: false, - rating: -500, - email: "#{Timex.format!(t, "%FT%T%:z", :strftime)}@user2", - lang: "java", - avatar_url: "/assets/images/logo.svg", - inserted_at: TimeHelper.utc_now(), - updated_at: TimeHelper.utc_now() - } - - {:ok, user_2} = - %User{} - |> User.changeset(user_2_params) - |> Repo.insert() - - user_game_1_params = %{ - game_id: game.id, - user_id: user_1.id, - result: "won", - creator: true, - rating: user_1.rating + 32, - rating_diff: 32, - lang: user_1.lang - } - - {:ok, _user_game_1_params} = - %UserGame{} - |> UserGame.changeset(user_game_1_params) - |> Repo.insert() - - user_game_2_params = %{ - game_id: game.id, - user_id: user_2.id, - result: "lost", - creator: false, - rating: user_2.rating - 32, - rating_diff: -32, - lang: user_2.lang - } - - {:ok, _user_game_2_params} = - %UserGame{} - |> UserGame.changeset(user_game_2_params) - |> Repo.insert() -end) - -for level <- levels do - task_ids = - Codebattle.Task - |> Repo.all() - |> Enum.filter(&(&1.level == level)) - |> Enum.filter(&String.starts_with?(&1.name, "task_#{level}")) - |> Enum.map(& &1.id) - - name = "7_#{level}" - - Repo.get_by(TaskPack, name: name) || - %TaskPack{ - creator_id: 1, - name: name, - visibility: "public", - state: "active", - task_ids: Enum.take(task_ids, 7) - } - |> TaskPack.changeset() - |> Repo.insert!() - - name = "10_#{level}" - - Repo.get_by(TaskPack, name: name) || - %TaskPack{ - creator_id: 1, - name: name, - visibility: "public", - state: "active", - task_ids: Enum.take(task_ids, 10) - } - |> TaskPack.changeset() - |> Repo.insert!() -end - -# Build users for load tests with clans -Enum.each(1..100, fn id -> - Clan.find_or_create_by_clan("clan_#{id}", 1) -end) - -tokens = - Enum.map(1..2000, fn id -> - t = DateTime.utc_now() - - clan_id = - 50 - |> Statistics.Distributions.Normal.rand(7) - |> round() - |> min(100) - |> max(1) - |> to_string() - - params = %{ - name: "rBot_#{id}_", - clan: "clan_#{clan_id}", - clan_id: clan_id, - is_bot: false, - rating: 1200, - email: "#{Timex.format!(t, "%FT%T%:z", :strftime)}@user#{id}", - lang: "python", - inserted_at: TimeHelper.utc_now(), - updated_at: TimeHelper.utc_now() - } - - {:ok, user} = - %User{} - |> User.changeset(params) - |> Repo.insert() - - token = Phoenix.Token.sign(CodebattleWeb.Endpoint, "user_token", user.id) - "#{user.id}:#{token}:python" - end) - -File.mkdir_p!("tmp") -File.write!("tmp/tokens.txt", Enum.join(tokens, "\n")) - -stages = - [ - %{ - slug: "qualification", - name: "Qualification", - dates: "May 12-17", - action_button_text: "Go", - confirmation_text: "Confirm that you want to suffer 1 hour", - status: :active, - type: :tournament, - playing_type: :single, - tournament_meta: %{ - type: "swiss", - rounds_limit: 7, - access_type: "token", - score_strategy: "win_loss", - state: "waiting_participants", - task_pack_name: "qualification", - tournament_timeout_seconds: 75 * 60, - players_limit: 128, - ranking_type: "void", - task_provider: "task_pack", - task_strategy: "sequential" - } - }, - %{ - slug: "semifinal_entrance", - name: "Semifinal Entrance", - type: :entrance, - status: :active - }, - %{ - slug: "semifinal", - name: "Semifinal", - dates: "May 31", - action_button_text: "Go", - confirmation_text: "Confirm that you want to suffer 1 hour", - status: :active, - type: :tournament - }, - %{ - slug: "final_entrance", - name: "Final Entrance", - type: :entrance, - status: :active - }, - %{ - slug: "final", - name: "Final", - action_button_text: "Go", - confirmation_text: "Confirm that you want to suffer 1 hour", - dates: "June 26", - status: :active, - type: :tournament - } - ] - -# Create or find event -event_slug = "vibecoding-2025" - -event_params = %{ - slug: event_slug, - title: "Codebattle Hexlet summer", - description: "Codebattle Hexlet summer", - starts_at: ~N[2019-08-22 19:33:08.910767], - finishes_at: ~N[2019-08-22 19:33:08.910767], - stages: stages -} - -case Repo.get_by(Event, slug: event_slug) do - nil -> - %Event{} - |> Event.changeset(event_params) - |> Repo.insert!() - - event -> - event - |> Event.changeset(event_params) - |> Repo.update!() -end - -# Create user_event records for all existing users -users = User |> Repo.all() |> Enum.filter(&(&1.id > 0)) -events = Repo.all(Event) - -if Enum.any?(events) do - Enum.each(events, fn event -> - Enum.each(users, fn user -> - case UserEvent.get_by_user_id_and_event_id(user.id, event.id) do - nil -> - UserEvent.create(%{ - user_id: user.id, - event_id: event.id, - stages: [ - %{ - slug: "qualification", - status: :pending, - place_in_total_rank: nil, - place_in_category_rank: nil, - score: nil, - wins_count: Enum.random(0..10), - games_count: Enum.random(1..20), - time_spent_in_seconds: Enum.random(100..10_000) - }, - %{ - slug: "semifinal_entrance", - entrance_result: :passed - }, - %{ - slug: "semifinal", - tournament_type: :global, - status: :pending, - place_in_total_rank: Enum.random(1..50), - place_in_category_rank: Enum.random(1..25), - score: Enum.random(10..100), - wins_count: Enum.random(0..10), - games_count: Enum.random(1..15), - time_spent_in_seconds: Enum.random(100..8000) - }, - %{ - slug: "final_entrance", - entrance_result: :not_passed - }, - %{ - slug: "final", - status: :pending, - place_in_total_rank: Enum.random(1..20), - place_in_category_rank: Enum.random(1..10), - score: Enum.random(20..100), - wins_count: Enum.random(0..8), - games_count: Enum.random(1..10), - time_spent_in_seconds: Enum.random(100..5000) - } - ] - }) - - user_event -> - IO.puts("User event already exists for user #{user.id} and event #{event.id}") - end - end) - end) -else - IO.puts("No events found in the database") -end - -# Repo.delete_all(UserEvent) - -# UserEvent.create(%{ -# user_id: 355, -# event_id: 1, -# stages: [ -# %{ -# slug: "qualification", -# status: :pending, -# place_in_total_rank: nil, -# place_in_category_rank: nil, -# score: nil, -# wins_count: nil, -# games_count: nil, -# time_spent_in_seconds: nil -# }, -# %{ -# slug: "semifinal_entrance", -# entrance_result: :passed -# }, -# %{ -# slug: "semifinal", -# tournament_type: :global, -# status: :pending, -# place_in_total_rank: Enum.random(1..50), -# place_in_category_rank: Enum.random(1..25), -# score: Enum.random(10..100), -# wins_count: Enum.random(0..10), -# games_count: Enum.random(1..15), -# time_spent_in_seconds: Enum.random(100..8000) -# }, -# %{ -# slug: "final_entrance", -# entrance_result: :not_passed -# }, -# %{ -# slug: "final", -# status: :pending, -# place_in_total_rank: Enum.random(1..20), -# place_in_category_rank: Enum.random(1..10), -# score: Enum.random(20..100), -# wins_count: Enum.random(0..8), -# games_count: Enum.random(1..10), -# time_spent_in_seconds: Enum.random(100..5000) -# } -# ] -# }) diff --git a/services/app/apps/codebattle/test/codebattle/asserts_service_test.exs b/services/app/apps/codebattle/test/codebattle/asserts_service_test.exs deleted file mode 100644 index 88c5a6808..000000000 --- a/services/app/apps/codebattle/test/codebattle/asserts_service_test.exs +++ /dev/null @@ -1,130 +0,0 @@ -defmodule Codebattle.AssertsServiceTest do - use CodebattleWeb.ConnCase, async: true - - alias Codebattle.AssertsService - - describe ".valid_asserts?" do - test "integers" do - input_arguments = %{"argument-name" => "some", "name" => "integer"} - asserts = [1] - - assert AssertsService.valid_asserts?(asserts, input_arguments) - end - - test "booleans" do - input_arguments = %{"argument-name" => "some", "name" => "boolean"} - asserts = [true] - - assert AssertsService.valid_asserts?(asserts, input_arguments) - end - - test "strings" do - input_arguments = %{"argument-name" => "some", "name" => "string"} - asserts = ["some string"] - - assert AssertsService.valid_asserts?(asserts, input_arguments) - end - - test "floats" do - input_arguments = %{"argument-name" => "some", "name" => "float"} - asserts = [1.2] - - assert AssertsService.valid_asserts?(asserts, input_arguments) - end - - test "arrays" do - input_arguments = %{ - "argument-name" => "some", - "name" => "array", - "nested" => %{"name" => "integer"} - } - - asserts = [[1, 2, 3]] - - assert AssertsService.valid_asserts?(asserts, input_arguments) - end - - test "hashes" do - input_arguments = %{ - "argument-name" => "some", - "name" => "hash", - "nested" => %{"name" => "integer"} - } - - asserts = [%{"some" => 1}] - - assert AssertsService.valid_asserts?(asserts, input_arguments) - end - - test "nested arrays" do - input_arguments = %{ - "argument-name" => "some", - "name" => "array", - "nested" => %{"name" => "array", "nested" => %{"name" => "integer"}} - } - - asserts = [[[1, 2, 3]]] - - assert AssertsService.valid_asserts?(asserts, input_arguments) - end - end - - describe ".type_asserts" do - test "integers" do - asserts = [1] - - assert [%{"name" => "integer"}] == AssertsService.type_asserts(asserts) - end - - test "booleans" do - asserts = [true] - - assert [%{"name" => "boolean"}] == AssertsService.type_asserts(asserts) - end - - test "strings" do - asserts = ["some"] - - assert [%{"name" => "string"}] == AssertsService.type_asserts(asserts) - end - - test "floats" do - asserts = [1.1] - - assert [%{"name" => "float"}] == AssertsService.type_asserts(asserts) - end - - test "arrays" do - asserts = [[1, 2]] - - assert [ - %{ - "name" => "array", - "nested" => %{"name" => "integer"} - } - ] == AssertsService.type_asserts(asserts) - end - - test "hashes" do - asserts = [%{"some" => 1}] - - assert [ - %{ - "name" => "hash", - "nested" => %{"name" => "integer"} - } - ] == AssertsService.type_asserts(asserts) - end - - test "nested arrays" do - asserts = [[[1, 2, 3]]] - - assert [ - %{ - "name" => "array", - "nested" => %{"name" => "array", "nested" => %{"name" => "integer"}} - } - ] == AssertsService.type_asserts(asserts) - end - end -end diff --git a/services/app/apps/codebattle/test/codebattle/bot/playbook_player_test.exs b/services/app/apps/codebattle/test/codebattle/bot/playbook_player_test.exs deleted file mode 100644 index 9b2550804..000000000 --- a/services/app/apps/codebattle/test/codebattle/bot/playbook_player_test.exs +++ /dev/null @@ -1,165 +0,0 @@ -defmodule Codebattle.Bot.PlaybookPlayerTest do - use Codebattle.IntegrationCase, async: false - - alias Codebattle.Bot - alias Codebattle.Game - alias Codebattle.Game.Helpers - alias CodebattleWeb.GameChannel - alias CodebattleWeb.UserSocket - - test "Bot playing with user and bot wins", %{conn: conn} do - task = insert(:task, level: "easy") - user = insert(:user, %{name: "first", email: "test1@test.test", github_id: 1, rating: 1400}) - - conn = put_session(conn, :user_id, user.id) - - playbook_used_by_bot = - insert(:playbook, %{ - data: playbook_data(), - task: task, - winner_id: 2, - winner_lang: "ruby", - solution_type: "complete" - }) - - socket = socket(UserSocket, "user_id", %{user_id: user.id, current_user: user}) - - # Create game - level = "easy" - - bot = Bot.Context.build() - - {:ok, game} = - Game.Context.create_game(%{ - state: "waiting_opponent", - type: "duo", - mode: "standard", - visibility_type: "public", - level: level, - players: [bot] - }) - - game_id = game.id - game_topic = "game:#{game_id}" - - :timer.sleep(100) - - # User join to the game - post(conn, Routes.game_path(conn, :join, game_id)) - :timer.sleep(100) - - {:ok, _response, socket} = subscribe_and_join(socket, GameChannel, game_topic) - :timer.sleep(3_000) - - Phoenix.ChannelTest.push(socket, "editor:data", %{editor_text: "test", lang_slug: "js"}) - :timer.sleep(100) - - game = Game.Context.get_game!(game_id) - assert game.state == "playing" - - :timer.sleep(3_000) - # bot write_some_text - game = game.id |> Game.Context.get_game!() |> Repo.preload(user_games: [:playbook]) - bot_user_game = Enum.find(game.user_games, fn user_game -> user_game.user_id == bot.id end) - - assert Helpers.get_first_player(game).editor_text == "tes" - assert Helpers.get_second_player(game).editor_text == "test" - assert bot_user_game.playbook.id == playbook_used_by_bot.id - end - - test "Bot playing with user and bot wins with task time to solve", %{conn: conn} do - FunWithFlags.enable(:use_only_approved_playbooks) - task = insert(:task, level: "easy", time_to_solve_sec: 1) - user = insert(:user, %{name: "first", email: "test1@test.test", github_id: 1, rating: 1400}) - - conn = put_session(conn, :user_id, user.id) - - playbook_used_by_bot = - insert(:playbook, %{ - data: playbook_data(), - approved: true, - task: task, - winner_id: 2, - winner_lang: "ruby", - solution_type: "complete" - }) - - socket = socket(UserSocket, "user_id", %{user_id: user.id, current_user: user}) - - # Create game - level = "easy" - - bot = Bot.Context.build() - - {:ok, game} = - Game.Context.create_game(%{ - state: "waiting_opponent", - type: "duo", - mode: "standard", - visibility_type: "public", - level: level, - players: [bot] - }) - - game_id = game.id - game_topic = "game:#{game_id}" - - :timer.sleep(100) - - # User join to the game - post(conn, Routes.game_path(conn, :join, game_id)) - :timer.sleep(100) - - {:ok, _response, socket} = subscribe_and_join(socket, GameChannel, game_topic) - :timer.sleep(3_000) - - Phoenix.ChannelTest.push(socket, "editor:data", %{editor_text: "test", lang_slug: "js"}) - :timer.sleep(100) - - game = Game.Context.get_game!(game_id) - assert game.state == "playing" - - :timer.sleep(3_000) - # bot write_some_text - game = game.id |> Game.Context.get_game!() |> Repo.preload(user_games: [:playbook]) - bot_user_game = Enum.find(game.user_games, fn user_game -> user_game.user_id == bot.id end) - - assert Helpers.get_first_player(game).editor_text == "tes" - assert Helpers.get_second_player(game).editor_text == "test" - assert bot_user_game.playbook.id == playbook_used_by_bot.id - FunWithFlags.disable(:use_only_approved_playbooks) - end - - defp playbook_data do - %{ - players: [%{id: 2, total_time_ms: 1_000_000}], - records: [ - %{"type" => "init", "id" => 2, "editor_text" => "", "editor_lang" => "ruby"}, - %{ - "diff" => %{"delta" => [%{"insert" => "t"}], "next_lang" => "ruby", "time" => 20}, - "type" => "update_editor_data", - "id" => 2 - }, - %{ - "diff" => %{ - "delta" => [%{"retain" => 1}, %{"insert" => "e"}], - "next_lang" => "ruby", - "time" => 20 - }, - "type" => "update_editor_data", - "id" => 2 - }, - %{ - "diff" => %{ - "delta" => [%{"retain" => 2}, %{"insert" => "s"}], - "next_lang" => "ruby", - "time" => 20 - }, - "type" => "update_editor_data", - "id" => 2 - }, - %{"type" => "game_over", "id" => 2, "lang" => "ruby"} - ] - } - end -end diff --git a/services/app/apps/codebattle/test/codebattle/chat_test.exs b/services/app/apps/codebattle/test/codebattle/chat_test.exs deleted file mode 100644 index b4fef7abe..000000000 --- a/services/app/apps/codebattle/test/codebattle/chat_test.exs +++ /dev/null @@ -1,99 +0,0 @@ -defmodule Codebattle.ChatTest do - use Codebattle.DataCase - - alias Codebattle.Chat - alias Codebattle.Chat.Message - - @chat_type {:game, 198_419_841_984} - - setup do - user1 = build(:user, name: "alice") - user2 = build(:user, name: "bob") - admin = build(:admin) - - {:ok, %{user1: user1, user2: user2, admin: admin}} - end - - test "works", %{user1: %{id: user_id, name: name} = user1} do - {:ok, _pid} = Chat.start_link(@chat_type, %{clean_timeout: 50, message_ttl: 10}) - - assert %{messages: [], users: [^user1]} = Chat.join_chat(@chat_type, user1) - - assert :ok = - Chat.add_message(@chat_type, %{type: :text, text: "oi", user_id: user_id, name: name}) - - assert [ - %Message{ - id: 1, - name: ^name, - text: "oi", - time: _, - type: :text, - user_id: ^user_id - } - ] = Chat.get_messages(@chat_type) - - assert [^user1] = Chat.get_users(@chat_type) - assert [] = Chat.leave_chat(@chat_type, user1) - assert [] = Chat.get_users(@chat_type) - end - - test "cleans messages periodically", %{user1: user1, user2: user2} do - {:ok, _pid} = Chat.start_link(@chat_type, %{clean_timeout: 50, message_ttl: 10}) - - Chat.add_message(@chat_type, %{type: :text, text: "oi", user_id: user1.id, name: user1.name}) - - Chat.add_message(@chat_type, %{type: :text, text: "blz", user_id: user2.id, name: user2.name}) - - assert length(Chat.get_messages(@chat_type)) == 2 - :timer.sleep(100) - assert Enum.empty?(Chat.get_messages(@chat_type)) - end - - test "deletes messages and bans user", %{user1: user1, user2: user2, admin: admin} do - {:ok, _pid} = Chat.start_link(@chat_type, %{clean_timeout: 50, message_ttl: 10}) - - Chat.join_chat(@chat_type, user1) - Chat.join_chat(@chat_type, user2) - Chat.join_chat(@chat_type, admin) - - Chat.add_message(@chat_type, %{type: :text, text: "oi", user_id: user1.id, name: user1.name}) - Chat.add_message(@chat_type, %{type: :text, text: "blz", user_id: user2.id, name: user2.name}) - Chat.add_message(@chat_type, %{type: :text, text: "bom", user_id: admin.id, name: admin.name}) - - assert length(Chat.get_messages(@chat_type)) == 3 - - :ok = - Chat.ban_user(@chat_type, %{admin_name: admin.name, user_id: user1.id, name: user1.name}) - - assert [ - %Message{id: 2, name: "bob", text: "blz", type: :text}, - %Message{id: 3, name: "admin", text: "bom", type: :text}, - %Message{id: 4, text: "alice has been banned by admin", type: :info} - ] = Chat.get_messages(@chat_type) - - Chat.add_message(@chat_type, %{type: :text, text: "oi", user_id: user1.id, name: user1.name}) - Chat.add_message(@chat_type, %{type: :text, text: "blz", user_id: user2.id, name: user2.name}) - - assert length(Chat.get_messages(@chat_type)) == 4 - :ok = Chat.clean_banned(@chat_type) - - Chat.add_message(@chat_type, %{type: :text, text: "oi", user_id: user1.id, name: user1.name}) - Chat.add_message(@chat_type, %{type: :text, text: "blz", user_id: user2.id, name: user2.name}) - - assert length(Chat.get_messages(@chat_type)) == 6 - end - - test "catches no_chat error", %{user1: %{id: user_id, name: name} = user1} do - assert %{messages: [], users: []} = Chat.join_chat(@chat_type, user1) - assert [] = Chat.leave_chat(@chat_type, user1) - - assert :ok = - Chat.add_message(@chat_type, %{type: :text, text: "oi", user_id: user_id, name: name}) - - assert [] = Chat.get_messages(@chat_type) - assert [] = Chat.get_users(@chat_type) - assert :ok = Chat.ban_user(@chat_type, %{admin_name: name, user_id: user_id, name: name}) - assert :ok = Chat.clean_banned(@chat_type) - end -end diff --git a/services/app/apps/codebattle/test/codebattle/code_check/output_parser_v2_test.exs b/services/app/apps/codebattle/test/codebattle/code_check/output_parser_v2_test.exs deleted file mode 100644 index 83aaec0d5..000000000 --- a/services/app/apps/codebattle/test/codebattle/code_check/output_parser_v2_test.exs +++ /dev/null @@ -1,240 +0,0 @@ -defmodule Codebattle.CodeCheck.OutputParser.V2Test do - use CodebattleWeb.ConnCase, async: true - - import CodebattleWeb.Factory - - alias Codebattle.CodeCheck.OutputParser - alias Codebattle.CodeCheck.Result - alias Codebattle.CodeCheck.Result.V2 - alias Codebattle.CodeCheck.Result.V2.AssertResult - - @success_output """ - {"type":"result","time":0.0076,"value":1,"output":"asdf"} - {"type":"result","time":0.0076,"value":2,"output":"asdf"} - """ - - @success_json_output """ - [{"type":"result","time":0.0076,"value":1,"output":"asdf"}, - {"type":"result","time":0.0076,"value":2,"output":"asdf"}] - """ - - @success_with_warning """ - Warning: something warning about ;) - {"type":"result","time":0.0076,"value":1,"output":"asdf"} - """ - - @failure_output """ - {"type":"output","time":0,"value":"pre_output","output":"pre_output"} - {"type":"result","time":0.0076,"value":1,"output":"asdf"} - {"type":"result","time":0.1234,"value":2,"output":"fdsa"} - {"type":"error","time":0.1406,"value":"ErrorMessage","output":"Output"} - """ - - @failure_expected %Result.V2{ - success_count: 2, - version: 2, - asserts_count: 3, - status: "failure", - output_error: "pre_output", - asserts: [ - %AssertResult{ - arguments: "[1, 3]", - expected: "4", - output: "Output", - result: "\"ErrorMessage\"", - execution_time: 0.1406, - status: "failure" - }, - %AssertResult{ - status: "success", - execution_time: 0.0076, - result: "1", - expected: "1", - arguments: "[1, 1]", - output: "asdf" - }, - %AssertResult{ - status: "success", - execution_time: 0.1234, - result: "2", - expected: "2", - arguments: "[2, 2]", - output: "fdsa" - } - ] - } - - @success_expected %Result.V2{ - asserts_count: 2, - output_error: "", - status: "ok", - success_count: 2, - asserts: [ - %AssertResult{ - arguments: "[1, 1]", - execution_time: 0.0076, - expected: "1", - output: "asdf", - result: "1", - status: "success" - }, - %AssertResult{ - arguments: "[2, 1]", - expected: "2", - result: "2", - output: "asdf", - execution_time: 0.0076, - status: "success" - } - ] - } - - @success_with_warning_expected %Result.V2{ - asserts_count: 1, - output_error: "", - status: "ok", - success_count: 1, - asserts: [ - %AssertResult{ - status: "success", - execution_time: 0.0076, - result: "1", - expected: "1", - arguments: "[1, 1]", - output: "asdf" - } - ] - } - - test "parses success output" do - task = - insert(:task, - asserts: [%{arguments: [1, 1], expected: 1}, %{arguments: [2, 1], expected: 2}] - ) - - result = - OutputParser.V2.call(%{ - task: task, - container_stderr: "", - container_output: @success_output, - exit_code: 0 - }) - - assert result == @success_expected - end - - test "parses success json output" do - task = - insert(:task, - asserts: [%{arguments: [1, 1], expected: 1}, %{arguments: [2, 1], expected: 2}] - ) - - result = - OutputParser.V2.call(%{ - task: task, - container_stderr: "", - container_output: @success_json_output, - exit_code: 0 - }) - - assert result == @success_expected - end - - test "parses success with warning output" do - task = insert(:task, asserts: [%{arguments: [1, 1], expected: 1}]) - - result = - OutputParser.V2.call(%{ - task: task, - container_stderr: "", - container_output: @success_with_warning, - exit_code: 0 - }) - - assert result == @success_with_warning_expected - end - - test "parses failure output" do - task = - insert(:task, - asserts: [ - %{arguments: [1, 1], expected: 1}, - %{arguments: [2, 2], expected: 2}, - %{arguments: [1, 3], expected: 4} - ] - ) - - result = - OutputParser.V2.call(%{ - task: task, - container_stderr: "", - container_output: @failure_output, - exit_code: 0 - }) - - assert result == @failure_expected - end - - test "parses out of memory error output" do - task = insert(:task) - - result = - OutputParser.V2.call(%{ - task: task, - container_stderr: "", - container_output: "make *** failed: Killed\n", - exit_code: 2 - }) - - assert result == %V2{ - asserts: [], - exit_code: 2, - asserts_count: 1, - output_error: "Your solution ran out of memory, please, rewrite it", - status: "error", - success_count: 0 - } - end - - test "parses out timeout termination" do - task = insert(:task) - - result = - OutputParser.V2.call(%{ - task: task, - container_stderr: "", - container_output: "SIGTERM\n", - exit_code: 143 - }) - - assert result == %V2{ - asserts: [], - exit_code: 143, - asserts_count: 1, - output_error: "Your solution was executed for longer than 15 seconds, try to write more optimally", - status: "error", - success_count: 0 - } - end - - test "parses unexpected termination" do - task = insert(:task) - - result = - OutputParser.V2.call(%{ - task: task, - container_stderr: "lolkek", - container_output: "asdf", - exit_code: 37 - }) - - assert %V2{ - asserts: [], - exit_code: 37, - asserts_count: 1, - output_error: "STDERR: lolkek\n\nSTDOUT: asdf\n", - status: "error", - success_count: 0 - } == result - end -end diff --git a/services/app/apps/codebattle/test/codebattle/game/context_test.exs b/services/app/apps/codebattle/test/codebattle/game/context_test.exs deleted file mode 100644 index 91bb95522..000000000 --- a/services/app/apps/codebattle/test/codebattle/game/context_test.exs +++ /dev/null @@ -1,80 +0,0 @@ -defmodule Codebattle.Game.ContextTest do - use Codebattle.DataCase - - alias Codebattle.Game.Player - alias Codebattle.PubSub.Message - - describe "trigger_timeout/1" do - setup do - user1 = insert(:user, rating: 1001) - user2 = insert(:user, rating: 1002) - task = insert(:task) - Codebattle.PubSub.subscribe("games") - - {:ok, %{user1: user1, user2: user2, task: task}} - end - - test "changes state and broadcasts events", %{user1: user1, user2: user2} do - {:ok, %{id: game_id, players: [%{id: user1_id}, %{id: user2_id}]}} = - Game.Context.create_game(%{state: "playing", players: [user1, user2], level: "easy"}) - - assert_received %Message{ - event: "game:created", - topic: "games", - payload: _ - } - - game_topic = "game:#{game_id}" - Codebattle.PubSub.subscribe(game_topic) - - :ok = Game.Context.trigger_timeout(game_id) - - assert_received %Message{ - event: "game:finished", - topic: "games", - payload: %{ - game_id: ^game_id, - game_state: "timeout", - game: %{id: ^game_id, players: [%{id: ^user1_id}, %{id: ^user2_id}], state: "timeout"} - } - } - - assert_received %Message{ - event: "game:finished", - topic: ^game_topic, - payload: %{game_id: ^game_id, game_state: "timeout"} - } - end - end - - describe "fetch_score_by_game_id/1" do - test "works" do - user1 = insert(:user) - user2 = insert(:user) - players = [Player.build(user1), Player.build(user2)] - - game1 = insert(:game, state: "game_over", players: players) - insert(:user_game, user: user1, creator: false, game: game1, result: "won") - insert(:user_game, user: user2, creator: true, game: game1, result: "gave_up") - game2 = insert(:game, state: "game_over", players: players) - insert(:user_game, user: user2, creator: true, game: game2, result: "won") - insert(:user_game, user: user1, creator: false, game: game2, result: "lost") - game3 = insert(:game, state: "playing", players: players) - insert(:user_game, user: user1, creator: false, game: game3, result: nil) - insert(:user_game, user: user2, creator: true, game: game3, result: nil) - game4 = insert(:game, state: "game_over", players: players) - insert(:user_game, user: user1, creator: false, game: game4, result: "won") - insert(:user_game, user: user2, creator: true, game: game4, result: "lost") - - assert %{ - game_results: [ - %{game_id: game1.id, inserted_at: game1.inserted_at, winner_id: user1.id}, - %{game_id: game2.id, inserted_at: game2.inserted_at, winner_id: user2.id}, - %{game_id: game4.id, inserted_at: game4.inserted_at, winner_id: user1.id} - ], - player_results: %{to_string(user2.id) => 1, to_string(user1.id) => 2}, - winner_id: user1.id - } == Game.Context.fetch_score_by_game_id(game3.id) - end - end -end diff --git a/services/app/apps/codebattle/test/codebattle/tasks_importer_test.exs b/services/app/apps/codebattle/test/codebattle/tasks_importer_test.exs deleted file mode 100644 index 3d804ecf0..000000000 --- a/services/app/apps/codebattle/test/codebattle/tasks_importer_test.exs +++ /dev/null @@ -1,116 +0,0 @@ -defmodule Codebattle.TasksImporterTest do - use CodebattleWeb.ConnCase - - alias Codebattle.Repo - alias Codebattle.Task - - @root_dir File.cwd!() - - setup do - path = Path.join(@root_dir, "test/support/fixtures/issues") - - issue_names = - path - |> File.ls!() - |> MapSet.new(fn file_name -> - file_name - |> String.split(".") - |> List.first() - end) - - {:ok, %{path: path, issue_names: issue_names}} - end - - test "uploads fixtures to database", %{ - path: path, - issue_names: issue_names - } do - Codebattle.TasksImporter.upsert([path]) - - task_names = - Task - |> Repo.all() - |> MapSet.new(fn task -> task.name end) - - assert MapSet.equal?(task_names, issue_names) - end - - test "is idempotent", %{path: path, issue_names: issue_names} do - Codebattle.TasksImporter.upsert([path]) - Codebattle.TasksImporter.upsert([path]) - - task_names = - Task - |> Repo.all() - |> MapSet.new(fn task -> task.name end) - - assert MapSet.equal?(task_names, issue_names) - end - - test "is correct signature", %{path: path, issue_names: _issue_names} do - Codebattle.TasksImporter.upsert([path]) - - task_signatures = - Task - |> Repo.all() - |> Enum.map(fn task -> - %{"input" => task.input_signature, "output" => task.output_signature} - end) - - assert task_signatures == - [ - %{ - "input" => [%{argument_name: "num", type: %{name: "integer"}}], - "output" => %{type: %{name: "integer"}} - } - ] - end - - test "respects disabled" do - path = Path.join(@root_dir, "test/support/fixtures/issues_with_disabled") - Codebattle.TasksImporter.upsert([path]) - - assert Task |> Repo.all() |> Enum.count() == 2 - - assert Task |> Task.visible() |> Repo.all() |> Enum.count() == 1 - end - - test "update fields", %{path: path} do - new_path = Path.join(@root_dir, "test/support/fixtures/new_issues") - - Codebattle.TasksImporter.upsert([path]) - - task = Task |> Repo.all() |> List.first() - - assert task.name == "asserts" - assert task.description_en == "description" - assert task.level == "medium" - assert task.state == "active" - assert task.visibility == "public" - assert task.origin == "github" - assert task.creator_id == nil - assert task.input_signature == [%{argument_name: "num", type: %{name: "integer"}}] - assert task.output_signature == %{type: %{name: "integer"}} - assert Enum.count(task.asserts) == 20 - - Codebattle.TasksImporter.upsert([new_path]) - - updated = Repo.get(Task, task.id) - - assert updated.name == "asserts" - assert updated.state == "disabled" - assert updated.visibility == "public" - assert updated.origin == "github" - assert updated.creator_id == nil - assert updated.description_en == "new_description" - assert updated.level == "easy" - - assert updated.input_signature == [ - %{argument_name: "str", type: %{name: "string"}} - ] - - assert updated.output_signature == %{type: %{name: "string"}} - assert Enum.count(updated.asserts) == 1 - assert updated.id == task.id - end -end diff --git a/services/app/apps/codebattle/test/codebattle/tournament/arena_test.exs b/services/app/apps/codebattle/test/codebattle/tournament/arena_test.exs deleted file mode 100644 index 97cd308ad..000000000 --- a/services/app/apps/codebattle/test/codebattle/tournament/arena_test.exs +++ /dev/null @@ -1,61 +0,0 @@ -defmodule Codebattle.Tournament.ArenaTest do - use Codebattle.DataCase, async: false - - import Codebattle.Tournament.Helpers - - alias Codebattle.Tournament - - setup do - tasks = insert_list(3, :task, level: "easy") - insert(:task_pack, name: "tp", task_ids: Enum.map(tasks, & &1.id)) - - :ok - end - - test "add bots to games" do - user1 = insert(:user) - - {:ok, tournament} = - Tournament.Context.create(%{ - "starts_at" => "2022-02-24T06:00", - "name" => "Test Swiss", - "user_timezone" => "Etc/UTC", - "level" => "easy", - "task_pack_name" => "tp", - "creator" => user1, - "break_duration_seconds" => 0, - "task_provider" => "task_pack_per_round", - "task_strategy" => "sequential", - "ranking_type" => "by_clan", - "type" => "arena", - "state" => "waiting_participants", - "use_clan" => "true", - "rounds_limit" => "3", - "players_limit" => 200 - }) - - Tournament.Server.handle_event(tournament.id, :join, %{user: user1}) - Tournament.Server.handle_event(tournament.id, :start, %{user: user1}) - - tournament = Tournament.Context.get(tournament.id) - - assert players_count(tournament) == 2 - - assert [ - %{ - duration_sec: nil, - finished_at: nil, - game_id: _, - id: 0, - level: "easy", - player_ids: [_, _], - player_results: %{}, - round_id: _, - round_position: 0, - started_at: ~N[2019-01-05 19:11:45], - state: "playing", - winner_id: nil - } - ] = get_matches(tournament) - end -end diff --git a/services/app/apps/codebattle/test/codebattle/tournament/entire/arena_clan_seq_task_win_loss_test.exs b/services/app/apps/codebattle/test/codebattle/tournament/entire/arena_clan_seq_task_win_loss_test.exs deleted file mode 100644 index 820b2e283..000000000 --- a/services/app/apps/codebattle/test/codebattle/tournament/entire/arena_clan_seq_task_win_loss_test.exs +++ /dev/null @@ -1,660 +0,0 @@ -defmodule Codebattle.Tournament.Entire.ArenaClanSeqTaskWinLossTest do - use Codebattle.DataCase, async: false - - import Codebattle.Tournament.Helpers - import Codebattle.TournamentTestHelpers - - alias Codebattle.Event.EventClanResult - alias Codebattle.Event.EventResult - alias Codebattle.PubSub.Message - alias Codebattle.Repo - alias Codebattle.Tournament - alias Codebattle.Tournament.TournamentResult - - @decimal100 Decimal.new("100.0") - - @tag :skip - test "works with several players and single round" do - [%{id: t1_id}, %{id: t2_id}, %{id: t3_id}] = insert_list(3, :task, level: "easy") - insert(:task_pack, name: "tp", task_ids: [t1_id, t2_id, t3_id]) - - event = %{id: e_id} = insert(:event) - creator = insert(:user) - user1 = %{id: u1_id} = insert(:user, %{clan_id: 1, clan: "1", name: "1"}) - user2 = %{id: u2_id} = insert(:user, %{clan_id: 1, clan: "1", name: "2"}) - user3 = insert(:user, %{clan_id: 2, clan: "3", name: "3"}) - user4 = insert(:user, %{clan_id: 3, clan: "4", name: "4"}) - user5 = insert(:user, %{clan_id: 4, clan: "5", name: "5"}) - user6 = insert(:user, %{clan_id: 5, clan: "6", name: "6"}) - user7 = insert(:user, %{clan_id: 6, clan: "7", name: "7"}) - user8 = insert(:user, %{clan_id: 7, clan: "8", name: "8"}) - - {:ok, tournament} = - Tournament.Context.create(%{ - "starts_at" => "2022-02-24T06:00", - "name" => "Test Clan Arena", - "event_id" => to_string(event.id), - "user_timezone" => "Etc/UTC", - "level" => "easy", - "task_pack_name" => "tp", - "creator" => creator, - "break_duration_seconds" => 0, - "task_provider" => "task_pack_per_round", - "score_strategy" => "win_loss", - "task_strategy" => "sequential", - "ranking_type" => "by_clan", - "type" => "arena", - "state" => "waiting_participants", - "use_clan" => "true", - "rounds_limit" => "1", - "players_limit" => 200 - }) - - users = [%{id: p1_id} = user1, %{id: p2_id} = user2, user3, user4, user5, user6, user7, user8] - - admin_topic = tournament_admin_topic(tournament.id) - common_topic = tournament_common_topic(tournament.id) - player1_topic = tournament_player_topic(tournament.id, p1_id) - player2_topic = tournament_player_topic(tournament.id, p2_id) - - Codebattle.PubSub.subscribe(admin_topic) - Codebattle.PubSub.subscribe(common_topic) - Codebattle.PubSub.subscribe(player1_topic) - Codebattle.PubSub.subscribe(player2_topic) - - Tournament.Server.handle_event(tournament.id, :join, %{users: users}) - - Enum.each(users, fn %{id: id, name: name} -> - assert_received %Message{ - topic: ^common_topic, - event: "tournament:player:joined", - payload: %{player: %{name: ^name, id: ^id, state: "active"}} - } - end) - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - Tournament.Server.handle_event(tournament.id, :start, %{ - user: creator, - time_step_ms: 20_000, - min_time_sec: 0 - }) - - assert_received %Message{ - topic: ^admin_topic, - event: "tournament:updated", - payload: %{ - tournament: %{ - state: "active", - current_round_position: 0, - break_state: "off", - last_round_ended_at: nil, - last_round_started_at: _ - } - } - } - - assert_received %Message{ - topic: ^common_topic, - event: "tournament:round_created", - payload: %{ - tournament: %{ - state: "active", - current_round_position: 0, - break_state: "off", - last_round_ended_at: nil, - last_round_started_at: _ - } - } - } - - assert_received %Message{ - topic: ^player1_topic, - event: "waiting_room:player:match_created", - payload: %{ - current_player: %{ - id: ^p1_id, - state: "active", - task_ids: [^t1_id], - score: 0, - wins_count: 0, - place: 0 - }, - match: %{state: "playing"}, - players: [%{}, %{}] - } - } - - assert_received %Message{ - topic: ^player2_topic, - event: "waiting_room:player:match_created", - payload: %{ - current_player: %{ - id: ^p2_id, - state: "active", - task_ids: [^t1_id], - score: 0, - wins_count: 0, - place: 0 - }, - match: %{state: "playing"}, - players: [%{}, %{}] - } - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - tournament = Tournament.Context.get(tournament.id) - matches = get_matches(tournament) - - assert players_count(tournament) == 8 - assert Enum.count(matches) == 4 - - assert %{ - entries: [ - %{score: 0, place: 1}, - %{score: 0, place: 2}, - %{score: 0, place: 3}, - %{score: 0, place: 4}, - %{score: 0, place: 5}, - %{score: 0, place: 6}, - %{score: 0, place: 7} - ] - } = Tournament.Ranking.get_page(tournament, 1) - - win_active_match(tournament, user1) - :timer.sleep(100) - - assert %{ - entries: [ - %{score: 3, place: 1, id: 1, players_count: 2}, - %{score: 1, place: 2, players_count: 1}, - %{score: 0, place: 3}, - %{score: 0, place: 4}, - %{score: 0, place: 5}, - %{score: 0, place: 6}, - %{score: 0, place: 7} - ] - } = Tournament.Ranking.get_page(tournament, 1) - - assert_received %Message{ - topic: ^player1_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{state: "game_over"}, - players: [%{}, %{}] - } - } - - assert_received %Message{ - topic: ^player1_topic, - event: "waiting_room:player:matchmaking_started", - payload: %{ - current_player: %{ - id: ^p1_id, - state: "matchmaking_active", - task_ids: [^t1_id], - score: 3, - wins_count: 1, - place: 0 - } - } - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - win_active_match(tournament, user2) - :timer.sleep(100) - - assert %{ - entries: [ - %{score: 6, place: 1, id: 1, players_count: 2}, - %{score: 1, place: 2, players_count: 1}, - %{score: 1, place: 3, players_count: 1}, - %{score: 0, place: 4}, - %{score: 0, place: 5}, - %{score: 0, place: 6}, - %{score: 0, place: 7} - ] - } = Tournament.Ranking.get_page(tournament, 1) - - assert_received %Message{ - topic: ^player2_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{state: "game_over"}, - players: [%{}, %{}] - } - } - - assert_received %Message{ - topic: ^player2_topic, - event: "waiting_room:player:matchmaking_started", - payload: %{ - current_player: %{ - id: ^p2_id, - state: "matchmaking_active", - task_ids: [^t1_id], - score: 3, - wins_count: 1, - place: 0 - } - } - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - tournament = Tournament.Context.get(tournament.id) - - players = Tournament.Players.get_players(tournament, "matchmaking_active") - assert Enum.count(players) == 4 - - Tournament.Server.match_waiting_room_players(tournament.id) - :timer.sleep(100) - players = Tournament.Players.get_players(tournament, "matchmaking_active") - assert Enum.empty?(players) - - assert_received %Message{ - topic: ^player1_topic, - event: "waiting_room:player:match_created", - payload: %{ - current_player: %{ - id: ^p1_id, - state: "active", - task_ids: [^t2_id, ^t1_id], - score: 3, - wins_count: 1, - place: 0 - }, - match: %{state: "playing"}, - players: [%{}, %{}] - } - } - - assert_received %Message{ - topic: ^player2_topic, - event: "waiting_room:player:match_created", - payload: %{ - current_player: %{ - id: ^p2_id, - state: "active", - task_ids: [^t2_id, ^t1_id], - score: 3, - wins_count: 1, - place: 0 - }, - match: %{state: "playing"}, - players: [%{}, %{}] - } - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - :timer.sleep(100) - matches = get_matches(tournament) - - assert Enum.count(matches) == 6 - - win_active_match(tournament, user1) - :timer.sleep(100) - - assert %{ - entries: [ - %{score: 9, place: 1, id: 1, players_count: 2}, - %{score: 2, place: 2, players_count: 1}, - %{score: 1, place: 3, players_count: 1}, - %{score: 0, place: 4}, - %{score: 0, place: 5}, - %{score: 0, place: 6}, - %{score: 0, place: 7} - ] - } = Tournament.Ranking.get_page(tournament, 1) - - assert_received %Message{ - topic: ^player1_topic, - event: "tournament:match:upserted", - payload: %{match: %{state: "game_over"}, players: [%{}, %{}]} - } - - assert_received %Message{ - topic: ^player1_topic, - event: "waiting_room:player:matchmaking_started", - payload: %{ - current_player: %{ - id: ^p1_id, - state: "matchmaking_active", - task_ids: [^t2_id, ^t1_id], - score: 6, - wins_count: 2, - place: 0 - } - } - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - tournament = Tournament.Context.get(tournament.id) - players = Tournament.Players.get_players(tournament, "matchmaking_active") - assert Enum.count(players) == 2 - - Tournament.Server.update_waiting_room_state(tournament.id, %{ - min_time_with_bot_sec: 0, - min_time_with_played_sec: 0 - }) - - Tournament.Server.match_waiting_room_players(tournament.id) - :timer.sleep(100) - players = Tournament.Players.get_players(tournament, "matchmaking_active") - assert Enum.empty?(players) - - assert_received %Message{ - topic: ^player1_topic, - event: "waiting_room:player:match_created", - payload: %{ - current_player: %{ - id: ^p1_id, - state: "active", - task_ids: [^t3_id, ^t2_id, ^t1_id], - score: 6, - wins_count: 2, - place: 0 - }, - match: %{state: "playing"}, - players: [%{}, %{}] - } - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - win_active_match(tournament, user1) - :timer.sleep(200) - - assert %{ - entries: [ - %{score: 12, place: 1, id: 1, players_count: 2}, - %{score: 3, place: 2, players_count: 1}, - %{score: 1, place: 3, players_count: 1}, - %{score: 0, place: 4}, - %{score: 0, place: 5}, - %{score: 0, place: 6}, - %{score: 0, place: 7} - ] - } = Tournament.Ranking.get_page(tournament, 1) - - assert_received %Message{ - topic: ^player1_topic, - event: "waiting_room:player:matchmaking_stopped", - payload: %{ - current_player: %{ - id: ^p1_id, - state: "finished_round", - task_ids: [^t3_id, ^t2_id, ^t1_id], - score: 9, - wins_count: 3, - place: 0 - } - } - } - - assert_received %Message{ - topic: ^player1_topic, - event: "tournament:match:upserted", - payload: %{match: %{state: "game_over"}} - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - matches = get_matches(tournament) - - assert Enum.count(matches) == 7 - - assert tournament.current_round_position == 0 - Tournament.Server.finish_round_after(tournament.id, tournament.current_round_position, 0) - :timer.sleep(100) - - assert_received %Message{ - topic: ^player1_topic, - event: "waiting_room:ended", - payload: %{ - current_player: %{ - id: ^p1_id, - state: "finished", - task_ids: [^t3_id, ^t2_id, ^t1_id], - score: 9, - wins_count: 3, - place: 0 - } - } - } - - assert_received %Message{ - topic: ^player2_topic, - event: "waiting_room:ended", - payload: %{ - current_player: %{ - id: ^p2_id, - state: "finished", - task_ids: [^t2_id, ^t1_id], - score: 4, - wins_count: 1, - place: 0 - } - } - } - - assert_received %Message{ - topic: ^player2_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{state: "timeout"}, - players: [%{}, %{}] - } - } - - assert_received %Message{ - topic: ^common_topic, - event: "tournament:round_finished", - payload: %{ - tournament: %{ - type: "arena", - state: "active", - current_round_position: 0, - break_state: "on", - last_round_ended_at: _, - last_round_started_at: _, - show_results: true - } - } - } - - assert_received %Message{ - topic: ^admin_topic, - event: "tournament:updated", - payload: %{ - tournament: %{ - type: "arena", - state: "active", - current_round_position: 0, - break_state: "on", - last_round_ended_at: _, - last_round_started_at: _, - show_results: true - } - } - } - - assert_received %Message{ - topic: ^common_topic, - event: "tournament:finished", - payload: %{ - tournament: %{ - type: "arena", - state: "finished", - current_round_position: 0, - break_state: "off", - last_round_ended_at: _, - last_round_started_at: _, - show_results: true - } - } - } - - assert_received %Message{ - topic: ^admin_topic, - event: "tournament:updated", - payload: %{ - tournament: %{ - type: "arena", - state: "finished", - current_round_position: 0, - break_state: "off", - last_round_ended_at: _, - last_round_started_at: _, - show_results: true - } - } - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - assert %{ - entries: [ - %{id: 1, place: 1, players_count: 2, score: 13}, - %{place: 2, players_count: 1}, - %{place: 3, players_count: 1}, - %{place: 4, players_count: 1}, - %{place: 5, players_count: 1}, - %{place: 6, players_count: 1}, - %{place: 7, players_count: 1} - ] - } = Tournament.Ranking.get_page(tournament, 1) - - tournament = Tournament.Context.get(tournament.id) - - assert tournament.current_round_position == 0 - matches = get_matches(tournament) - - assert Enum.count(matches) == 7 - - assert %{ - entries: [ - %{id: 1, place: 1, players_count: 2, score: 13}, - %{place: 2, players_count: 1}, - %{place: 3, players_count: 1}, - %{place: 4, players_count: 1}, - %{place: 5, players_count: 1}, - %{place: 6, players_count: 1}, - %{place: 7, players_count: 1} - ], - page_number: 1, - page_size: 10, - total_entries: 7 - } = Tournament.Ranking.get_page(tournament, 1) - - tournament_id = tournament.id - - assert [ - %{ - score: 3, - clan_id: 1, - duration_sec: 0, - game_id: _, - id: _, - level: "easy", - result_percent: @decimal100, - task_id: ^t1_id, - tournament_id: ^tournament_id, - user_id: ^u1_id, - user_name: "1" - }, - %{ - score: 3, - clan_id: 1, - duration_sec: 0, - game_id: _, - id: _, - level: "easy", - result_percent: @decimal100, - task_id: ^t2_id, - tournament_id: ^tournament_id, - user_id: ^u1_id, - user_name: "1" - }, - %{ - score: 3, - clan_id: 1, - duration_sec: 0, - game_id: _, - id: _, - level: "easy", - result_percent: @decimal100, - task_id: ^t3_id, - tournament_id: ^tournament_id, - user_id: ^u1_id, - user_name: "1" - }, - %{ - score: 3, - clan_id: 1, - duration_sec: 0, - game_id: _, - id: _, - level: "easy", - result_percent: @decimal100, - task_id: ^t1_id, - tournament_id: ^tournament_id, - user_id: ^u2_id, - user_name: "2" - }, - %{}, - %{}, - %{}, - %{}, - %{}, - %{}, - %{}, - %{}, - %{}, - %{} - ] = TournamentResult |> Repo.all() |> Enum.sort_by(&{&1.user_id, &1.task_id}) - - assert [ - %{id: _, event_id: ^e_id, clan_id: 1, players_count: 2, place: 1, score: 13}, - %{id: _, event_id: ^e_id, players_count: 1, place: 2}, - %{id: _, event_id: ^e_id, players_count: 1}, - %{id: _, event_id: ^e_id, players_count: 1}, - %{id: _, event_id: ^e_id, players_count: 1}, - %{id: _, event_id: ^e_id, players_count: 1}, - %{id: _, event_id: ^e_id, players_count: 1} - ] = EventClanResult |> Repo.all() |> Enum.sort_by(&{&1.place, &1.clan_id}) - - assert [ - %{ - id: _, - event_id: ^e_id, - clan_id: 1, - user_id: ^u1_id, - user_name: "1", - clan_place: 1, - place: 1, - score: 9 - }, - %{ - id: _, - event_id: ^e_id, - clan_id: 1, - user_id: ^u2_id, - user_name: "2", - clan_place: 2, - place: 2, - score: 4 - }, - %{id: _, event_id: ^e_id, clan_place: 1}, - %{id: _, event_id: ^e_id, clan_place: 1}, - %{id: _, event_id: ^e_id, clan_place: 1}, - %{id: _, event_id: ^e_id, clan_place: 1}, - %{id: _, event_id: ^e_id, clan_place: 1}, - %{id: _, event_id: ^e_id, clan_place: 1} - ] = EventResult |> Repo.all() |> Enum.sort_by(&{&1.place, &1.clan_id}) - end -end diff --git a/services/app/apps/codebattle/test/codebattle/tournament/entire/arena_personal_with_clan_seq_task_95_percentile_test.exs b/services/app/apps/codebattle/test/codebattle/tournament/entire/arena_personal_with_clan_seq_task_95_percentile_test.exs deleted file mode 100644 index 1de68011c..000000000 --- a/services/app/apps/codebattle/test/codebattle/tournament/entire/arena_personal_with_clan_seq_task_95_percentile_test.exs +++ /dev/null @@ -1,1136 +0,0 @@ -defmodule Codebattle.Tournament.Entire.ArenaPersonalWithClanSeqTask95PercentTest do - use Codebattle.DataCase, async: false - - import Codebattle.Tournament.Helpers - import Codebattle.TournamentTestHelpers - - alias Codebattle.Event.EventResult - alias Codebattle.PubSub.Message - alias Codebattle.Repo - alias Codebattle.Tournament - alias Codebattle.Tournament.Ranking.UpdateFromResultsServer - alias Codebattle.Tournament.TournamentResult - - @tag :skip - test "works with several players and single round" do - [%{id: t1_id}, %{id: t2_id}, %{id: t3_id}] = insert_list(3, :task, level: "easy") - [%{id: t4_id}, %{id: t5_id}] = insert_list(2, :task, level: "medium") - [%{id: t6_id}] = insert_list(1, :task, level: "hard") - insert(:task_pack, name: "tp1", task_ids: [t1_id, t2_id, t3_id]) - insert(:task_pack, name: "tp2", task_ids: [t4_id, t5_id]) - insert(:task_pack, name: "tp3", task_ids: [t6_id]) - - [ - %{id: c1_id}, - %{id: c2_id}, - %{id: c3_id}, - %{id: c4_id}, - %{id: c5_id}, - %{id: c6_id}, - %{id: c7_id} - ] = - Enum.map(1..7, fn i -> - insert(:clan, %{name: to_string(i)}) - end) - - event = %{id: e_id} = insert(:event) - creator = insert(:user) - user1 = %{id: u1_id} = insert(:user, %{clan_id: c1_id, clan: "1", name: "1"}) - user2 = %{id: u2_id} = insert(:user, %{clan_id: c1_id, clan: "1", name: "2"}) - user3 = insert(:user, %{clan_id: c2_id, clan: "2", name: "3"}) - user4 = insert(:user, %{clan_id: c3_id, clan: "3", name: "4"}) - user5 = insert(:user, %{clan_id: c4_id, clan: "4", name: "5"}) - user6 = insert(:user, %{clan_id: c5_id, clan: "5", name: "6"}) - user7 = insert(:user, %{clan_id: c6_id, clan: "6", name: "7"}) - user8 = insert(:user, %{clan_id: c7_id, clan: "7", name: "8"}) - - {:ok, tournament} = - Tournament.Context.create(%{ - "starts_at" => "2022-02-24T06:00", - "name" => "Test Personal Clan Arena", - "event_id" => to_string(event.id), - "user_timezone" => "Etc/UTC", - "level" => "easy", - "task_pack_name" => "tp1,tp2,tp3", - "creator" => creator, - "break_duration_seconds" => 100, - "task_provider" => "task_pack_per_round", - "score_strategy" => "win_loss", - "task_strategy" => "sequential", - "ranking_type" => "by_player_95th_percentile", - "type" => "arena", - "state" => "waiting_participants", - "use_clan" => "true", - "rounds_limit" => "3", - "players_limit" => 200 - }) - - users = [%{id: p1_id} = user1, %{id: p2_id} = user2, user3, user4, user5, user6, user7, user8] - - admin_topic = tournament_admin_topic(tournament.id) - common_topic = tournament_common_topic(tournament.id) - player1_topic = tournament_player_topic(tournament.id, p1_id) - player2_topic = tournament_player_topic(tournament.id, p2_id) - - Codebattle.PubSub.subscribe(admin_topic) - Codebattle.PubSub.subscribe(common_topic) - Codebattle.PubSub.subscribe(player1_topic) - Codebattle.PubSub.subscribe(player2_topic) - - Tournament.Server.handle_event(tournament.id, :join, %{users: users}) - - Enum.each(users, fn %{id: id, name: name} -> - assert_received %Message{ - topic: ^common_topic, - event: "tournament:player:joined", - payload: %{player: %{name: ^name, id: ^id, state: "active"}} - } - end) - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - Tournament.Server.handle_event(tournament.id, :start, %{ - user: creator, - time_step_ms: 20_000, - min_time_sec: 0 - }) - - assert_received %Message{ - topic: ^admin_topic, - event: "tournament:updated", - payload: %{ - tournament: %{ - state: "active", - current_round_position: 0, - break_state: "off", - last_round_ended_at: nil, - last_round_started_at: _ - } - } - } - - assert_received %Message{ - topic: ^common_topic, - event: "tournament:round_created", - payload: %{ - tournament: %{ - state: "active", - current_round_position: 0, - break_state: "off", - last_round_ended_at: nil, - last_round_started_at: _ - } - } - } - - assert_received %Message{ - topic: ^player1_topic, - event: "waiting_room:player:match_created", - payload: %{ - current_player: %{ - id: ^p1_id, - state: "active", - task_ids: [^t1_id], - score: 0, - wins_count: 0, - place: 0 - }, - match: %{state: "playing"}, - players: [%{}, %{}] - } - } - - assert_received %Message{ - topic: ^player2_topic, - event: "waiting_room:player:match_created", - payload: %{ - current_player: %{ - id: ^p2_id, - state: "active", - task_ids: [^t1_id], - score: 0, - wins_count: 0, - place: 0 - }, - match: %{state: "playing"}, - players: [%{}, %{}] - } - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - tournament = Tournament.Context.get(tournament.id) - matches = get_matches(tournament) - - assert players_count(tournament) == 8 - assert Enum.count(matches) == 4 - - assert %{ - entries: [ - %{id: _, name: _, score: 0, clan: _, place: 1, clan_id: _}, - %{id: _, name: _, score: 0, clan: _, place: 2, clan_id: _}, - %{id: _, name: _, score: 0, clan: _, place: 3, clan_id: _}, - %{id: _, name: _, score: 0, clan: _, place: 4, clan_id: _}, - %{id: _, name: _, score: 0, clan: _, place: 5, clan_id: _}, - %{id: _, name: _, score: 0, clan: _, place: 6, clan_id: _}, - %{id: _, name: _, score: 0, clan: _, place: 7, clan_id: _}, - %{id: _, name: _, score: 0, clan: _, place: 8, clan_id: _} - ] - } = Tournament.Ranking.get_page(tournament, 1) - - ##### user1 win 1 round 1 game - win_active_match(tournament, user1, %{opponent_percent: 33}) - - :timer.sleep(100) - UpdateFromResultsServer.update(tournament) - - assert %{ - entries: [ - %{id: ^u1_id, place: 1, score: 100}, - %{place: 2, score: 33}, - %{id: _, name: _, score: 0, clan: _, clan_id: _, place: 3}, - %{id: _, name: _, score: 0, clan: _, clan_id: _, place: 4}, - %{id: _, name: _, score: 0, clan: _, clan_id: _, place: 5}, - %{id: _, name: _, score: 0, clan: _, clan_id: _, place: 6}, - %{id: _, name: _, score: 0, clan: _, clan_id: _, place: 7}, - %{id: _, name: _, score: 0, clan: _, clan_id: _, place: 8} - ] - } = Tournament.Ranking.get_page(tournament, 1) - - assert_received %Message{ - topic: ^player1_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{state: "game_over"}, - players: [%{}, %{}] - } - } - - assert_received %Message{ - topic: ^player1_topic, - event: "waiting_room:player:matchmaking_started", - payload: %{ - current_player: %{ - id: ^p1_id, - state: "matchmaking_active", - task_ids: [^t1_id], - score: 3, - wins_count: 1, - place: 0 - } - } - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - ##### user2 win 1 round 1 game - win_active_match(tournament, user2, %{opponent_percent: 66}) - :timer.sleep(100) - - UpdateFromResultsServer.update(tournament) - - assert %{ - entries: [ - %{place: 1, score: 100}, - %{place: 2, score: 100}, - %{place: 3, score: 67}, - %{place: 4, score: 33}, - %{id: _, name: _, score: 0, clan: _, clan_id: _, place: 5}, - %{id: _, name: _, score: 0, clan: _, clan_id: _, place: 6}, - %{id: _, name: _, score: 0, clan: _, clan_id: _, place: 7}, - %{id: _, name: _, score: 0, clan: _, clan_id: _, place: 8} - ] - } = Tournament.Ranking.get_page(tournament, 1) - - assert_received %Message{ - topic: ^player2_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{state: "game_over"}, - players: [%{}, %{}] - } - } - - assert_received %Message{ - topic: ^player2_topic, - event: "waiting_room:player:matchmaking_started", - payload: %{ - current_player: %{ - id: ^p2_id, - state: "matchmaking_active", - task_ids: [^t1_id], - score: 3, - wins_count: 1, - place: 0 - } - } - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - tournament = Tournament.Context.get(tournament.id) - - players = Tournament.Players.get_players(tournament, "matchmaking_active") - assert Enum.count(players) == 4 - - Tournament.Server.match_waiting_room_players(tournament.id) - :timer.sleep(100) - - players = Tournament.Players.get_players(tournament, "matchmaking_active") - assert Enum.empty?(players) - - assert_received %Message{ - topic: ^player1_topic, - event: "waiting_room:player:match_created", - payload: %{ - current_player: %{ - id: ^p1_id, - state: "active", - task_ids: [^t2_id, ^t1_id], - score: 3, - wins_count: 1, - place: 0 - }, - match: %{state: "playing"}, - players: [%{}, %{}] - } - } - - assert_received %Message{ - topic: ^player2_topic, - event: "waiting_room:player:match_created", - payload: %{ - current_player: %{ - id: ^p2_id, - state: "active", - task_ids: [^t2_id, ^t1_id], - score: 3, - wins_count: 1, - place: 0 - }, - match: %{state: "playing"}, - players: [%{}, %{}] - } - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - :timer.sleep(100) - matches = get_matches(tournament) - - assert Enum.count(matches) == 6 - - ##### user1 win 1 round 2 game - win_active_match(tournament, user1) - :timer.sleep(100) - - UpdateFromResultsServer.update(tournament) - - assert %{ - entries: [ - %{place: 1, score: 200}, - %{place: 2, score: 100}, - %{place: 3, score: 67}, - %{place: 4, score: 33}, - %{id: _, name: _, score: 0, clan: _, clan_id: _, place: 5}, - %{id: _, name: _, score: 0, clan: _, clan_id: _, place: 6}, - %{id: _, name: _, score: 0, clan: _, clan_id: _, place: 7}, - %{id: _, name: _, score: 0, clan: _, clan_id: _, place: 8} - ] - } = Tournament.Ranking.get_page(tournament, 1) - - assert_received %Message{ - topic: ^player1_topic, - event: "tournament:match:upserted", - payload: %{match: %{state: "game_over"}, players: [%{}, %{}]} - } - - assert_received %Message{ - topic: ^player1_topic, - event: "waiting_room:player:matchmaking_started", - payload: %{ - current_player: %{ - id: ^p1_id, - state: "matchmaking_active", - task_ids: [^t2_id, ^t1_id], - score: 6, - wins_count: 2, - place: 0 - } - } - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - tournament = Tournament.Context.get(tournament.id) - players = Tournament.Players.get_players(tournament, "matchmaking_active") - - assert Enum.count(players) == 2 - - Tournament.Server.update_waiting_room_state(tournament.id, %{ - min_time_with_played_sec: 0 - }) - - Tournament.Server.match_waiting_room_players(tournament.id) - :timer.sleep(100) - - Tournament.Server.update_waiting_room_state(tournament.id, %{ - min_time_with_played_sec: 1000 - }) - - players = Tournament.Players.get_players(tournament, "matchmaking_active") - assert Enum.empty?(players) - - assert_received %Message{ - topic: ^player1_topic, - event: "waiting_room:player:match_created", - payload: %{ - current_player: %{ - id: ^p1_id, - state: "active", - task_ids: [^t3_id, ^t2_id, ^t1_id], - score: 6, - wins_count: 2, - place: 0 - }, - match: %{state: "playing"}, - players: [%{}, %{}] - } - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - ##### user1 win 1 round 3 game - win_active_match(tournament, user1) - :timer.sleep(100) - - UpdateFromResultsServer.update(tournament) - - assert %{ - entries: [ - %{place: 1, score: 300}, - %{place: 2, score: 100}, - %{place: 3, score: 67}, - %{place: 4, score: 33}, - %{id: _, name: _, score: 0, clan: _, clan_id: _, place: 5}, - %{id: _, name: _, score: 0, clan: _, clan_id: _, place: 6}, - %{id: _, name: _, score: 0, clan: _, clan_id: _, place: 7}, - %{id: _, name: _, score: 0, clan: _, clan_id: _, place: 8} - ] - } = Tournament.Ranking.get_page(tournament, 1) - - assert_received %Message{ - topic: ^player1_topic, - event: "waiting_room:player:matchmaking_stopped", - payload: %{ - current_player: %{ - id: ^p1_id, - state: "finished_round", - task_ids: [^t3_id, ^t2_id, ^t1_id], - score: 9, - wins_count: 3, - place: 0 - } - } - } - - assert_received %Message{ - topic: ^player1_topic, - event: "tournament:match:upserted", - payload: %{match: %{state: "game_over"}} - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - matches = get_matches(tournament) - - assert Enum.count(matches) == 7 - - assert tournament.current_round_position == 0 - - ##### Finish 1 round - Tournament.Server.finish_round_after(tournament.id, tournament.current_round_position, 0) - :timer.sleep(100) - - assert_received %Message{ - topic: ^player2_topic, - event: "waiting_room:player:matchmaking_stopped", - payload: %{ - current_player: %{ - id: ^p2_id, - state: "finished_round", - task_ids: [^t2_id, ^t1_id], - score: 100, - wins_count: 1, - place: 2 - } - } - } - - assert_received %Message{ - topic: ^player2_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{state: "timeout"}, - players: [%{}, %{}] - } - } - - assert_received %Message{ - topic: ^common_topic, - event: "tournament:round_finished", - payload: %{ - tournament: %{ - type: "arena", - state: "active", - current_round_position: 0, - break_state: "on", - last_round_ended_at: _, - last_round_started_at: _, - show_results: true - } - } - } - - assert_received %Message{ - topic: ^admin_topic, - event: "tournament:updated", - payload: %{ - tournament: %{ - type: "arena", - state: "active", - current_round_position: 0, - break_state: "on", - last_round_ended_at: _, - last_round_started_at: _, - show_results: true - } - } - } - - assert_received %Message{ - topic: ^admin_topic, - event: "tournament:updated", - payload: %{ - tournament: %{ - state: "active", - current_round_position: 0, - break_state: "on", - last_round_ended_at: _, - last_round_started_at: _ - } - } - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - ##### Finish 1 round break/Start 2 round - tournament = Tournament.Context.get(tournament.id) - Tournament.Server.stop_round_break_after(tournament.id, tournament.current_round_position, 0) - :timer.sleep(100) - - assert_received %Message{ - topic: ^common_topic, - event: "tournament:round_created", - payload: %{ - tournament: %{ - state: "active", - current_round_position: 1, - break_state: "off", - last_round_ended_at: _, - last_round_started_at: _ - } - } - } - - assert_received %Message{ - topic: ^player1_topic, - event: "waiting_room:player:match_created", - payload: %{ - current_player: %{ - id: ^p1_id, - state: "active", - task_ids: [^t4_id], - score: 300, - wins_count: 3, - place: 1 - }, - match: %{state: "playing"}, - players: [%{}, %{}] - } - } - - assert_received %Message{ - topic: ^player2_topic, - event: "waiting_room:player:match_created", - payload: %{ - current_player: %{ - id: ^p2_id, - state: "active", - task_ids: [^t4_id], - score: 100, - wins_count: 1, - place: 2 - }, - match: %{state: "playing"}, - players: [%{}, %{}] - } - } - - assert_received %Message{ - topic: ^admin_topic, - event: "tournament:updated", - payload: %{ - tournament: %{ - state: "active", - current_round_position: 1, - break_state: "off", - last_round_ended_at: _, - last_round_started_at: _ - } - } - } - - assert %{ - entries: [ - %{place: 1, score: 300}, - %{place: 2, score: 100}, - %{place: 3, score: 67}, - %{place: 4, score: 33}, - %{id: _, name: _, score: 0, clan: _, clan_id: _, place: 5}, - %{id: _, name: _, score: 0, clan: _, clan_id: _, place: 6}, - %{id: _, name: _, score: 0, clan: _, clan_id: _, place: 7}, - %{id: _, name: _, score: 0, clan: _, clan_id: _, place: 8} - ] - } = Tournament.Ranking.get_page(tournament, 1) - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - tournament = Tournament.Context.get(tournament.id) - - ##### user1 win 2 round 1 game - win_active_match(tournament, user1, %{opponent_percent: 0}) - - :timer.sleep(100) - UpdateFromResultsServer.update(tournament) - - assert %{ - entries: [ - %{id: ^u1_id, place: 1, score: 600}, - %{place: 2, score: 100}, - %{place: 3, score: 67}, - %{place: 4, score: 33}, - %{place: 5, score: 0}, - %{place: 6, score: 0}, - %{place: 7, score: 0}, - %{place: 8, score: 0} - ] - } = Tournament.Ranking.get_page(tournament, 1) - - assert_received %Message{ - topic: ^player1_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{state: "game_over"}, - players: [%{}, %{}] - } - } - - assert_received %Message{ - topic: ^player1_topic, - event: "waiting_room:player:matchmaking_started", - payload: %{ - current_player: %{ - id: ^p1_id, - state: "matchmaking_active", - task_ids: [^t4_id], - score: 305, - wins_count: 4, - place: 1 - } - } - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - ##### user2 win 2 round 1 game - win_active_match(tournament, user2) - :timer.sleep(100) - - UpdateFromResultsServer.update(tournament) - - assert %{ - entries: [ - %{id: ^u1_id, place: 1, score: 600}, - %{id: ^u2_id, place: 2, score: 400}, - %{place: 3, score: 67}, - %{place: 4, score: 33}, - %{place: 5, score: 0}, - %{place: 6, score: 0}, - %{place: 7, score: 0}, - %{place: 8, score: 0} - ] - } = Tournament.Ranking.get_page(tournament, 1) - - assert_received %Message{ - topic: ^player2_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{state: "game_over"}, - players: [%{}, %{}] - } - } - - assert_received %Message{ - topic: ^player2_topic, - event: "waiting_room:player:matchmaking_started", - payload: %{ - current_player: %{ - id: ^p2_id, - state: "matchmaking_active", - task_ids: [^t4_id], - score: 105, - wins_count: 2, - place: 2 - } - } - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - ##### match players - Tournament.Server.update_waiting_room_state(tournament.id, %{ - min_time_with_played_sec: 0 - }) - - Tournament.Server.match_waiting_room_players(tournament.id) - :timer.sleep(100) - - Tournament.Server.update_waiting_room_state(tournament.id, %{ - min_time_with_played_sec: 1000 - }) - - assert_received %Message{ - topic: ^player1_topic, - event: "waiting_room:player:match_created", - payload: %{ - current_player: %{ - id: ^p1_id, - state: "active", - task_ids: [^t5_id, ^t4_id], - score: 305, - wins_count: 4, - place: 1 - }, - match: %{state: "playing"}, - players: [%{}, %{}] - } - } - - assert_received %Message{ - topic: ^player2_topic, - event: "waiting_room:player:match_created", - payload: %{ - current_player: %{ - id: ^p2_id, - state: "active", - task_ids: [^t5_id, ^t4_id], - place: 2, - wins_count: 2, - score: 105 - }, - match: %{state: "playing"}, - players: [%{}, %{}] - } - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - assert Enum.empty?(players) - - ##### user1 win 2 round 2 game - win_active_match(tournament, user1) - :timer.sleep(100) - - assert_received %Message{ - topic: ^player1_topic, - event: "tournament:match:upserted", - payload: %{match: %{state: "game_over"}, players: [%{}, %{}]} - } - - assert_received %Message{ - topic: ^player1_topic, - event: "waiting_room:player:matchmaking_stopped", - payload: %{ - current_player: %{ - id: ^p1_id, - state: "finished_round", - task_ids: [^t5_id, ^t4_id], - score: 310, - wins_count: 5, - place: 1 - } - } - } - - UpdateFromResultsServer.update(tournament) - - assert %{ - entries: [ - %{place: 1, score: 900, id: ^u1_id}, - %{place: 2, score: 400, id: ^u2_id}, - %{place: 3, score: 67}, - %{place: 4, score: 33}, - %{place: 5, score: 0}, - %{place: 6, score: 0}, - %{place: 7, score: 0}, - %{place: 8, score: 0} - ] - } = Tournament.Ranking.get_page(tournament, 1) - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - tournament = Tournament.Context.get(tournament.id) - - ##### Finish 2 round - Tournament.Server.finish_round_after(tournament.id, tournament.current_round_position, 0) - :timer.sleep(100) - - assert_received %Message{ - topic: ^player2_topic, - event: "waiting_room:player:matchmaking_stopped", - payload: %{ - current_player: %{ - id: ^p2_id, - state: "finished_round", - task_ids: [^t5_id, ^t4_id], - score: 400, - wins_count: 2, - place: 2 - } - } - } - - assert_received %Message{ - topic: ^player2_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{state: "timeout"}, - players: [%{}, %{}] - } - } - - assert_received %Message{ - topic: ^common_topic, - event: "tournament:round_finished", - payload: %{ - tournament: %{ - type: "arena", - state: "active", - current_round_position: 1, - break_state: "on", - last_round_ended_at: _, - last_round_started_at: _, - show_results: true - } - } - } - - assert_received %Message{ - topic: ^admin_topic, - event: "tournament:updated", - payload: %{ - tournament: %{ - type: "arena", - state: "active", - current_round_position: 1, - break_state: "on", - last_round_ended_at: _, - last_round_started_at: _, - show_results: true - } - } - } - - assert_received %Message{ - topic: ^admin_topic, - event: "tournament:updated", - payload: %{ - tournament: %{ - state: "active", - current_round_position: 1, - break_state: "on", - last_round_ended_at: _, - last_round_started_at: _ - } - } - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - ##### Finish 2 round break/Start 3 round - tournament = Tournament.Context.get(tournament.id) - Tournament.Server.stop_round_break_after(tournament.id, tournament.current_round_position, 0) - :timer.sleep(100) - - assert_received %Message{ - topic: ^common_topic, - event: "tournament:round_created", - payload: %{ - tournament: %{ - state: "active", - current_round_position: 2, - break_state: "off", - last_round_ended_at: _, - last_round_started_at: _ - } - } - } - - assert_received %Message{ - topic: ^player1_topic, - event: "waiting_room:player:match_created", - payload: %{ - current_player: %{ - id: ^p1_id, - state: "active", - task_ids: [^t6_id], - score: 900, - wins_count: 5, - place: 1 - }, - match: %{state: "playing"}, - players: [%{}, %{}] - } - } - - assert_received %Message{ - topic: ^player2_topic, - event: "waiting_room:player:match_created", - payload: %{ - current_player: %{ - id: ^p2_id, - state: "active", - task_ids: [^t6_id], - score: 400, - wins_count: 2, - place: 2 - }, - match: %{state: "playing"}, - players: [%{}, %{}] - } - } - - assert_received %Message{ - topic: ^admin_topic, - event: "tournament:updated", - payload: %{ - tournament: %{ - state: "active", - current_round_position: 2, - break_state: "off", - last_round_ended_at: _, - last_round_started_at: _ - } - } - } - - assert %{ - entries: [ - %{place: 1, score: 900}, - %{place: 2, score: 400}, - %{place: 3, score: 67}, - %{place: 4, score: 33}, - %{place: 5, score: 0}, - %{place: 6, score: 0}, - %{place: 7, score: 0}, - %{place: 8, score: 0} - ] - } = Tournament.Ranking.get_page(tournament, 1) - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - ##### user2 win 3 round 1 game - win_active_match(tournament, user2, %{opponent_percent: 33}) - - :timer.sleep(100) - UpdateFromResultsServer.update(tournament) - - assert %{ - entries: [ - %{id: ^u2_id, place: 1, score: 1400}, - %{id: ^u1_id, place: 2, score: 900}, - %{place: 3, score: 366}, - %{place: 4, score: 67}, - %{place: 5, score: 0}, - %{place: 6, score: 0}, - %{place: 7, score: 0}, - %{place: 8, score: 0} - ] - } = Tournament.Ranking.get_page(tournament, 1) - - assert_received %Message{ - topic: ^player2_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{state: "game_over"}, - players: [%{}, %{}] - } - } - - assert_received %Message{ - topic: ^player2_topic, - event: "waiting_room:player:matchmaking_stopped", - payload: %{ - current_player: %{ - id: ^p2_id, - state: "finished_round", - task_ids: [^t6_id], - score: 408, - wins_count: 3, - place: 2 - } - } - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - ##### Finish 3 round - - tournament = Tournament.Context.get(tournament.id) - Tournament.Server.finish_round_after(tournament.id, tournament.current_round_position, 0) - :timer.sleep(100) - - assert_received %Message{ - topic: ^player1_topic, - event: "waiting_room:ended", - payload: %{ - current_player: %{ - id: ^p1_id, - state: "finished", - task_ids: [^t6_id], - score: 900, - wins_count: 5, - place: 2 - } - } - } - - assert_received %Message{ - topic: ^player2_topic, - event: "waiting_room:ended", - payload: %{ - current_player: %{ - id: ^p2_id, - state: "finished", - task_ids: [^t6_id], - score: 1400, - wins_count: 3, - place: 1 - } - } - } - - assert_received %Message{ - topic: ^player1_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{state: "timeout"}, - players: [%{}, %{}] - } - } - - assert_received %Message{ - topic: ^common_topic, - event: "tournament:round_finished", - payload: %{ - tournament: %{ - type: "arena", - state: "active", - current_round_position: 2, - break_state: "on", - last_round_ended_at: _, - last_round_started_at: _, - show_results: true - } - } - } - - assert_received %Message{ - topic: ^admin_topic, - event: "tournament:updated", - payload: %{ - tournament: %{ - type: "arena", - state: "active", - current_round_position: 2, - break_state: "on", - last_round_ended_at: _, - last_round_started_at: _, - show_results: true - } - } - } - - assert_received %Message{ - topic: ^admin_topic, - event: "tournament:updated", - payload: %{ - tournament: %{ - state: "finished", - current_round_position: 2, - break_state: "off", - last_round_ended_at: _, - last_round_started_at: _ - } - } - } - - assert_received %Message{ - topic: ^common_topic, - event: "tournament:finished", - payload: %{ - tournament: %{ - break_state: "off", - current_round_position: 2, - last_round_ended_at: _, - last_round_started_at: _, - show_results: true, - state: "finished", - type: "arena" - } - } - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - assert 34 == Repo.count(TournamentResult) - - assert [ - %{ - id: _, - event_id: ^e_id, - clan_id: ^c1_id, - user_id: ^u2_id, - user_name: "2", - place: 1, - score: 1400 - }, - %{ - id: _, - event_id: ^e_id, - clan_id: ^c1_id, - user_id: ^u1_id, - user_name: "1", - place: 2, - score: 900 - }, - %{place: 3, event_id: ^e_id, score: 366}, - %{place: 4, event_id: ^e_id, score: 67}, - %{place: 5, event_id: ^e_id, score: 0}, - %{place: 6, event_id: ^e_id, score: 0}, - %{place: 7, event_id: ^e_id, score: 0}, - %{place: 8, event_id: ^e_id, score: 0} - ] = EventResult |> Repo.all() |> Enum.sort_by(&{&1.place}) - end -end diff --git a/services/app/apps/codebattle/test/codebattle/tournament/entire/squad_seq_task_one_zero_test.exs b/services/app/apps/codebattle/test/codebattle/tournament/entire/squad_seq_task_one_zero_test.exs deleted file mode 100644 index 928842051..000000000 --- a/services/app/apps/codebattle/test/codebattle/tournament/entire/squad_seq_task_one_zero_test.exs +++ /dev/null @@ -1,881 +0,0 @@ -defmodule Codebattle.Tournament.Entire.SquadSeqTaskOneZeroTest do - use Codebattle.DataCase, async: false - - import Codebattle.Tournament.Helpers - import Codebattle.TournamentTestHelpers - - alias Codebattle.PubSub.Message - alias Codebattle.Tournament - - @tag :skip - test "works with several players and single round" do - [%{id: t1_id}, %{id: t2_id}] = insert_list(2, :task, level: "easy") - [%{id: t3_id}, %{id: t4_id}] = insert_list(2, :task, level: "medium") - [%{id: t5_id}, %{id: t6_id}] = insert_list(2, :task, level: "hard") - insert(:task_pack, name: "tp1", task_ids: [t1_id, t2_id]) - insert(:task_pack, name: "tp2", task_ids: [t3_id, t4_id]) - insert(:task_pack, name: "tp3", task_ids: [t5_id, t6_id]) - - creator = insert(:user) - user1 = %{id: u1_id} = insert(:user, %{name: "1"}) - user2 = %{id: u2_id} = insert(:user, %{name: "2"}) - user3 = %{id: u3_id} = insert(:user, %{name: "3"}) - user4 = %{id: u4_id} = insert(:user, %{name: "4"}) - users = [user1, user2, user3, user4] - - {:ok, tournament} = - Tournament.Context.create(%{ - "starts_at" => "2022-02-24T06:00", - "name" => "Test Clan Arena", - "user_timezone" => "Etc/UTC", - "level" => "easy", - "task_pack_name" => "tp1,tp2,tp3", - "creator" => creator, - "break_duration_seconds" => "100", - "task_provider" => "task_pack_per_round", - "score_strategy" => "one_zero", - "task_strategy" => "sequential", - "ranking_type" => "void", - "type" => "squad", - "state" => "waiting_participants", - "use_clan" => "false", - "rounds_limit" => "3", - "players_limit" => 200 - }) - - admin_topic = tournament_admin_topic(tournament.id) - common_topic = tournament_common_topic(tournament.id) - player1_topic = tournament_player_topic(tournament.id, u1_id) - player2_topic = tournament_player_topic(tournament.id, u2_id) - player3_topic = tournament_player_topic(tournament.id, u3_id) - player4_topic = tournament_player_topic(tournament.id, u4_id) - - Codebattle.PubSub.subscribe(admin_topic) - Codebattle.PubSub.subscribe(common_topic) - Codebattle.PubSub.subscribe(player1_topic) - Codebattle.PubSub.subscribe(player2_topic) - Codebattle.PubSub.subscribe(player3_topic) - Codebattle.PubSub.subscribe(player4_topic) - - Tournament.Server.handle_event(tournament.id, :join, %{users: users}) - - Enum.each(users, fn %{id: id, name: name} -> - assert_received %Message{ - topic: ^common_topic, - event: "tournament:player:joined", - payload: %{player: %{name: ^name, id: ^id, state: "active"}} - } - end) - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - Tournament.Server.handle_event(tournament.id, :start, %{ - user: creator, - time_step_ms: 20_000, - min_time_sec: 0 - }) - - assert_received %Message{ - topic: ^admin_topic, - event: "tournament:updated", - payload: %{ - tournament: %{ - state: "active", - current_round_position: 0, - break_state: "off", - last_round_ended_at: nil, - last_round_started_at: _ - } - } - } - - assert_received %Message{ - topic: ^common_topic, - event: "tournament:round_created", - payload: %{ - tournament: %{ - state: "active", - current_round_position: 0, - break_state: "off", - last_round_ended_at: nil, - last_round_started_at: _ - } - } - } - - assert_received %Message{ - topic: ^player1_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{ - id: 0, - task_id: ^t1_id, - player_ids: [^u1_id, ^u2_id] - }, - players: [%{id: ^u1_id}, %{id: ^u2_id}] - } - } - - assert_received %Message{ - topic: ^player2_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{ - id: 0, - task_id: ^t1_id, - player_ids: [^u1_id, ^u2_id] - }, - players: [%{id: ^u1_id}, %{id: ^u2_id}] - } - } - - assert_received %Message{ - topic: ^player3_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{ - id: 1, - task_id: ^t1_id, - player_ids: [^u3_id, ^u4_id] - }, - players: [%{id: ^u3_id}, %{id: ^u4_id}] - } - } - - assert_received %Message{ - topic: ^player4_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{ - id: 1, - task_id: ^t1_id, - player_ids: [^u3_id, ^u4_id] - }, - players: [%{id: ^u3_id}, %{id: ^u4_id}] - } - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - tournament = Tournament.Context.get(tournament.id) - matches = get_matches(tournament) - - assert players_count(tournament) == 4 - assert Enum.count(matches) == 2 - - ##### user1 win 1 round 1 game - win_active_match(tournament, user1) - :timer.sleep(100) - - assert_received %Message{ - topic: ^player1_topic, - event: "tournament:match:upserted", - payload: %{match: %{id: 0, state: "game_over"}, players: [%{}, %{}]} - } - - assert_received %Message{ - topic: ^player2_topic, - event: "tournament:match:upserted", - payload: %{match: %{id: 0, state: "game_over"}, players: [%{}, %{}]} - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - ##### user3 win 1 round 1 game - win_active_match(tournament, user3) - :timer.sleep(100) - - assert_received %Message{ - topic: ^player3_topic, - event: "tournament:match:upserted", - payload: %{match: %{id: 1, state: "game_over"}, players: [%{}, %{}]} - } - - assert_received %Message{ - topic: ^player4_topic, - event: "tournament:match:upserted", - payload: %{match: %{id: 1, state: "game_over"}, players: [%{}, %{}]} - } - - assert_received %Message{ - topic: ^admin_topic, - event: "tournament:updated", - payload: %{ - tournament: %{ - state: "active", - current_round_position: 0, - break_state: "off", - last_round_ended_at: nil, - last_round_started_at: _ - } - } - } - - assert_received %Message{ - topic: ^player1_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{id: 2, task_id: ^t2_id, player_ids: [^u1_id, ^u2_id]}, - players: [%{id: ^u1_id}, %{id: ^u2_id}] - } - } - - assert_received %Message{ - topic: ^player2_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{id: 2, task_id: ^t2_id, player_ids: [^u1_id, ^u2_id]}, - players: [%{id: ^u1_id}, %{id: ^u2_id}] - } - } - - assert_received %Message{ - topic: ^player3_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{id: 3, task_id: ^t2_id, player_ids: [^u3_id, ^u4_id]}, - players: [%{id: ^u3_id}, %{id: ^u4_id}] - } - } - - assert_received %Message{ - topic: ^player4_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{id: 3, task_id: ^t2_id, player_ids: [^u3_id, ^u4_id]}, - players: [%{id: ^u3_id}, %{id: ^u4_id}] - } - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - matches = get_matches(tournament) - - assert Enum.count(matches) == 4 - - ##### user1 win 1 round 2 game - win_active_match(tournament, user1) - :timer.sleep(100) - - assert_received %Message{ - topic: ^player1_topic, - event: "tournament:match:upserted", - payload: %{match: %{id: 2, state: "game_over"}, players: [%{}, %{}]} - } - - assert_received %Message{ - topic: ^player2_topic, - event: "tournament:match:upserted", - payload: %{match: %{id: 2, state: "game_over"}, players: [%{}, %{}]} - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - tournament = Tournament.Context.get(tournament.id) - - ##### user3 win 1 round 2 game - win_active_match(tournament, user3) - :timer.sleep(100) - - assert_received %Message{ - topic: ^player3_topic, - event: "tournament:match:upserted", - payload: %{match: %{id: 3, state: "game_over"}, players: [%{}, %{}]} - } - - assert_received %Message{ - topic: ^player4_topic, - event: "tournament:match:upserted", - payload: %{match: %{id: 3, state: "game_over"}, players: [%{}, %{}]} - } - - assert_received %Message{ - topic: ^common_topic, - event: "tournament:round_finished", - payload: %{ - tournament: %{ - type: "squad", - state: "active", - current_round_position: 0, - break_state: "on", - last_round_ended_at: _, - last_round_started_at: _, - show_results: true - } - } - } - - assert_received %Message{ - topic: ^admin_topic, - event: "tournament:updated", - payload: %{ - tournament: %{ - type: "squad", - state: "active", - current_round_position: 0, - break_state: "on", - last_round_ended_at: _, - last_round_started_at: _, - show_results: true - } - } - } - - assert_received %Message{ - topic: ^admin_topic, - event: "tournament:updated", - payload: %{ - tournament: %{ - type: "squad", - state: "active", - current_round_position: 0, - break_state: "on", - last_round_ended_at: _, - last_round_started_at: _, - show_results: true - } - } - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - matches = get_matches(tournament) - - assert Enum.count(matches) == 4 - - assert tournament.current_round_position == 0 - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - tournament = Tournament.Context.get(tournament.id) - - ##### Finish 1 round break/Start 2 round - tournament = Tournament.Context.get(tournament.id) - Tournament.Server.stop_round_break_after(tournament.id, tournament.current_round_position, 0) - :timer.sleep(100) - - assert_received %Message{ - topic: ^common_topic, - event: "tournament:round_created", - payload: %{ - tournament: %{ - state: "active", - current_round_position: 1, - break_state: "off", - last_round_ended_at: _, - last_round_started_at: _ - } - } - } - - assert_received %Message{ - topic: ^player1_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{id: 4, task_id: ^t3_id, player_ids: [^u1_id, ^u2_id]}, - players: [%{id: ^u1_id}, %{id: ^u2_id}] - } - } - - assert_received %Message{ - topic: ^player2_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{id: 4, task_id: ^t3_id, player_ids: [^u1_id, ^u2_id]}, - players: [%{id: ^u1_id}, %{id: ^u2_id}] - } - } - - assert_received %Message{ - topic: ^player3_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{id: 5, task_id: ^t3_id, player_ids: [^u3_id, ^u4_id]}, - players: [%{id: ^u3_id}, %{id: ^u4_id}] - } - } - - assert_received %Message{ - topic: ^player4_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{id: 5, task_id: ^t3_id, player_ids: [^u3_id, ^u4_id]}, - players: [%{id: ^u3_id}, %{id: ^u4_id}] - } - } - - assert_received %Message{ - topic: ^admin_topic, - event: "tournament:updated", - payload: %{ - tournament: %{ - state: "active", - current_round_position: 1, - break_state: "off", - last_round_ended_at: _, - last_round_started_at: _ - } - } - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - ##### user1 win 2 round 1 game - win_active_match(tournament, user1) - :timer.sleep(100) - - assert_received %Message{ - topic: ^player1_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{state: "game_over"}, - players: [%{}, %{}] - } - } - - assert_received %Message{ - topic: ^player2_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{state: "game_over"}, - players: [%{}, %{}] - } - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - ##### user3 win 2 round 1 game - win_active_match(tournament, user3) - :timer.sleep(100) - - assert_received %Message{ - topic: ^player3_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{state: "game_over"}, - players: [%{}, %{}] - } - } - - assert_received %Message{ - topic: ^player4_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{state: "game_over"}, - players: [%{}, %{}] - } - } - - assert_received %Message{ - topic: ^admin_topic, - event: "tournament:updated", - payload: %{ - tournament: %{ - state: "active", - current_round_position: 1, - break_state: "off", - last_round_ended_at: _, - last_round_started_at: _ - } - } - } - - assert_received %Message{ - topic: ^player1_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{id: 6, task_id: ^t4_id, player_ids: [^u1_id, ^u2_id]}, - players: [%{id: ^u1_id}, %{id: ^u2_id}] - } - } - - assert_received %Message{ - topic: ^player2_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{id: 6, task_id: ^t4_id, player_ids: [^u1_id, ^u2_id]}, - players: [%{id: ^u1_id}, %{id: ^u2_id}] - } - } - - assert_received %Message{ - topic: ^player3_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{id: 7, task_id: ^t4_id, player_ids: [^u3_id, ^u4_id]}, - players: [%{id: ^u3_id}, %{id: ^u4_id}] - } - } - - assert_received %Message{ - topic: ^player4_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{id: 7, task_id: ^t4_id, player_ids: [^u3_id, ^u4_id]}, - players: [%{id: ^u3_id}, %{id: ^u4_id}] - } - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - matches = get_matches(tournament) - - assert Enum.count(matches) == 8 - - ##### user1 win 2 round 2 game - win_active_match(tournament, user1) - :timer.sleep(100) - - assert_received %Message{ - topic: ^player1_topic, - event: "tournament:match:upserted", - payload: %{match: %{id: 6, state: "game_over"}, players: [%{}, %{}]} - } - - assert_received %Message{ - topic: ^player2_topic, - event: "tournament:match:upserted", - payload: %{match: %{id: 6, state: "game_over"}, players: [%{}, %{}]} - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - tournament = Tournament.Context.get(tournament.id) - - ##### user3 win 2 round 2 game - win_active_match(tournament, user3) - :timer.sleep(100) - - assert_received %Message{ - topic: ^player3_topic, - event: "tournament:match:upserted", - payload: %{match: %{id: 7, state: "game_over"}, players: [%{}, %{}]} - } - - assert_received %Message{ - topic: ^player4_topic, - event: "tournament:match:upserted", - payload: %{match: %{id: 7, state: "game_over"}, players: [%{}, %{}]} - } - - assert_received %Message{ - topic: ^common_topic, - event: "tournament:round_finished", - payload: %{ - tournament: %{ - type: "squad", - state: "active", - current_round_position: 1, - break_state: "on", - last_round_ended_at: _, - last_round_started_at: _, - show_results: true - } - } - } - - assert_received %Message{ - topic: ^admin_topic, - event: "tournament:updated", - payload: %{ - tournament: %{ - type: "squad", - state: "active", - current_round_position: 1, - break_state: "on", - last_round_ended_at: _, - last_round_started_at: _, - show_results: true - } - } - } - - assert_received %Message{ - topic: ^admin_topic, - event: "tournament:updated", - payload: %{ - tournament: %{ - type: "squad", - state: "active", - current_round_position: 1, - break_state: "on", - last_round_ended_at: _, - last_round_started_at: _, - show_results: true - } - } - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - tournament = Tournament.Context.get(tournament.id) - - matches = get_matches(tournament) - - assert Enum.count(matches) == 8 - - assert tournament.current_round_position == 1 - - ##### Finish 2 round break/Start 3 round - Tournament.Server.stop_round_break_after(tournament.id, tournament.current_round_position, 0) - :timer.sleep(100) - - assert_received %Message{ - topic: ^common_topic, - event: "tournament:round_created", - payload: %{ - tournament: %{ - state: "active", - current_round_position: 2, - break_state: "off", - last_round_ended_at: _, - last_round_started_at: _ - } - } - } - - assert_received %Message{ - topic: ^player1_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{id: 8, task_id: ^t5_id, player_ids: [^u1_id, ^u2_id]}, - players: [%{id: ^u1_id}, %{id: ^u2_id}] - } - } - - assert_received %Message{ - topic: ^player2_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{id: 8, task_id: ^t5_id, player_ids: [^u1_id, ^u2_id]}, - players: [%{id: ^u1_id}, %{id: ^u2_id}] - } - } - - assert_received %Message{ - topic: ^player3_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{id: 9, task_id: ^t5_id, player_ids: [^u3_id, ^u4_id]}, - players: [%{id: ^u3_id}, %{id: ^u4_id}] - } - } - - assert_received %Message{ - topic: ^player4_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{id: 9, task_id: ^t5_id, player_ids: [^u3_id, ^u4_id]}, - players: [%{id: ^u3_id}, %{id: ^u4_id}] - } - } - - assert_received %Message{ - topic: ^admin_topic, - event: "tournament:updated", - payload: %{ - tournament: %{ - state: "active", - current_round_position: 2, - break_state: "off", - last_round_ended_at: _, - last_round_started_at: _ - } - } - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - ##### user1 win 3 round 1 game - win_active_match(tournament, user1) - :timer.sleep(100) - - assert_received %Message{ - topic: ^player1_topic, - event: "tournament:match:upserted", - payload: %{match: %{id: 8, state: "game_over"}, players: [%{}, %{}]} - } - - assert_received %Message{ - topic: ^player2_topic, - event: "tournament:match:upserted", - payload: %{match: %{id: 8, state: "game_over"}, players: [%{}, %{}]} - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - ##### user3 win 3 round 1 game - win_active_match(tournament, user3) - :timer.sleep(100) - - assert_received %Message{ - topic: ^player3_topic, - event: "tournament:match:upserted", - payload: %{match: %{id: 9, state: "game_over"}, players: [%{}, %{}]} - } - - assert_received %Message{ - topic: ^player4_topic, - event: "tournament:match:upserted", - payload: %{match: %{id: 9, state: "game_over"}, players: [%{}, %{}]} - } - - assert_received %Message{ - topic: ^admin_topic, - event: "tournament:updated", - payload: %{ - tournament: %{ - state: "active", - current_round_position: 2, - break_state: "off", - last_round_ended_at: _, - last_round_started_at: _ - } - } - } - - assert_received %Message{ - topic: ^player1_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{id: 10, task_id: ^t6_id, player_ids: [^u1_id, ^u2_id]}, - players: [%{id: ^u1_id}, %{id: ^u2_id}] - } - } - - assert_received %Message{ - topic: ^player2_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{id: 10, task_id: ^t6_id, player_ids: [^u1_id, ^u2_id]}, - players: [%{id: ^u1_id}, %{id: ^u2_id}] - } - } - - assert_received %Message{ - topic: ^player3_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{id: 11, task_id: ^t6_id, player_ids: [^u3_id, ^u4_id]}, - players: [%{id: ^u3_id}, %{id: ^u4_id}] - } - } - - assert_received %Message{ - topic: ^player4_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{id: 11, task_id: ^t6_id, player_ids: [^u3_id, ^u4_id]}, - players: [%{id: ^u3_id}, %{id: ^u4_id}] - } - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - matches = get_matches(tournament) - - assert Enum.count(matches) == 12 - - ##### user1 win 3 round 2 game - win_active_match(tournament, user1) - :timer.sleep(100) - - assert_received %Message{ - topic: ^player1_topic, - event: "tournament:match:upserted", - payload: %{match: %{id: 10, state: "game_over"}, players: [%{}, %{}]} - } - - assert_received %Message{ - topic: ^player2_topic, - event: "tournament:match:upserted", - payload: %{match: %{id: 10, state: "game_over"}, players: [%{}, %{}]} - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - tournament = Tournament.Context.get(tournament.id) - - ##### user3 win 3 round 2 game - win_active_match(tournament, user3) - :timer.sleep(100) - - assert_received %Message{ - topic: ^player3_topic, - event: "tournament:match:upserted", - payload: %{match: %{id: 11, state: "game_over"}, players: [%{}, %{}]} - } - - assert_received %Message{ - topic: ^player4_topic, - event: "tournament:match:upserted", - payload: %{match: %{id: 11, state: "game_over"}, players: [%{}, %{}]} - } - - assert_received %Message{ - topic: ^common_topic, - event: "tournament:round_finished", - payload: %{ - tournament: %{ - type: "squad", - state: "active", - current_round_position: 2, - break_state: "on", - last_round_ended_at: _, - last_round_started_at: _, - show_results: true - } - } - } - - assert_received %Message{ - topic: ^admin_topic, - event: "tournament:updated", - payload: %{ - tournament: %{ - type: "squad", - state: "active", - current_round_position: 2, - break_state: "on", - last_round_ended_at: _, - last_round_started_at: _, - show_results: true - } - } - } - - assert_received %Message{ - topic: ^admin_topic, - event: "tournament:updated", - payload: %{ - tournament: %{ - type: "squad", - state: "finished", - current_round_position: 2, - break_state: "off", - last_round_ended_at: _, - last_round_started_at: _, - show_results: true - } - } - } - - assert_received %Message{ - topic: ^common_topic, - event: "tournament:finished", - payload: %{ - tournament: %{ - type: "squad", - state: "finished", - current_round_position: 2, - break_state: "off", - last_round_ended_at: _, - last_round_started_at: _, - show_results: true - } - } - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - end -end diff --git a/services/app/apps/codebattle/test/codebattle/tournament/entire/swiss_qualification_test.exs b/services/app/apps/codebattle/test/codebattle/tournament/entire/swiss_qualification_test.exs deleted file mode 100644 index 864d821d8..000000000 --- a/services/app/apps/codebattle/test/codebattle/tournament/entire/swiss_qualification_test.exs +++ /dev/null @@ -1,378 +0,0 @@ -defmodule Codebattle.Tournament.Entire.SwissQualificationTest do - use Codebattle.DataCase, async: false - - import Codebattle.Tournament.Helpers - import Codebattle.TournamentTestHelpers - - alias Codebattle.PubSub.Message - alias Codebattle.Repo - alias Codebattle.Tournament - alias Codebattle.Tournament.TournamentResult - alias Codebattle.UserEvent - - @decimal100 Decimal.new("100.0") - - test "works with player who solved all tasks" do - [%{id: t1_id}, %{id: t2_id}, %{id: t3_id}] = insert_list(3, :task, level: "easy") - insert(:task_pack, name: "tp", task_ids: [t1_id, t2_id, t3_id]) - - event = - insert(:event, - stages: [ - %{ - slug: "qualification", - name: "Qualification", - status: :active, - type: :tournament, - playing_type: :single - } - ] - ) - - creator = insert(:user) - user1 = %{id: u1_id} = insert(:user, %{clan_id: 1, clan: "1", name: "1"}) - - {:ok, tournament} = - Tournament.Context.create(%{ - "starts_at" => "2025-02-24T06:00", - "name" => "Qualification", - "event_id" => to_string(event.id), - "user_timezone" => "Etc/UTC", - "level" => "easy", - "task_pack_name" => "tp", - "creator" => creator, - "break_duration_seconds" => 0, - "task_provider" => "task_pack", - "score_strategy" => "win_loss", - "task_strategy" => "sequential", - "ranking_type" => "by_clan", - "type" => "swiss", - "state" => "waiting_participants", - "use_clan" => "false", - "use_chat" => "false", - "rounds_limit" => "3", - "players_limit" => 2 - }) - - insert(:user_event, - event: event, - user: user1, - stages: [ - %{ - slug: "qualification", - status: :pending, - place_in_total_rank: nil, - place_in_category_rank: nil, - score: nil, - wins_count: nil, - games_count: nil, - tournament_id: tournament.id, - time_spent_in_seconds: nil - } - ] - ) - - users = [%{id: p1_id} = user1] - - admin_topic = tournament_admin_topic(tournament.id) - common_topic = tournament_common_topic(tournament.id) - player1_topic = tournament_player_topic(tournament.id, p1_id) - - Codebattle.PubSub.subscribe(admin_topic) - Codebattle.PubSub.subscribe(common_topic) - Codebattle.PubSub.subscribe(player1_topic) - - Tournament.Server.handle_event(tournament.id, :join, %{users: users}) - - Enum.each(users, fn %{id: id, name: name} -> - assert_received %Message{ - topic: ^common_topic, - event: "tournament:player:joined", - payload: %{player: %{name: ^name, id: ^id, state: "active"}} - } - end) - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - Tournament.Server.handle_event(tournament.id, :start, %{ - user: creator, - time_step_ms: 20_000, - min_time_sec: 0 - }) - - assert_received %Message{ - topic: ^admin_topic, - event: "tournament:updated", - payload: %{ - tournament: %{ - state: "active", - current_round_position: 0, - break_state: "off", - last_round_ended_at: nil, - last_round_started_at: _ - } - } - } - - assert_received %Message{ - topic: ^common_topic, - event: "tournament:round_created", - payload: %{ - tournament: %{ - state: "active", - current_round_position: 0, - break_state: "off", - last_round_ended_at: nil, - last_round_started_at: _ - } - } - } - - assert_received %Message{ - topic: ^player1_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{task_id: ^t1_id, state: "playing"}, - players: [%{}, %{}] - } - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - tournament = Tournament.Context.get(tournament.id) - matches = get_matches(tournament) - - assert players_count(tournament) == 2 - assert Enum.count(matches) == 1 - - win_active_match(tournament, user1) - :timer.sleep(100) - - assert_received %Message{ - topic: ^player1_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{state: "game_over"}, - players: [%{}, %{}] - } - } - - assert_received %Message{ - topic: ^player1_topic, - event: "tournament:match:upserted", - payload: %{} - } - - assert_received %Message{ - topic: ^admin_topic, - event: "tournament:updated", - payload: %{} - } - - assert_received %Message{ - topic: ^admin_topic, - event: "tournament:updated", - payload: %{} - } - - assert_received %Message{ - topic: ^common_topic, - event: "tournament:round_finished", - payload: %{ - tournament: %{ - state: "active", - current_round_position: 0, - break_state: "on" - } - } - } - - assert_received %Message{ - topic: ^common_topic, - event: "tournament:round_created", - payload: %{ - tournament: %{ - state: "active", - current_round_position: 1, - break_state: "off" - } - } - } - - assert_received %Message{ - topic: ^admin_topic, - event: "tournament:updated", - payload: %{} - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - :timer.sleep(100) - - tournament = Tournament.Context.get(tournament.id) - matches = get_matches(tournament) - - assert Enum.count(matches) == 2 - - win_active_match(tournament, user1) - :timer.sleep(200) - - assert_received %Message{ - topic: ^player1_topic, - event: "tournament:match:upserted", - payload: %{match: %{state: "game_over"}, players: [%{}, %{}]} - } - - assert_received %Message{ - topic: ^admin_topic, - event: "tournament:updated", - payload: %{} - } - - assert_received %Message{ - topic: ^admin_topic, - event: "tournament:updated", - payload: %{} - } - - assert_received %Message{ - topic: ^admin_topic, - event: "tournament:updated", - payload: %{} - } - - assert_received %Message{ - topic: ^common_topic, - event: "tournament:round_finished", - payload: %{} - } - - assert_received %Message{ - topic: ^common_topic, - event: "tournament:round_created", - payload: %{} - } - - assert_received %Message{ - topic: ^player1_topic, - event: "tournament:match:upserted", - payload: %{} - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - tournament = Tournament.Context.get(tournament.id) - win_active_match(tournament, user1) - :timer.sleep(200) - - assert_received %Message{ - topic: ^player1_topic, - event: "tournament:match:upserted", - payload: %{match: %{state: "game_over"}} - } - - assert_received %Message{ - topic: ^admin_topic, - event: "tournament:updated", - payload: %{} - } - - assert_received %Message{ - topic: ^admin_topic, - event: "tournament:updated", - payload: %{} - } - - assert_received %Message{ - topic: ^common_topic, - event: "tournament:round_finished", - payload: %{} - } - - assert_received %Message{ - topic: ^common_topic, - event: "tournament:finished", - payload: %{ - tournament: %{ - type: "swiss", - state: "finished", - current_round_position: 2, - break_state: "off", - last_round_ended_at: _, - last_round_started_at: _ - } - } - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - tournament = %{id: tournament_id} = Tournament.Context.get(tournament.id) - matches = get_matches(tournament) - - assert Enum.count(matches) == 3 - - assert tournament.current_round_position == 2 - - assert [ - %{ - score: 3, - clan_id: 1, - duration_sec: 0, - game_id: _, - id: _, - level: "easy", - result_percent: @decimal100, - task_id: ^t1_id, - tournament_id: ^tournament_id, - user_id: ^u1_id, - user_name: "1" - }, - %{ - score: 3, - clan_id: 1, - duration_sec: 0, - game_id: _, - id: _, - level: "easy", - result_percent: @decimal100, - task_id: ^t2_id, - tournament_id: ^tournament_id, - user_id: ^u1_id, - user_name: "1" - }, - %{ - score: 3, - clan_id: 1, - duration_sec: 0, - game_id: _, - id: _, - level: "easy", - result_percent: @decimal100, - task_id: ^t3_id, - tournament_id: ^tournament_id, - user_id: ^u1_id, - user_name: "1" - } - ] = TournamentResult |> Repo.all() |> Enum.sort_by(&{&1.user_id, &1.task_id}) - - assert %{ - stages: [ - %{ - finished_at: finished_at, - games_count: 3, - place_in_category_rank: nil, - place_in_total_rank: nil, - score: nil, - slug: "qualification", - started_at: nil, - status: :completed, - time_spent_in_seconds: 0, - tournament_id: ^tournament_id, - wins_count: 3 - } - ] - } = Repo.one(UserEvent) - - assert finished_at - end -end diff --git a/services/app/apps/codebattle/test/codebattle/tournament/entire/swiss_qualification_timeout_test.exs b/services/app/apps/codebattle/test/codebattle/tournament/entire/swiss_qualification_timeout_test.exs deleted file mode 100644 index c7eb9dbec..000000000 --- a/services/app/apps/codebattle/test/codebattle/tournament/entire/swiss_qualification_timeout_test.exs +++ /dev/null @@ -1,301 +0,0 @@ -defmodule Codebattle.Tournament.Entire.SwissQualificationTimeoutTest do - use Codebattle.DataCase, async: false - - import Codebattle.Tournament.Helpers - import Codebattle.TournamentTestHelpers - - alias Codebattle.PubSub.Message - alias Codebattle.Repo - alias Codebattle.Tournament - alias Codebattle.Tournament.TournamentResult - alias Codebattle.UserEvent - - @decimal100 Decimal.new("100.0") - @decimal0 Decimal.new("0.0") - - test "works with single player and timeout" do - [%{id: t1_id}, %{id: t2_id}, %{id: t3_id}] = insert_list(3, :task, level: "easy") - insert(:task_pack, name: "tp", task_ids: [t1_id, t2_id, t3_id]) - - event = - insert(:event, - stages: [ - %{ - slug: "qualification", - name: "Qualification", - status: :active, - type: :tournament, - playing_type: :single - } - ] - ) - - creator = insert(:user) - user1 = %{id: u1_id} = insert(:user, %{clan_id: 1, clan: "1", name: "1"}) - - {:ok, tournament} = - Tournament.Context.create(%{ - "starts_at" => "2025-02-24T06:00", - "name" => "Qualification", - "event_id" => to_string(event.id), - "user_timezone" => "Etc/UTC", - "level" => "easy", - "task_pack_name" => "tp", - "creator" => creator, - "break_duration_seconds" => 0, - "task_provider" => "task_pack", - "score_strategy" => "win_loss", - "task_strategy" => "sequential", - "ranking_type" => "by_clan", - "type" => "swiss", - "state" => "waiting_participants", - "use_clan" => "false", - "use_chat" => "false", - "rounds_limit" => "3", - "players_limit" => 2 - }) - - insert(:user_event, - event: event, - user: user1, - stages: [ - %{ - slug: "qualification", - status: :pending, - place_in_total_rank: nil, - place_in_category_rank: nil, - score: nil, - wins_count: nil, - games_count: nil, - tournament_id: tournament.id, - time_spent_in_seconds: nil - } - ] - ) - - users = [%{id: p1_id} = user1] - - admin_topic = tournament_admin_topic(tournament.id) - common_topic = tournament_common_topic(tournament.id) - player1_topic = tournament_player_topic(tournament.id, p1_id) - - Codebattle.PubSub.subscribe(admin_topic) - Codebattle.PubSub.subscribe(common_topic) - Codebattle.PubSub.subscribe(player1_topic) - - Tournament.Server.handle_event(tournament.id, :join, %{users: users}) - - Enum.each(users, fn %{id: id, name: name} -> - assert_received %Message{ - topic: ^common_topic, - event: "tournament:player:joined", - payload: %{player: %{name: ^name, id: ^id, state: "active"}} - } - end) - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - Tournament.Server.handle_event(tournament.id, :start, %{ - user: creator, - time_step_ms: 20_000, - min_time_sec: 0 - }) - - assert_received %Message{ - topic: ^admin_topic, - event: "tournament:updated", - payload: %{ - tournament: %{ - state: "active", - current_round_position: 0, - break_state: "off", - last_round_ended_at: nil, - last_round_started_at: _ - } - } - } - - assert_received %Message{ - topic: ^common_topic, - event: "tournament:round_created", - payload: %{ - tournament: %{ - state: "active", - current_round_position: 0, - break_state: "off", - last_round_ended_at: nil, - last_round_started_at: _ - } - } - } - - assert_received %Message{ - topic: ^player1_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{task_id: ^t1_id, state: "playing"}, - players: [%{}, %{}] - } - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - tournament = Tournament.Context.get(tournament.id) - matches = get_matches(tournament) - - assert players_count(tournament) == 2 - assert Enum.count(matches) == 1 - - # win first game - win_active_match(tournament, user1) - :timer.sleep(100) - - assert_received %Message{ - topic: ^player1_topic, - event: "tournament:match:upserted", - payload: %{ - match: %{state: "game_over"}, - players: [%{}, %{}] - } - } - - assert_received %Message{ - topic: ^player1_topic, - event: "tournament:match:upserted", - payload: %{} - } - - assert_received %Message{ - topic: ^admin_topic, - event: "tournament:updated", - payload: %{} - } - - assert_received %Message{ - topic: ^admin_topic, - event: "tournament:updated", - payload: %{} - } - - assert_received %Message{ - topic: ^common_topic, - event: "tournament:round_finished", - payload: %{ - tournament: %{ - state: "active", - current_round_position: 0, - break_state: "on" - } - } - } - - assert_received %Message{ - topic: ^common_topic, - event: "tournament:round_created", - payload: %{ - tournament: %{ - state: "active", - current_round_position: 1, - break_state: "off" - } - } - } - - assert_received %Message{ - topic: ^admin_topic, - event: "tournament:updated", - payload: %{} - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - :timer.sleep(100) - - tournament = Tournament.Context.get(tournament.id) - matches = get_matches(tournament) - - assert Enum.count(matches) == 2 - - Tournament.Server.handle_event(tournament.id, :finish_tournament, %{}) - :timer.sleep(300) - - assert_received %Message{ - topic: ^player1_topic, - event: "tournament:match:upserted", - payload: %{match: %{state: "timeout"}} - } - - assert_received %Message{ - topic: ^common_topic, - event: "tournament:finished", - payload: %{ - tournament: %{ - type: "swiss", - state: "finished", - current_round_position: 1, - break_state: "off", - last_round_ended_at: _, - last_round_started_at: _ - } - } - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - tournament = %{id: tournament_id} = Tournament.Context.get(tournament.id) - matches = get_matches(tournament) - - assert Enum.count(matches) == 2 - - assert tournament.current_round_position == 1 - - assert [ - %{ - score: 3, - clan_id: 1, - duration_sec: 0, - game_id: _, - id: _, - level: "easy", - result_percent: @decimal100, - task_id: ^t1_id, - tournament_id: ^tournament_id, - user_id: ^u1_id, - user_name: "1" - }, - %{ - score: 1, - clan_id: 1, - duration_sec: 0, - game_id: _, - id: _, - level: "easy", - result_percent: @decimal0, - task_id: ^t2_id, - tournament_id: ^tournament_id, - user_id: ^u1_id, - user_name: "1" - } - ] = TournamentResult |> Repo.all() |> Enum.sort_by(&{&1.user_id, &1.task_id}) - - assert %{ - stages: [ - %{ - finished_at: finished_at, - games_count: 3, - place_in_category_rank: nil, - place_in_total_rank: nil, - score: nil, - slug: "qualification", - started_at: nil, - status: :completed, - time_spent_in_seconds: 0, - tournament_id: ^tournament_id, - wins_count: 1 - } - ] - } = Repo.one(UserEvent) - - assert finished_at - end -end diff --git a/services/app/apps/codebattle/test/codebattle/tournament/individual_test.exs b/services/app/apps/codebattle/test/codebattle/tournament/individual_test.exs deleted file mode 100644 index e8ccdb0be..000000000 --- a/services/app/apps/codebattle/test/codebattle/tournament/individual_test.exs +++ /dev/null @@ -1,251 +0,0 @@ -defmodule Codebattle.Tournament.IndividualTest do - use Codebattle.IntegrationCase, async: false - - import Codebattle.Tournament.Helpers - import Codebattle.TournamentTestHelpers - - alias Codebattle.Tournament - - setup do - insert(:task, level: "elementary", name: "2") - - :ok - end - - describe "complete players" do - test "scales to 2 when 1 player" do - user = insert(:user) - - {:ok, tournament} = - Tournament.Context.create(%{ - "starts_at" => "2022-02-24T06:00", - "name" => "Test Swiss", - "user_timezone" => "Etc/UTC", - "level" => "elementary", - "creator" => user, - "break_duration_seconds" => 0, - "type" => "individual", - "state" => "waiting_participants" - }) - - Tournament.Server.handle_event(tournament.id, :join, %{user: user}) - Tournament.Server.handle_event(tournament.id, :start, %{user: user}) - - tournament = Tournament.Context.get(tournament.id) - - assert players_count(tournament) == 2 - end - - test "scales to 4 when 3 player" do - user = insert(:user) - users = insert_list(2, :user) - - {:ok, tournament} = - Tournament.Context.create(%{ - "starts_at" => "2022-02-24T06:00", - "name" => "Test Swiss", - "user_timezone" => "Etc/UTC", - "level" => "elementary", - "creator" => user, - "break_duration_seconds" => 0, - "type" => "individual", - "state" => "waiting_participants" - }) - - Tournament.Server.handle_event(tournament.id, :join, %{user: user}) - Tournament.Server.handle_event(tournament.id, :join, %{users: users}) - Tournament.Server.handle_event(tournament.id, :start, %{user: user}) - - tournament = Tournament.Context.get(tournament.id) - - assert players_count(tournament) == 4 - end - - test "scales to 8 when 5 players" do - user = insert(:user) - users = insert_list(4, :user) - - {:ok, tournament} = - Tournament.Context.create(%{ - "starts_at" => "2022-02-24T06:00", - "name" => "Test Swiss", - "user_timezone" => "Etc/UTC", - "level" => "elementary", - "creator" => user, - "break_duration_seconds" => 0, - "type" => "individual", - "state" => "waiting_participants" - }) - - Tournament.Server.handle_event(tournament.id, :join, %{user: user}) - Tournament.Server.handle_event(tournament.id, :join, %{users: users}) - Tournament.Server.handle_event(tournament.id, :start, %{user: user}) - - tournament = Tournament.Context.get(tournament.id) - - assert players_count(tournament) == 8 - end - - test "scales to 16 when 9 players" do - user = insert(:user) - users = insert_list(8, :user) - - {:ok, tournament} = - Tournament.Context.create(%{ - "starts_at" => "2022-02-24T06:00", - "name" => "Test Swiss", - "user_timezone" => "Etc/UTC", - "level" => "elementary", - "creator" => user, - "break_duration_seconds" => 0, - "type" => "individual", - "state" => "waiting_participants" - }) - - Tournament.Server.handle_event(tournament.id, :join, %{user: user}) - Tournament.Server.handle_event(tournament.id, :join, %{users: users}) - Tournament.Server.handle_event(tournament.id, :start, %{user: user}) - - tournament = Tournament.Context.get(tournament.id) - - assert players_count(tournament) == 16 - end - - test "scales to 32 when 18 players" do - user = insert(:user) - users = insert_list(17, :user) - - {:ok, tournament} = - Tournament.Context.create(%{ - "starts_at" => "2022-02-24T06:00", - "name" => "Test Swiss", - "user_timezone" => "Etc/UTC", - "level" => "elementary", - "creator" => user, - "break_duration_seconds" => 0, - "type" => "individual", - "state" => "waiting_participants" - }) - - Tournament.Server.handle_event(tournament.id, :join, %{user: user}) - Tournament.Server.handle_event(tournament.id, :join, %{users: users}) - Tournament.Server.handle_event(tournament.id, :start, %{user: user}) - - tournament = Tournament.Context.get(tournament.id) - - assert players_count(tournament) == 32 - end - - test "limits players" do - user = insert(:user) - users = insert_list(9, :user) - - {:ok, tournament} = - Tournament.Context.create(%{ - "starts_at" => "2022-02-24T06:00", - "name" => "Test Swiss", - "user_timezone" => "Etc/UTC", - "level" => "elementary", - "creator" => user, - "break_duration_seconds" => 0, - "type" => "individual", - "state" => "waiting_participants", - "players_limit" => 7 - }) - - Tournament.Server.handle_event(tournament.id, :join, %{user: user}) - Tournament.Server.handle_event(tournament.id, :join, %{users: users}) - Tournament.Server.handle_event(tournament.id, :start, %{user: user}) - - tournament = Tournament.Context.get(tournament.id) - - assert players_count(tournament) == 8 - end - - test "scales to 128 when 65 players" do - user = insert(:user) - users = insert_list(64, :user) - - {:ok, tournament} = - Tournament.Context.create(%{ - "starts_at" => "2022-02-24T06:00", - "name" => "Test Swiss", - "user_timezone" => "Etc/UTC", - "level" => "elementary", - "creator" => user, - "break_duration_seconds" => 0, - "type" => "individual", - "state" => "waiting_participants", - "players_limit" => 200 - }) - - Tournament.Server.handle_event(tournament.id, :join, %{user: user}) - Tournament.Server.handle_event(tournament.id, :join, %{users: users}) - Tournament.Server.handle_event(tournament.id, :start, %{user: user}) - - tournament = Tournament.Context.get(tournament.id) - - assert players_count(tournament) == 128 - end - end - - describe "finish_match/2" do - test "creates new round after all matches finished" do - user1 = insert(:user) - user2 = insert(:user) - user3 = insert(:user) - user4 = insert(:user) - - {:ok, tournament} = - Tournament.Context.create(%{ - "starts_at" => "2022-02-24T06:00", - "name" => "Test Swiss", - "user_timezone" => "Etc/UTC", - "level" => "elementary", - "creator" => user1, - "break_duration_seconds" => 0, - "type" => "individual", - "state" => "waiting_participants", - "players_limit" => 200 - }) - - Tournament.Server.handle_event(tournament.id, :join, %{user: user1}) - Tournament.Server.handle_event(tournament.id, :join, %{user: user2}) - Tournament.Server.handle_event(tournament.id, :join, %{user: user3}) - Tournament.Server.handle_event(tournament.id, :join, %{user: user4}) - Tournament.Server.handle_event(tournament.id, :start, %{user: user1}) - - tournament = Tournament.Context.get(tournament.id) - - [match1, match2] = get_matches(tournament) - - [id1, _id2] = match1.player_ids - [id3, _id4] = match2.player_ids - - player1 = Tournament.Players.get_player(tournament, id1) - - tournament = Tournament.Context.get(tournament.id) - - assert tournament.current_round_position == 0 - win_active_match(tournament, player1) - tournament = Tournament.Context.get(tournament.id) - - assert tournament.current_round_position == 0 - assert matches_count(tournament) == 2 - - player3 = Tournament.Players.get_player(tournament, id3) - win_active_match(tournament, player3) - tournament = Tournament.Context.get(tournament.id) - - assert tournament.current_round_position == 1 - - assert matches_count(tournament) == 3 - - win_active_match(tournament, player1) - - tournament = Tournament.Context.get(tournament.id) - - assert tournament.state == "finished" - end - end -end diff --git a/services/app/apps/codebattle/test/codebattle/tournament/pair_builder/by_clan_and_score_test.exs b/services/app/apps/codebattle/test/codebattle/tournament/pair_builder/by_clan_and_score_test.exs deleted file mode 100644 index bf707191a..000000000 --- a/services/app/apps/codebattle/test/codebattle/tournament/pair_builder/by_clan_and_score_test.exs +++ /dev/null @@ -1,121 +0,0 @@ -defmodule Codebattle.Tournament.PairBuilder.ByClanAndScoreTest do - use Codebattle.DataCase - - @matcher Codebattle.Tournament.PairBuilder.ByClanAndScore - - describe "call/1" do - test "one player" do - users = build_users([1]) - - {pairs, unmatched_player_ids} = @matcher.call(users) - - assert Enum.empty?(pairs) - assert length(unmatched_player_ids) == 1 - end - - test "two players" do - users = build_users([1, 1]) - - {pairs, unmatched_player_ids} = @matcher.call(users) - - assert length(pairs) == 1 - assert Enum.empty?(unmatched_player_ids) - end - - test "simple case with 6,4,4 players linear score" do - users = build_users([6, 4, 4]) - - {pairs, unmatched_player_ids} = @matcher.call(users) - - assert length(pairs) > 5 - assert length(unmatched_player_ids) < 3 - end - - test "simple case with 6,4,4 players specific score" do - users = - Enum.shuffle([ - {257, 0, 10}, - {258, 0, 20}, - {259, 0, 30}, - {260, 0, 40}, - {261, 0, 50}, - {262, 0, 60}, - {263, 1, 11}, - {264, 1, 21}, - {265, 1, 31}, - {266, 1, 41}, - {267, 2, 12}, - {268, 2, 22}, - {269, 2, 32}, - {270, 2, 42} - ]) - - {pairs, unmatched_player_ids} = @matcher.call(users) - - assert [[263, 257], [258, 267], [268, 264], [265, 259], [260, 269], [261, 266], [262, 270]] == - pairs - - assert Enum.empty?(unmatched_player_ids) - end - - test "simple case with unmatched players" do - users = build_users([4, 3]) - - {pairs, unmatched_player_ids} = @matcher.call(users) - - assert length(pairs) == 3 - assert length(unmatched_player_ids) == 1 - end - - test "10_000 players with small amount of clans" do - users = build_users([4000, 3000, 2000, 1000, 100, 10, 1]) - - {pairs, unmatched_player_ids} = @matcher.call(users) - - assert length(pairs) > 5040 - assert length(unmatched_player_ids) > 0 - end - - @tag :skip - test "1000 clans ~ 100 players" do - users = - 0..1000 - |> Enum.map(fn _id -> Enum.random(30..100) end) - |> build_users() - - {execution_time, {pairs, unmatched_player_ids}} = - :timer.tc(fn -> @matcher.call(users) end) - - assert execution_time / 1000 < 3000 - assert length(pairs) > 10_000 - assert length(unmatched_player_ids) < 2 - end - - @tag :skip - test "10_000 clans with small amount of players" do - users = - 0..10_000 - |> Enum.map(fn _id -> Enum.random(2..3) end) - |> build_users() - - {execution_time, {pairs, unmatched_player_ids}} = - :timer.tc(fn -> @matcher.call(users) end) - - assert execution_time / 1000 < 7000 - assert length(pairs) > 10_000 - assert length(unmatched_player_ids) < 2 - end - end - - defp build_users(counts) do - counts - |> Enum.with_index(1) - |> Enum.flat_map(fn {count, index} -> - Enum.map(1..count, fn id -> - user_id = index * max(256, Enum.max(counts)) + id - {user_id, index, rem(user_id, length(counts))} - end) - end) - |> Enum.shuffle() - end -end diff --git a/services/app/apps/codebattle/test/codebattle/tournament/pair_builder/by_clan_test.exs b/services/app/apps/codebattle/test/codebattle/tournament/pair_builder/by_clan_test.exs deleted file mode 100644 index 7d8f1235d..000000000 --- a/services/app/apps/codebattle/test/codebattle/tournament/pair_builder/by_clan_test.exs +++ /dev/null @@ -1,91 +0,0 @@ -defmodule Codebattle.Tournament.PairBuilder.ByClanTest do - use Codebattle.DataCase - - @matcher Codebattle.Tournament.PairBuilder.ByClan - - describe "call/1" do - test "one player" do - users = build_users([1]) - - {pairs, unmatched_player_ids} = @matcher.call(users) - - assert Enum.empty?(pairs) - assert length(unmatched_player_ids) == 1 - end - - test "two players" do - users = build_users([1, 1]) - - {pairs, unmatched_player_ids} = @matcher.call(users) - - assert length(pairs) == 1 - assert Enum.empty?(unmatched_player_ids) - end - - test "simple case with 6,4,4 players" do - users = build_users([6, 4, 4]) - - {pairs, unmatched_player_ids} = @matcher.call(users) - - assert length(pairs) == 7 - assert Enum.empty?(unmatched_player_ids) - end - - test "simple case with unmatched players" do - users = build_users([4, 3]) - - {pairs, unmatched_player_ids} = @matcher.call(users) - - assert length(pairs) == 3 - assert length(unmatched_player_ids) == 1 - end - - test "10_000 players with small amount of clans" do - users = build_users([4000, 3000, 2000, 1000, 100, 10, 1]) - - {pairs, unmatched_player_ids} = @matcher.call(users) - - assert length(pairs) == 5055 - assert length(unmatched_player_ids) == 1 - end - - @tag :skip - test "1000 clans ~ 100 players" do - users = - 0..1000 - |> Enum.map(fn _id -> Enum.random(30..100) end) - |> build_users() - - {execution_time, {pairs, unmatched_player_ids}} = - :timer.tc(fn -> @matcher.call(users) end) - - assert execution_time / 1000 < 3000 - assert length(pairs) > 10_000 - assert length(unmatched_player_ids) < 2 - end - - @tag :skip - test "10_000 clans with small amount of players" do - users = - 0..10_000 - |> Enum.map(fn _id -> Enum.random(2..3) end) - |> build_users() - - {execution_time, {pairs, unmatched_player_ids}} = - :timer.tc(fn -> @matcher.call(users) end) - - assert execution_time / 1000 < 7000 - assert length(pairs) > 10_000 - assert length(unmatched_player_ids) < 2 - end - end - - defp build_users(counts) do - counts - |> Enum.with_index() - |> Enum.flat_map(fn {count, index} -> - Enum.map(1..count, fn user_id -> {index * Enum.max(counts) + user_id, index} end) - end) - |> Enum.shuffle() - end -end diff --git a/services/app/apps/codebattle/test/codebattle/tournament/score/one_zero_test.exs b/services/app/apps/codebattle/test/codebattle/tournament/score/one_zero_test.exs deleted file mode 100644 index 9ad9f8a54..000000000 --- a/services/app/apps/codebattle/test/codebattle/tournament/score/one_zero_test.exs +++ /dev/null @@ -1,37 +0,0 @@ -defmodule Codebattle.Tournament.Score.OneZeroTest do - use Codebattle.DataCase - - import Codebattle.Tournament.Score.OneZero - - @test_results [100.0, 80.0, 60.0, 40.0, 20.0, 10.0, 3.0] - - describe "get_score/2" do - test "elementary level" do - level = "elementary" - - assert [1, 0, 0, 0, 0, 0, 0] = - Enum.map(@test_results, fn tests -> get_score(level, tests) end) - end - - test "easy level" do - level = "easy" - - assert [1, 0, 0, 0, 0, 0, 0] = - Enum.map(@test_results, fn tests -> get_score(level, tests) end) - end - - test "medium level" do - level = "medium" - - assert [1, 0, 0, 0, 0, 0, 0] = - Enum.map(@test_results, fn tests -> get_score(level, tests) end) - end - - test "hard level" do - level = "hard" - - assert [1, 0, 0, 0, 0, 0, 0] = - Enum.map(@test_results, fn tests -> get_score(level, tests) end) - end - end -end diff --git a/services/app/apps/codebattle/test/codebattle/tournament/score/time_and_tests_test.exs b/services/app/apps/codebattle/test/codebattle/tournament/score/time_and_tests_test.exs deleted file mode 100644 index 150793167..000000000 --- a/services/app/apps/codebattle/test/codebattle/tournament/score/time_and_tests_test.exs +++ /dev/null @@ -1,176 +0,0 @@ -defmodule Codebattle.Tournament.Score.TimeAndTestsTest do - use Codebattle.DataCase - - import Codebattle.Tournament.Score.TimeAndTests - - @test_results [100.0, 80.0, 60.0, 40.0, 20.0, 10.0, 3.0] - - describe "get_score/3" do - test "elementary level" do - level = "elementary" - durations = [1.0, 10.0, 20.0, 60.0, 2 * 60.0, 3 * 60.0, 4 * 60.0, 5 * 60.0, 6 * 60.0] - - assert [ - [30, 24, 18, 12, 6, 3, 1], - [30, 24, 18, 12, 6, 3, 1], - [29, 23, 17, 12, 6, 3, 1], - [25, 20, 15, 10, 5, 2, 1], - [19, 15, 11, 7, 4, 2, 1], - [13, 10, 8, 5, 3, 1, 0], - [6, 5, 4, 3, 1, 1, 0], - [0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0] - ] = - Enum.map(durations, fn d -> - Enum.map( - @test_results, - fn tests -> get_score(level, tests, d) end - ) - end) - end - - test "easy level" do - level = "easy" - - durations = [ - 1.0, - 20.0, - 60.0, - 2 * 60.0, - 3 * 60.0, - 4 * 60.0, - 5 * 60.0, - 6 * 60.0, - 7 * 60.0, - 8 * 60.0, - 9 * 60.0 - ] - - assert [ - [100, 80, 60, 40, 20, 10, 3], - [100, 80, 60, 40, 20, 10, 3], - [91, 73, 55, 37, 18, 9, 3], - [78, 63, 47, 31, 16, 8, 2], - [66, 52, 39, 26, 13, 7, 2], - [53, 42, 32, 21, 11, 5, 2], - [40, 32, 24, 16, 8, 4, 1], - [27, 21, 16, 11, 5, 3, 1], - [14, 11, 8, 6, 3, 1, 0], - [1, 1, 1, 0, 0, 0, 0], - [1, 1, 1, 0, 0, 0, 0] - ] = - Enum.map(durations, fn d -> - Enum.map( - @test_results, - fn tests -> get_score(level, tests, d) end - ) - end) - end - - test "medium level" do - level = "medium" - - durations = [ - 1.0, - 40.0, - 60.0, - 2 * 60.0, - 3 * 60.0, - 4 * 60.0, - 5 * 60.0, - 6 * 60.0, - 7 * 60.0, - 8 * 60.0, - 10 * 60.0, - 11 * 60.0, - 12 * 60.0, - 13 * 60.0, - 14 * 60.0 - ] - - assert [ - [300, 240, 180, 120, 60, 30, 9], - [300, 240, 180, 120, 60, 30, 9], - [292, 234, 175, 117, 58, 29, 9], - [268, 214, 161, 107, 54, 27, 8], - [244, 195, 146, 98, 49, 24, 7], - [220, 176, 132, 88, 44, 22, 7], - [196, 157, 117, 78, 39, 20, 6], - [172, 137, 103, 69, 34, 17, 5], - [147, 118, 88, 59, 29, 15, 4], - [123, 99, 74, 49, 25, 12, 4], - [75, 60, 45, 30, 15, 8, 2], - [51, 41, 31, 20, 10, 5, 2], - [27, 22, 16, 11, 5, 3, 1], - [3, 2, 2, 1, 1, 0, 0], - [3, 2, 2, 1, 1, 0, 0] - ] = - Enum.map(durations, fn d -> - Enum.map( - @test_results, - fn tests -> get_score(level, tests, d) end - ) - end) - end - - test "hard level" do - level = "hard" - - durations = [ - 1.0, - 60.0, - 2 * 60.0, - 3 * 60.0, - 4 * 60.0, - 5 * 60.0, - 6 * 60.0, - 7 * 60.0, - 8 * 60.0, - 10 * 60.0, - 11 * 60.0, - 12 * 60.0, - 13 * 60.0, - 14 * 60.0, - 15 * 60.0, - 16 * 60.0, - 17 * 60.0, - 18 * 60.0, - 19 * 60.0, - 20 * 60.0, - 21 * 60.0, - 22 * 60.0 - ] - - assert [ - [1000, 800, 600, 400, 200, 100, 30], - [1000, 800, 600, 400, 200, 100, 30], - [951, 760, 570, 380, 190, 95, 29], - [901, 721, 541, 360, 180, 90, 27], - [852, 681, 511, 341, 170, 85, 26], - [802, 642, 481, 321, 160, 80, 24], - [753, 602, 452, 301, 151, 75, 23], - [703, 562, 422, 281, 141, 70, 21], - [654, 523, 392, 261, 131, 65, 20], - [555, 444, 333, 222, 111, 55, 17], - [505, 404, 303, 202, 101, 51, 15], - [456, 364, 273, 182, 91, 46, 14], - [406, 325, 244, 162, 81, 41, 12], - [357, 285, 214, 143, 71, 36, 11], - [307, 246, 184, 123, 61, 31, 9], - [258, 206, 155, 103, 52, 26, 8], - [208, 166, 125, 83, 42, 21, 6], - [159, 127, 95, 63, 32, 16, 5], - [109, 87, 65, 44, 22, 11, 3], - [60, 48, 36, 24, 12, 6, 2], - [10, 8, 6, 4, 2, 1, 0], - [10, 8, 6, 4, 2, 1, 0] - ] = - Enum.map(durations, fn d -> - Enum.map( - @test_results, - fn tests -> get_score(level, tests, d) end - ) - end) - end - end -end diff --git a/services/app/apps/codebattle/test/codebattle/tournament/score/win_loss_test.exs b/services/app/apps/codebattle/test/codebattle/tournament/score/win_loss_test.exs deleted file mode 100644 index e0a871676..000000000 --- a/services/app/apps/codebattle/test/codebattle/tournament/score/win_loss_test.exs +++ /dev/null @@ -1,37 +0,0 @@ -defmodule Codebattle.Tournament.Score.WinLossTest do - use Codebattle.DataCase - - import Codebattle.Tournament.Score.WinLoss - - @test_results [100.0, 80.0, 60.0, 40.0, 20.0, 10.0, 3.0] - - describe "get_score/2" do - test "elementary level" do - level = "elementary" - - assert [2, 1, 1, 1, 1, 1, 1] = - Enum.map(@test_results, fn tests -> get_score(level, tests) end) - end - - test "easy level" do - level = "easy" - - assert [3, 1, 1, 1, 1, 1, 1] = - Enum.map(@test_results, fn tests -> get_score(level, tests) end) - end - - test "medium level" do - level = "medium" - - assert [5, 1, 1, 1, 1, 1, 1] = - Enum.map(@test_results, fn tests -> get_score(level, tests) end) - end - - test "hard level" do - level = "hard" - - assert [8, 1, 1, 1, 1, 1, 1] = - Enum.map(@test_results, fn tests -> get_score(level, tests) end) - end - end -end diff --git a/services/app/apps/codebattle/test/codebattle/tournament/team_test.exs b/services/app/apps/codebattle/test/codebattle/tournament/team_test.exs deleted file mode 100644 index cb28da20f..000000000 --- a/services/app/apps/codebattle/test/codebattle/tournament/team_test.exs +++ /dev/null @@ -1,44 +0,0 @@ -defmodule Codebattle.Tournament.TeamTest do - use Codebattle.DataCase, async: false - - import Codebattle.Tournament.Helpers - - alias Codebattle.Tournament - - setup do - insert(:task, level: "elementary", name: "2") - - :ok - end - - describe "complete players" do - test "add bots to complete teams" do - insert_list(2, :task, level: "easy") - user1 = insert(:user) - user2 = insert(:user) - - {:ok, tournament} = - Tournament.Context.create(%{ - "starts_at" => "2022-02-24T06:00", - "name" => "Test Swiss", - "user_timezone" => "Etc/UTC", - "level" => "easy", - "creator" => user1, - "break_duration_seconds" => 0, - "type" => "team", - "state" => "waiting_participants", - "players_limit" => 200, - "team_1_name" => "1", - "team_2_name" => "2" - }) - - Tournament.Server.handle_event(tournament.id, :join, %{user: user1, team_id: 0}) - Tournament.Server.handle_event(tournament.id, :join, %{user: user2, team_id: 0}) - Tournament.Server.handle_event(tournament.id, :start, %{user: user1}) - - tournament = Tournament.Context.get(tournament.id) - - assert players_count(tournament) == 4 - end - end -end diff --git a/services/app/apps/codebattle/test/codebattle/tournament/tournament_result_test.exs b/services/app/apps/codebattle/test/codebattle/tournament/tournament_result_test.exs deleted file mode 100644 index c2c51b895..000000000 --- a/services/app/apps/codebattle/test/codebattle/tournament/tournament_result_test.exs +++ /dev/null @@ -1,730 +0,0 @@ -defmodule Codebattle.Tournament.TournamenResultTest do - use Codebattle.DataCase, async: false - - alias Codebattle.Tournament.TournamentResult - - describe "get_player_results" do - test "calculates results correctly by_player_95th_percentile" do - [clan1, clan2, clan3, clan4, clan5, clan6, clan7, clan8] = - Enum.map(1..8, fn i -> insert(:clan, name: "c#{i}", long_name: "l#{i}") end) - - task1 = insert(:task, level: "elementary", name: "t1") - task2 = insert(:task, level: "easy", name: "t2") - task3 = insert(:task, level: "medium", name: "t3") - task4 = insert(:task, level: "hard", name: "t4") - - [user11, user12, user13, user14, user15, user16, user17] = - Enum.map(1..7, fn i -> insert(:user, name: "u1#{i}", clan_id: clan1.id) end) - - [user21, user22, user23, user24, user25, user26] = - Enum.map(1..6, fn i -> insert(:user, name: "u2#{i}", clan_id: clan2.id) end) - - [user31, user32, user33, user34, user35] = - Enum.map(1..5, fn i -> insert(:user, name: "u3#{i}", clan_id: clan3.id) end) - - [user41, user42, user43, user44] = - Enum.map(1..4, fn i -> insert(:user, name: "u4#{i}", clan_id: clan4.id) end) - - [user51, user52, user53] = - Enum.map(1..3, fn i -> insert(:user, name: "u5#{i}", clan_id: clan5.id) end) - - [user61, user62] = - Enum.map(1..2, fn i -> insert(:user, name: "u6#{i}", clan_id: clan6.id) end) - - user71 = insert(:user, name: "u71", clan_id: clan7.id) - user81 = insert(:user, name: "u81", clan_id: clan8.id) - - tournament = insert(:tournament, type: "arena", ranking_type: "by_player_95th_percentile") - - insert_game(task4, tournament, user11, user21, 100, 100.0, 70.0) - insert_game(task4, tournament, user12, user22, 200, 100.0, 60.0) - insert_game(task4, tournament, user13, user23, 400, 100.0, 50.0) - insert_game(task4, tournament, user14, user24, 600, 100.0, 40.0) - insert_game(task4, tournament, user15, user25, 800, 100.0, 30.0) - insert_game(task4, tournament, user16, user26, 1000, 100.0, 20.0) - insert_game(task4, tournament, user17, user81, 1200, 100.0, 10.0) - - insert_game(task3, tournament, user11, user21, 100, 100.0, 90.0) - insert_game(task3, tournament, user12, user22, 120, 100.0, 80.0) - insert_game(task3, tournament, user13, user23, 140, 100.0, 70.0) - insert_game(task3, tournament, user14, user24, 160, 100.0, 60.0) - insert_game(task3, tournament, user31, user41, 180, 100.0, 50.0) - insert_game(task3, tournament, user32, user42, 200, 100.0, 40.0) - insert_game(task3, tournament, user33, user43, 220, 100.0, 30.0) - insert_game(task3, tournament, user34, user44, 240, 100.0, 20.0) - insert_game(task3, tournament, user35, user71, 260, 100.0, 10.0) - - insert_game(task2, tournament, user11, user21, 10, 100.0, 90.0) - insert_game(task2, tournament, user12, user22, 12, 100.0, 80.0) - insert_game(task2, tournament, user13, user23, 14, 100.0, 70.0) - insert_game(task2, tournament, user51, user61, 16, 100.0, 60.0) - insert_game(task2, tournament, user52, user62, 18, 100.0, 50.0) - insert_game(task2, tournament, user53, user71, 20, 100.0, 40.0) - - insert_game(task1, tournament, user11, user21, 100, 100.0, 10.0) - insert_game(task1, tournament, user71, user81, 10, 80.0, 10.0) - - TournamentResult.upsert_results(tournament) - - assert [ - %{ - user_name: "u11", - user_id: _, - clan_id: _, - wins_count: 4, - clan_name: "c1", - total_score: 1430, - total_duration_sec: 310, - clan_rank: 1 - }, - %{ - user_name: "u12", - user_id: _, - clan_id: _, - wins_count: 3, - clan_name: "c1", - total_score: 1321, - total_duration_sec: 332, - clan_rank: 1 - }, - %{ - user_name: "u13", - user_id: _, - clan_id: _, - wins_count: 3, - clan_name: "c1", - total_score: 1139, - total_duration_sec: 554, - clan_rank: 1 - }, - %{ - user_name: "u14", - user_id: _, - clan_id: _, - wins_count: 2, - clan_name: "c1", - total_score: 898, - total_duration_sec: 760, - clan_rank: 1 - }, - %{ - user_name: "u15", - user_id: _, - clan_id: _, - wins_count: 1, - clan_name: "c1", - total_score: 536, - total_duration_sec: 800, - clan_rank: 1 - }, - %{ - user_name: "u21", - user_id: _, - clan_id: _, - wins_count: 0, - clan_name: "c2", - total_score: 1063, - total_duration_sec: 310, - clan_rank: 2 - }, - %{ - user_name: "u22", - user_id: _, - clan_id: _, - wins_count: 0, - clan_name: "c2", - total_score: 868, - total_duration_sec: 332, - clan_rank: 2 - }, - %{ - user_name: "u23", - user_id: _, - clan_id: _, - wins_count: 0, - clan_name: "c2", - total_score: 634, - total_duration_sec: 554, - clan_rank: 2 - }, - %{ - user_name: "u24", - user_id: _, - clan_id: _, - wins_count: 0, - clan_name: "c2", - total_score: 405, - total_duration_sec: 760, - clan_rank: 2 - }, - %{ - user_name: "u25", - user_id: _, - clan_id: _, - wins_count: 0, - clan_name: "c2", - total_score: 161, - total_duration_sec: 800, - clan_rank: 2 - }, - %{ - user_name: "u31", - user_id: _, - clan_id: _, - wins_count: 1, - clan_name: "c3", - total_score: 195, - total_duration_sec: 180, - clan_rank: 3 - }, - %{ - user_name: "u32", - user_id: _, - clan_id: _, - wins_count: 1, - clan_name: "c3", - total_score: 166, - total_duration_sec: 200, - clan_rank: 3 - }, - %{ - user_name: "u33", - user_id: _, - clan_id: _, - wins_count: 1, - clan_name: "c3", - total_score: 137, - total_duration_sec: 220, - clan_rank: 3 - }, - %{ - user_name: "u34", - user_id: _, - clan_id: _, - wins_count: 1, - clan_name: "c3", - total_score: 108, - total_duration_sec: 240, - clan_rank: 3 - }, - %{ - user_name: "u35", - user_id: _, - clan_id: _, - wins_count: 1, - clan_name: "c3", - total_score: 90, - total_duration_sec: 260, - clan_rank: 3 - }, - %{ - user_name: "u41", - user_id: _, - clan_id: _, - wins_count: 0, - clan_name: "c4", - total_score: 98, - total_duration_sec: 180, - clan_rank: 4 - }, - %{ - user_name: "u42", - user_id: _, - clan_id: _, - wins_count: 0, - clan_name: "c4", - total_score: 66, - total_duration_sec: 200, - clan_rank: 4 - }, - %{ - user_name: "u43", - user_id: _, - clan_id: _, - wins_count: 0, - clan_name: "c4", - total_score: 41, - total_duration_sec: 220, - clan_rank: 4 - }, - %{ - user_name: "u44", - user_id: _, - clan_id: _, - wins_count: 0, - clan_name: "c4", - total_score: 22, - total_duration_sec: 240, - clan_rank: 4 - }, - %{ - user_name: "u51", - user_id: _, - clan_id: _, - wins_count: 1, - clan_name: "c5", - total_score: 57, - total_duration_sec: 16, - clan_rank: 5 - }, - %{ - user_name: "u52", - user_id: _, - clan_id: _, - wins_count: 1, - clan_name: "c5", - total_score: 42, - total_duration_sec: 18, - clan_rank: 5 - }, - %{ - user_name: "u53", - user_id: _, - clan_id: _, - wins_count: 1, - clan_name: "c5", - total_score: 30, - total_duration_sec: 20, - clan_rank: 5 - }, - %{ - user_name: "u61", - user_id: _, - clan_id: _, - wins_count: 0, - clan_name: "c6", - total_score: 34, - total_duration_sec: 16, - clan_rank: 6 - }, - %{ - user_name: "u62", - user_id: _, - clan_id: _, - wins_count: 0, - clan_name: "c6", - total_score: 21, - total_duration_sec: 18, - clan_rank: 6 - }, - %{ - user_name: "u71", - user_id: _, - clan_id: _, - wins_count: 0, - clan_name: "c7", - total_score: 45, - total_duration_sec: 290, - clan_rank: 7 - } - ] = TournamentResult.get_top_users_by_clan_ranking(tournament) - - assert [ - %{ - max: Decimal.new("1200.00"), - min: Decimal.new("100.00"), - name: "t4", - level: "hard", - task_id: task4.id, - wins_count: 7, - p5: Decimal.new("250.00"), - p25: Decimal.new("250.00"), - p50: Decimal.new("600.00"), - p75: Decimal.new("1010.00"), - p95: Decimal.new("1200.00") - }, - %{ - max: Decimal.new("260.00"), - min: Decimal.new("100.00"), - name: "t3", - level: "medium", - task_id: task3.id, - wins_count: 9, - p5: Decimal.new("140.00"), - p25: Decimal.new("140.00"), - p50: Decimal.new("180.00"), - p75: Decimal.new("240.00"), - p95: Decimal.new("260.00") - }, - %{ - max: Decimal.new("20.00"), - min: Decimal.new("10.00"), - name: "t2", - level: "easy", - task_id: task2.id, - wins_count: 6, - p5: Decimal.new("12.00"), - p25: Decimal.new("12.00"), - p50: Decimal.new("15.00"), - p75: Decimal.new("18.70"), - p95: Decimal.new("20.00") - }, - %{ - max: Decimal.new("100.00"), - min: Decimal.new("10.00"), - name: "t1", - level: "elementary", - task_id: task1.id, - wins_count: 1, - p5: Decimal.new("10.00"), - p25: Decimal.new("10.00"), - p50: Decimal.new("55.00"), - p75: Decimal.new("100.00"), - p95: Decimal.new("100.00") - } - ] == TournamentResult.get_tasks_ranking(tournament) - - assert [ - %{clan_name: "c1", game_id: _, score: 1000, user_id: _, user_name: "u11"}, - %{ - clan_id: _, - clan_name: "c1", - game_id: _, - score: 951, - user_id: _, - user_name: "u12" - }, - %{ - clan_id: _, - clan_name: "c1", - game_id: _, - score: 813, - user_id: _, - user_name: "u13" - }, - %{ - clan_id: _, - clan_name: "c1", - game_id: _, - score: 674, - user_id: _, - user_name: "u14" - }, - %{ - clan_id: _, - clan_name: "c1", - game_id: _, - score: 536, - user_id: _, - user_name: "u15" - }, - %{ - clan_id: _, - clan_name: "c1", - game_id: _, - score: 397, - user_id: _, - user_name: "u16" - }, - %{ - clan_id: _, - clan_name: "c1", - game_id: _, - score: 300, - user_id: _, - user_name: "u17" - } - ] = TournamentResult.get_top_user_by_task_ranking(tournament, task4.id) - - assert [ - %{ - user_name: "u11", - user_id: _, - score: 300, - clan_id: _, - clan_name: "c1", - game_id: _ - }, - %{ - user_name: "u12", - user_id: _, - score: 282, - clan_id: _, - clan_name: "c1", - game_id: _ - }, - %{ - user_name: "u13", - user_id: _, - score: 253, - clan_id: _, - clan_name: "c1", - game_id: _ - }, - %{ - user_name: "u14", - user_id: _, - score: 224, - clan_id: _, - clan_name: "c1", - game_id: _ - }, - %{ - user_name: "u31", - user_id: _, - score: 195, - clan_id: _, - clan_name: "c3", - game_id: _ - }, - %{ - user_name: "u32", - user_id: _, - score: 166, - clan_id: _, - clan_name: "c3", - game_id: _ - }, - %{ - user_name: "u33", - user_id: _, - score: 137, - clan_id: _, - clan_name: "c3", - game_id: _ - }, - %{ - user_name: "u34", - user_id: _, - score: 108, - clan_id: _, - clan_name: "c3", - game_id: _ - }, - %{user_name: "u35", user_id: _, score: 90, clan_id: _, clan_name: "c3", game_id: _} - ] = TournamentResult.get_top_user_by_task_ranking(tournament, task3.id) - - assert [ - %{ - user_name: "u11", - user_id: _, - score: 100, - clan_id: _, - clan_name: "c1", - game_id: _ - }, - %{ - user_name: "u12", - user_id: _, - score: 88, - clan_id: _, - clan_name: "c1", - game_id: _ - }, - %{ - user_name: "u13", - user_id: _, - score: 73, - clan_id: _, - clan_name: "c1", - game_id: _ - }, - %{ - user_name: "u51", - user_id: _, - score: 57, - clan_id: _, - clan_name: "c5", - game_id: _ - }, - %{ - user_name: "u52", - user_id: _, - score: 42, - clan_id: _, - clan_name: "c5", - game_id: _ - }, - %{user_name: "u53", user_id: _, score: 30, clan_id: _, clan_name: "c5", game_id: _} - ] = TournamentResult.get_top_user_by_task_ranking(tournament, task2.id) - - assert [ - %{ - user_name: "u11", - user_id: _, - score: 30, - clan_id: _, - clan_name: "c1", - game_id: _, - clan_long_name: "l1" - } - ] = - TournamentResult.get_top_user_by_task_ranking(tournament, task1.id) - - assert [%{start: 100, end: 100, wins_count: 0}] == - TournamentResult.get_task_duration_distribution(tournament, task1.id) - - assert [ - %{end: 11, start: 10, wins_count: 1}, - %{end: 12, start: 11, wins_count: 0}, - %{end: 13, start: 12, wins_count: 1}, - %{end: 13, start: 13, wins_count: 0}, - %{start: 13, end: 14, wins_count: 0}, - %{start: 14, end: 15, wins_count: 1}, - %{start: 15, end: 15, wins_count: 0}, - %{start: 15, end: 16, wins_count: 0}, - %{start: 16, end: 17, wins_count: 1}, - %{start: 17, end: 17, wins_count: 0}, - %{start: 17, end: 18, wins_count: 0}, - %{start: 18, end: 19, wins_count: 1}, - %{start: 19, end: 19, wins_count: 0}, - %{start: 19, end: 20, wins_count: 0}, - %{start: 20, end: 21, wins_count: 1}, - %{start: 21, end: 21, wins_count: 0} - ] == TournamentResult.get_task_duration_distribution(tournament, task2.id) - - assert [ - %{end: 111, start: 100, wins_count: 1}, - %{end: 122, start: 111, wins_count: 1}, - %{end: 133, start: 122, wins_count: 0}, - %{end: 143, start: 133, wins_count: 1}, - %{end: 154, start: 143, wins_count: 0}, - %{end: 165, start: 154, wins_count: 1}, - %{end: 175, start: 165, wins_count: 0}, - %{end: 186, start: 175, wins_count: 1}, - %{end: 197, start: 186, wins_count: 0}, - %{end: 207, start: 197, wins_count: 1}, - %{end: 218, start: 207, wins_count: 0}, - %{start: 218, end: 229, wins_count: 1}, - %{start: 229, end: 239, wins_count: 0}, - %{start: 239, end: 250, wins_count: 1}, - %{start: 250, end: 261, wins_count: 1}, - %{start: 261, end: 271, wins_count: 0} - ] == TournamentResult.get_task_duration_distribution(tournament, task3.id) - - assert [ - %{end: 174, start: 100, wins_count: 1}, - %{end: 247, start: 174, wins_count: 1}, - %{end: 320, start: 247, wins_count: 0}, - %{end: 394, start: 320, wins_count: 0}, - %{end: 467, start: 394, wins_count: 1}, - %{end: 540, start: 467, wins_count: 0}, - %{end: 614, start: 540, wins_count: 1}, - %{end: 687, start: 614, wins_count: 0}, - %{end: 760, start: 687, wins_count: 0}, - %{end: 834, start: 760, wins_count: 1}, - %{start: 834, end: 907, wins_count: 0}, - %{start: 907, end: 980, wins_count: 0}, - %{start: 980, end: 1054, wins_count: 1}, - %{start: 1054, end: 1127, wins_count: 0}, - %{start: 1127, end: 1200, wins_count: 0}, - %{start: 1200, end: 1274, wins_count: 1} - ] == TournamentResult.get_task_duration_distribution(tournament, task4.id) - - assert [ - %{ - clan_id: _, - clan_long_name: "l1", - clan_name: "c1", - performance: 860, - player_count: 7, - radius: 7, - total_score: 6021 - }, - %{ - clan_id: _, - clan_long_name: "l2", - clan_name: "c2", - performance: 535, - player_count: 6, - radius: 6, - total_score: 3210 - }, - %{ - clan_id: _, - clan_long_name: "l3", - clan_name: "c3", - performance: 139, - player_count: 5, - radius: 5, - total_score: 696 - }, - %{ - clan_id: _, - clan_long_name: "l4", - clan_name: "c4", - performance: 56, - player_count: 4, - radius: 4, - total_score: 227 - }, - %{ - clan_id: _, - clan_long_name: "l5", - clan_name: "c5", - performance: 43, - player_count: 3, - radius: 3, - total_score: 129 - }, - %{ - clan_id: _, - clan_long_name: "l6", - clan_name: "c6", - performance: 27, - player_count: 2, - radius: 2, - total_score: 55 - }, - %{ - clan_id: _, - clan_long_name: "l7", - clan_name: "c7", - performance: 45, - player_count: 1, - radius: 1, - total_score: 45 - }, - %{ - clan_id: _, - clan_long_name: "l8", - clan_name: "c8", - performance: 33, - player_count: 1, - radius: 1, - total_score: 33 - } - ] = TournamentResult.get_clans_bubble_distribution(tournament) - end - - defp insert_game(task, tournament, user1, user2, duration_sec, percent1, percent2) do - state = - if percent1 == 100.0 or percent2 == 100.0 do - "game_over" - else - "timeout" - end - - insert(:game, - state: state, - level: task.level, - duration_sec: duration_sec, - players: build_players(user1, user2, percent1, percent2), - tournament_id: tournament.id, - task: task - ) - end - - defp build_players(user1, user2, p1, p2) do - [ - %{ - id: user1.id, - name: user1.name, - clan_id: user1.clan_id, - result_percent: p1, - result: get_result(p1) - }, - %{ - id: user2.id, - name: user2.name, - clan_id: user2.clan_id, - result_percent: p2, - result: get_result(p2) - } - ] - end - - def get_result(100.0), do: "won" - def get_result(_), do: "lost" - end -end diff --git a/services/app/apps/codebattle/test/codebattle/user/scope_test.exs b/services/app/apps/codebattle/test/codebattle/user/scope_test.exs deleted file mode 100644 index c3a2e008d..000000000 --- a/services/app/apps/codebattle/test/codebattle/user/scope_test.exs +++ /dev/null @@ -1,57 +0,0 @@ -defmodule Codebattle.User.ScopeTest do - use CodebattleWeb.ConnCase, async: true - - alias Codebattle.User.Scope - - describe "#list_users" do - test "finds users by username" do - user1 = - insert(:user, %{name: "first", email: "test1@test.test", github_id: 1, rating: 2400}) - - _user2 = - insert(:user, %{name: "second", email: "test2@test.test", github_id: 2, rating: 2310}) - - _user3 = - insert(:user, %{name: "third", email: "test3@test.test", github_id: 3, rating: 2210}) - - params = %{"q" => %{"name_ilike" => "first"}} - query = Scope.list_users(params) - [result] = Repo.all(query) - assert user1.id == result.id - end - - test "sorts users by permitted attributes" do - user1 = - insert(:user, %{name: "first", email: "test1@test.test", github_id: 1, rating: 2400}) - - user2 = - insert(:user, %{name: "second", email: "test2@test.test", github_id: 2, rating: 2310}) - - _user3 = - insert(:user, %{name: "third", email: "test3@test.test", github_id: 3, rating: 2210}) - - params = %{"s" => "rating+desc"} - query = Scope.list_users(params) - [result_1, result_2] = query |> Repo.all() |> Enum.take(2) - assert result_1.id == user1.id - assert result_2.id == user2.id - end - - test "sorts users by permitted attributes in asc order" do - user1 = - insert(:user, %{name: "first", email: "test1@test.test", github_id: 1, rating: -2400}) - - user2 = - insert(:user, %{name: "second", email: "test2@test.test", github_id: 2, rating: -2310}) - - _user3 = - insert(:user, %{name: "third", email: "test3@test.test", github_id: 3, rating: 2210}) - - params = %{"s" => "rating+asc"} - query = Scope.list_users(params) - [result_1, result_2] = query |> Repo.all() |> Enum.take(2) - assert result_1.id == user1.id - assert result_2.id == user2.id - end - end -end diff --git a/services/app/apps/codebattle/test/codebattle/waiting_room/enginge_test.exs b/services/app/apps/codebattle/test/codebattle/waiting_room/enginge_test.exs deleted file mode 100644 index 26e7a694b..000000000 --- a/services/app/apps/codebattle/test/codebattle/waiting_room/enginge_test.exs +++ /dev/null @@ -1,99 +0,0 @@ -defmodule Codebattle.WaitingRoom.EngineTest do - use Codebattle.DataCase - - alias Codebattle.WaitingRoom.Engine - alias Codebattle.WaitingRoom.State - - test "matches players with clans" do - now = :os.system_time(:seconds) - joined = now - 5 - pair_with_same_opponent = now - 16 - pair_with_bot = now - 21 - - players = - Enum.shuffle([ - %{id: 1, tasks: 1, score: 1, wr_joined_at: joined, clan_id: 1}, - %{id: 2, tasks: 1, score: 4, wr_joined_at: joined, clan_id: 1}, - %{id: 3, tasks: 1, score: 3, wr_joined_at: joined, clan_id: 2}, - %{id: 4, tasks: 1, score: 5, wr_joined_at: joined, clan_id: 2}, - %{id: 5, tasks: 2, score: 6, wr_joined_at: joined, clan_id: 3}, - %{id: 6, tasks: 2, score: 8, wr_joined_at: joined, clan_id: 4}, - %{id: 7, tasks: 2, score: 9, wr_joined_at: joined, clan_id: 5}, - %{id: 8, tasks: 3, score: 9, wr_joined_at: joined, clan_id: 5}, - %{id: 9, tasks: 3, score: 9, wr_joined_at: joined, clan_id: 6}, - %{id: 10, tasks: 4, score: 9, wr_joined_at: joined, clan_id: 7}, - %{id: 11, tasks: 5, score: 9, wr_joined_at: now, clan_id: 4}, - %{id: 12, tasks: 6, score: 9, wr_joined_at: pair_with_same_opponent, clan_id: 5}, - %{id: 13, tasks: 6, score: 9, wr_joined_at: pair_with_same_opponent, clan_id: 5}, - %{id: 14, tasks: 7, score: 9, wr_joined_at: pair_with_same_opponent, clan_id: 5}, - %{id: 15, tasks: 7, score: 9, wr_joined_at: pair_with_same_opponent, clan_id: 6}, - %{id: 16, tasks: 8, score: 9, wr_joined_at: pair_with_bot, clan_id: 6} - ]) - - state = %State{ - name: "wr", - state: "active", - min_time_sec: 3, - min_time_with_bot_sec: 20, - min_time_with_played_sec: 15, - played_pair_ids: MapSet.new([[2, 4], [8, 9], [14, 15]]), - players: players, - time_step_ms: 100_000, - use_clan?: true, - use_sequential_tasks?: true - } - - %{ - pairs: pairs, - players: players, - played_pair_ids: played_pair_ids, - matched_with_bot: matched_with_bot - } = Engine.call(state) - - assert [[1, 4], [2, 3], [6, 7], [14, 15]] == Enum.sort(pairs) - assert [16] == Enum.sort(matched_with_bot) - - assert [ - %{id: 5, tasks: 2, score: 6, wr_joined_at: joined, clan_id: 3}, - %{id: 8, tasks: 3, score: 9, wr_joined_at: joined, clan_id: 5}, - %{id: 9, tasks: 3, score: 9, wr_joined_at: joined, clan_id: 6}, - %{id: 10, tasks: 4, score: 9, wr_joined_at: joined, clan_id: 7}, - %{id: 11, tasks: 5, score: 9, wr_joined_at: now, clan_id: 4}, - %{id: 12, tasks: 6, score: 9, wr_joined_at: pair_with_same_opponent, clan_id: 5}, - %{id: 13, tasks: 6, score: 9, wr_joined_at: pair_with_same_opponent, clan_id: 5} - ] == Enum.sort_by(players, & &1.id) - - assert MapSet.new([[1, 4], [2, 3], [2, 4], [6, 7], [8, 9], [14, 15]]) == played_pair_ids - end - - test "10_000 players with clans" do - joined = :os.system_time(:seconds) - 5 - - players = - 1..10_000 - |> Enum.map(fn id -> - %{ - id: id, - tasks: Enum.random(1..30), - score: Enum.random(1..100), - wr_joined_at: joined, - clan_id: Enum.random(1..100) - } - end) - |> Enum.shuffle() - - played_pair_ids = 1..10_000 |> Enum.shuffle() |> Enum.chunk_every(2) |> MapSet.new() - - state = %State{ - name: "wr", - time_step_ms: 100_000, - use_clan?: true, - use_sequential_tasks?: true, - min_time_sec: 3, - players: players, - played_pair_ids: played_pair_ids - } - - Engine.call(state) - end -end diff --git a/services/app/apps/codebattle/test/codebattle/waiting_room/waiting_room_test.exs b/services/app/apps/codebattle/test/codebattle/waiting_room/waiting_room_test.exs deleted file mode 100644 index 09228b796..000000000 --- a/services/app/apps/codebattle/test/codebattle/waiting_room/waiting_room_test.exs +++ /dev/null @@ -1,32 +0,0 @@ -defmodule Codebattle.WaitingRoomTest do - use Codebattle.DataCase - - alias Codebattle.WaitingRoom - - test "matches players" do - players = [ - %{id: -1, clan_id: 1, score: 1, is_bot: true, task_ids: []}, - %{id: 1, clan_id: 1, score: 1, is_bot: false, task_ids: [1]}, - %{id: 2, clan_id: 1, score: 4, is_bot: false, task_ids: [1]}, - %{id: 3, clan_id: 2, score: 3, is_bot: false, task_ids: [1]}, - %{id: 4, clan_id: 2, score: 5, is_bot: false, task_ids: [1]}, - %{id: 5, clan_id: 3, score: 6, is_bot: false, task_ids: [1, 2]}, - %{id: 5, clan_id: 4, score: 8, is_bot: false, task_ids: [1, 2]} - ] - - Codebattle.PubSub.subscribe("waiting_room:wr") - - WaitingRoom.start_link(%{name: "wr", time_step_ms: 100_000, min_time_sec: 0}) - WaitingRoom.start("wr", MapSet.new()) - WaitingRoom.put_players("wr", players) - WaitingRoom.Server.get_state("wr") - WaitingRoom.Server.match_players("wr") - - assert_receive %Codebattle.PubSub.Message{ - payload: %{pairs: pairs} - } - - # assert pairs == [[5, 5], [1, 3], [2, 4]] - assert pairs == [[1, 3], [2, 4]] - end -end diff --git a/services/app/apps/codebattle/test/codebattle_web/channels/chat_channel_test.exs b/services/app/apps/codebattle/test/codebattle_web/channels/chat_channel_test.exs deleted file mode 100644 index 6d55e3ead..000000000 --- a/services/app/apps/codebattle/test/codebattle_web/channels/chat_channel_test.exs +++ /dev/null @@ -1,165 +0,0 @@ -defmodule CodebattleWeb.ChatChannelTest do - use CodebattleWeb.ChannelCase, async: true - - alias Codebattle.Chat - alias CodebattleWeb.ChatChannel - alias CodebattleWeb.UserSocket - alias Phoenix.Socket.Broadcast - - setup do - user1 = insert(:user, name: "alice") - user2 = insert(:user, name: "bob") - admin = insert(:admin) - - user_token1 = Phoenix.Token.sign(socket(UserSocket), "user_token", user1.id) - {:ok, socket1} = connect(UserSocket, %{"token" => user_token1}) - - user_token2 = Phoenix.Token.sign(socket(UserSocket), "user_token", user2.id) - {:ok, socket2} = connect(UserSocket, %{"token" => user_token2}) - - admin_token = Phoenix.Token.sign(socket(UserSocket), "user_token", admin.id) - {:ok, admin_socket} = connect(UserSocket, %{"token" => admin_token}) - - {:ok, %{user1: user1, user2: user2, socket1: socket1, socket2: socket2, admin_socket: admin_socket}} - end - - test "sends chat info when user join", %{user1: user1, socket1: socket1} do - chat_id = :rand.uniform(1000) - Chat.start_link({:game, chat_id}) - chat_topic = get_chat_topic(chat_id) - - {:ok, response, _socket1} = subscribe_and_join(socket1, ChatChannel, chat_topic) - - assert Jason.encode(response) == - Jason.encode(%{users: [Codebattle.User.get!(user1.id)], messages: []}) - end - - test "broadcasts chat:user_joined with state after user join", %{user2: user2, socket2: socket2} do - chat_id = :rand.uniform(1000) - Chat.start_link({:game, chat_id}) - chat_topic = get_chat_topic(chat_id) - {:ok, _response, _socket2} = subscribe_and_join(socket2, ChatChannel, chat_topic) - - assert_receive %Broadcast{ - topic: ^chat_topic, - event: "chat:user_joined", - payload: response - } - - assert Jason.encode(response) == Jason.encode(%{users: [Codebattle.User.get!(user2.id)]}) - end - - # SKIP flaky test for now, pls fix it - @tag :skip - test "messaging process", %{user1: user1, socket1: socket1, socket2: socket2} do - chat_id = :rand.uniform(1000) - Chat.start_link({:game, chat_id}) - chat_topic = get_chat_topic(chat_id) - {:ok, _response, socket1} = subscribe_and_join(socket1, ChatChannel, chat_topic) - - message = "oiblz" - - push(socket1, "chat:add_msg", %{text: message}) - - :timer.sleep(100) - - assert_receive %Phoenix.Socket.Message{ - topic: ^chat_topic, - event: "chat:new_msg", - payload: response - } - - id = user1.id - assert %{name: "alice", user_id: ^id, text: ^message, time: _} = response - - {:ok, %{users: users, messages: messages}, _socket2} = - subscribe_and_join(socket2, ChatChannel, chat_topic) - - assert length(users) == 2 - assert [%{name: "alice", user_id: ^id, text: ^message, time: _}] = messages - end - - test "removes user from list on leaving channel", %{socket1: socket1, socket2: socket2} do - chat_id = :rand.uniform(1000) - Chat.start_link({:game, chat_id}) - chat_topic = get_chat_topic(chat_id) - - {:ok, _response, _socket1} = subscribe_and_join(socket1, ChatChannel, chat_topic) - {:ok, response, socket2} = subscribe_and_join(socket2, ChatChannel, chat_topic) - - %{users: users} = response - - assert length(users) == 2 - - leave(socket2) - Process.unlink(socket2.channel_pid) - :timer.sleep(100) - - assert_receive %Broadcast{ - topic: ^chat_topic, - event: "chat:user_left", - payload: response - } - - %{users: users} = response - - assert length(users) == 1 - end - - test "bans user", %{ - socket1: socket1, - user1: user1, - socket2: socket2, - admin_socket: admin_socket - } do - assert Chat.get_messages(:lobby) == [] - - {:ok, _response, socket1} = subscribe_and_join(socket1, ChatChannel, "chat:lobby") - {:ok, _response, socket2} = subscribe_and_join(socket2, ChatChannel, "chat:lobby") - {:ok, _response, admin_socket} = subscribe_and_join(admin_socket, ChatChannel, "chat:lobby") - - push(socket1, "chat:add_msg", %{"text" => "oi"}) - :timer.sleep(10) - push(socket2, "chat:add_msg", %{"text" => "blz"}) - :timer.sleep(10) - push(socket1, "chat:add_msg", %{"text" => "invalid_content"}) - :timer.sleep(100) - - assert [ - %{id: 1, name: "alice", type: :text, text: "oi", time: _}, - %{id: 2, name: "bob", type: :text, text: "blz", time: _}, - %{id: 3, name: "alice", type: :text, text: "invalid_content", time: _} - ] = Chat.get_messages(:lobby) - - # common user cannot ban users - push(socket2, "chat:command", %{ - "type" => "ban", - "user_id" => user1.id, - "name" => user1.name - }) - - :timer.sleep(10) - - assert [ - %{name: "alice", type: :text, text: "oi", time: _}, - %{name: "bob", type: :text, text: "blz", time: _}, - %{name: "alice", type: :text, text: "invalid_content", time: _} - ] = Chat.get_messages(:lobby) - - # only admin can ban users - push(admin_socket, "chat:command", %{ - "type" => "ban", - "user_id" => user1.id, - "name" => user1.name - }) - - :timer.sleep(20) - - assert [ - %{name: "bob", type: :text, text: "blz", time: _}, - %{type: :info, text: "alice has been banned by admin", time: _} - ] = Chat.get_messages(:lobby) - end - - def get_chat_topic(id), do: "chat:g_#{id}" -end diff --git a/services/app/apps/codebattle/test/codebattle_web/channels/game_channel_test.exs b/services/app/apps/codebattle/test/codebattle_web/channels/game_channel_test.exs deleted file mode 100644 index 9b42e0a0c..000000000 --- a/services/app/apps/codebattle/test/codebattle_web/channels/game_channel_test.exs +++ /dev/null @@ -1,168 +0,0 @@ -defmodule CodebattleWeb.GameChannelTest do - use CodebattleWeb.ChannelCase - - alias Codebattle.Game - alias Codebattle.Game.Player - alias CodebattleWeb.GameChannel - alias CodebattleWeb.UserSocket - alias Phoenix.Socket.Broadcast - alias Phoenix.Socket.Reply - - setup do - user1 = insert(:user, rating: 1001) - user2 = insert(:user, rating: 1002) - insert(:task, level: "easy") - - user_token1 = Phoenix.Token.sign(socket(UserSocket), "user_token", user1.id) - {:ok, socket1} = connect(UserSocket, %{"token" => user_token1}) - - user_token2 = Phoenix.Token.sign(socket(UserSocket), "user_token", user2.id) - {:ok, socket2} = connect(UserSocket, %{"token" => user_token2}) - - {:ok, %{user1: user1, user2: user2, socket1: socket1, socket2: socket2}} - end - - describe "join/3" do - test "sends game info", %{user1: user1, socket1: socket1} do - {:ok, game} = - Game.Context.create_game(%{state: "waiting_opponent", players: [user1], level: "easy"}) - - {:ok, %{game: created}, _socket1} = - subscribe_and_join(socket1, GameChannel, game_topic(game)) - - assert created.task.level == "easy" - assert created.mode == "standard" - assert created.type == "duo" - end - end - - describe "handle_in(editor:data)" do - test "broadcasts editor:data", %{ - user1: user1, - user2: user2, - socket1: socket1, - socket2: socket2 - } do - {:ok, game} = - Game.Context.create_game(%{state: "playing", players: [user1, user2], level: "easy"}) - - game_topic = game_topic(game) - editor_text1 = "test1" - editor_text2 = "test2" - editor_lang1 = "js" - editor_lang2 = "ruby" - - {:ok, _response, socket1} = subscribe_and_join(socket1, GameChannel, game_topic) - {:ok, _response, socket2} = subscribe_and_join(socket2, GameChannel, game_topic) - Mix.Shell.Process.flush() - - push(socket1, "editor:data", %{editor_text: editor_text1, lang_slug: "js"}) - push(socket2, "editor:data", %{editor_text: editor_text2, lang_slug: "js"}) - - push(socket1, "editor:data", %{editor_text: editor_text1, lang_slug: editor_lang1}) - push(socket2, "editor:data", %{editor_text: editor_text2, lang_slug: editor_lang2}) - - payload1 = %{user_id: user1.id, editor_text: editor_text1, lang_slug: "js"} - payload2 = %{user_id: user2.id, editor_text: editor_text2, lang_slug: "js"} - payload3 = %{user_id: user1.id, editor_text: editor_text1, lang_slug: editor_lang1} - payload4 = %{user_id: user2.id, editor_text: editor_text2, lang_slug: editor_lang2} - - assert_receive %Broadcast{ - topic: ^game_topic, - event: "editor:data", - payload: ^payload1 - } - - assert_receive %Broadcast{ - topic: ^game_topic, - event: "editor:data", - payload: ^payload2 - } - - assert_receive %Broadcast{ - topic: ^game_topic, - event: "editor:data", - payload: ^payload3 - } - - assert_receive %Broadcast{ - topic: ^game_topic, - event: "editor:data", - payload: ^payload4 - } - end - end - - test "on give up opponents win when state playing", %{ - user1: user1, - user2: user2, - socket1: socket1, - socket2: socket2 - } do - {:ok, game} = - Game.Context.create_game(%{state: "playing", players: [user1, user2], level: "easy"}) - - game_topic = game_topic(game) - - {:ok, _response, socket1} = subscribe_and_join(socket1, GameChannel, game_topic) - {:ok, _response, _socket2} = subscribe_and_join(socket2, GameChannel, game_topic) - Mix.Shell.Process.flush() - - push(socket1, "give_up") - - :timer.sleep(100) - game = Game.Context.get_game!(game.id) - - assert game.state == "game_over" - assert Game.Helpers.gave_up?(game, user1.id) == true - assert Game.Helpers.winner?(game, user2.id) == true - - assert_receive %Broadcast{ - topic: ^game_topic, - event: "user:give_up", - payload: payload - } - - assert payload.players == game.players - end - - describe "handle_in" do - test "do not erros if there is no game in registry", %{user1: user1, socket1: socket1} do - {:ok, game} = Game.Context.create_game(%{players: [user1], level: "easy"}) - :ok = Game.Context.terminate_game(game) - game_topic = game_topic(game) - {:ok, _response, socket1} = subscribe_and_join(socket1, GameChannel, game_topic) - Mix.Shell.Process.flush() - - push(socket1, "editor:data", %{editor_text: "oi", lang_slug: "js"}) - - assert_receive %Reply{ - topic: ^game_topic, - payload: %{reason: :game_is_dead} - } - end - - test "show score", %{user1: user1, user2: user2, socket1: socket1} do - players = [Player.build(user1), Player.build(user2)] - game1 = insert(:game, state: "game_over", players: players) - insert(:user_game, user: user1, creator: false, game: game1, result: "won") - insert(:user_game, user: user2, creator: true, game: game1, result: "gave_up") - - {:ok, game} = Game.Context.create_game(%{players: [user1, user2], level: "easy"}) - :ok = Game.Context.terminate_game(game) - game_topic = game_topic(game) - {:ok, _response, socket1} = subscribe_and_join(socket1, GameChannel, game_topic) - Mix.Shell.Process.flush() - - user1_id = user1.id - push(socket1, "game:score", %{}) - - assert_receive %Reply{ - topic: ^game_topic, - payload: %{score: %{game_results: [%{}], player_results: %{}, winner_id: ^user1_id}} - } - end - end - - defp game_topic(game), do: "game:" <> to_string(game.id) -end diff --git a/services/app/apps/codebattle/test/codebattle_web/controllers/api/v1/activity_controller_test.exs b/services/app/apps/codebattle/test/codebattle_web/controllers/api/v1/activity_controller_test.exs deleted file mode 100644 index 669e9fe2e..000000000 --- a/services/app/apps/codebattle/test/codebattle_web/controllers/api/v1/activity_controller_test.exs +++ /dev/null @@ -1,24 +0,0 @@ -defmodule CodebattleWeb.Api.V1.ActivityControllerTest do - use CodebattleWeb.ConnCase, async: true - - test "show user: signed in", %{conn: conn} do - user = insert(:user) - insert_list(3, :user_game, user: user, inserted_at: ~N[2000-01-02 22:00:07]) - insert_list(2, :user_game, user: user, inserted_at: ~N[2000-01-01 23:00:07]) - - conn = - conn - |> put_session(:user_id, user.id) - |> get(Routes.api_v1_activity_path(conn, :show, user.id)) - - asserted_data = [ - %{"count" => 3, "date" => "2000-01-02"}, - %{"count" => 2, "date" => "2000-01-01"} - ] - - assert conn - |> json_response(200) - |> Map.get("activities") - |> Enum.sort(&(Map.get(&1, "count") >= Map.get(&2, "count"))) == asserted_data - end -end diff --git a/services/app/apps/codebattle/test/codebattle_web/controllers/api/v1/game_controller_test.exs b/services/app/apps/codebattle/test/codebattle_web/controllers/api/v1/game_controller_test.exs deleted file mode 100644 index 65ea2c843..000000000 --- a/services/app/apps/codebattle/test/codebattle_web/controllers/api/v1/game_controller_test.exs +++ /dev/null @@ -1,83 +0,0 @@ -defmodule CodebattleWeb.Api.V1.GameControllerTest do - use CodebattleWeb.ConnCase, async: true - - alias Codebattle.Game.Player - - describe ".completed_games" do - test "shows user stats", %{conn: conn} do - user1 = - insert(:user, %{ - name: "first", - email: "test1@test.test", - github_id: 1, - rating: 2400 - }) - - user2 = - insert(:user, %{name: "second", email: "test2@test.test", github_id: 2, rating: 2310}) - - players = [Player.build(user1), Player.build(user2)] - - game1 = - insert(:game, state: "game_over", finishes_at: ~N[2001-01-01 23:00:07], players: players) - - game2 = - insert(:game, state: "game_over", finishes_at: ~N[2002-02-02 23:00:07], players: players) - - insert(:game, state: "timeout", players: players) - - insert(:user_game, user: user1, creator: false, game: game1, result: "won") - insert(:user_game, user: user2, creator: false, game: game1, result: "lost") - insert(:user_game, user: user1, creator: false, game: game2, result: "lost") - insert(:user_game, user: user2, creator: false, game: game2, result: "won") - - %{id: game1_id} = game1 - %{id: game2_id} = game2 - - resp_body = - conn - |> get(Routes.api_v1_game_path(conn, :completed)) - |> json_response(200) - - %{"games" => [%{"id" => ^game2_id}, %{"id" => ^game1_id}], "page_info" => page_info} = - resp_body - - assert page_info == %{ - "page_number" => 1, - "page_size" => 20, - "total_entries" => 2, - "total_pages" => 1 - } - - resp_body = - conn - |> get(Routes.api_v1_game_path(conn, :completed, %{user_id: user1.id})) - |> json_response(200) - - %{"games" => games, "page_info" => page_info} = resp_body - assert Enum.count(games) == 2 - - assert page_info == %{ - "page_number" => 1, - "page_size" => 20, - "total_entries" => 2, - "total_pages" => 1 - } - - resp_body = - conn - |> get(Routes.api_v1_game_path(conn, :completed, %{user_id: user1.id, page: 2, page_size: 1})) - |> json_response(200) - - %{"games" => games, "page_info" => page_info} = resp_body - assert Enum.count(games) == 1 - - assert page_info == %{ - "page_number" => 2, - "page_size" => 1, - "total_entries" => 2, - "total_pages" => 3 - } - end - end -end diff --git a/services/app/apps/codebattle/test/codebattle_web/controllers/api/v1/settings_controller_test.exs b/services/app/apps/codebattle/test/codebattle_web/controllers/api/v1/settings_controller_test.exs deleted file mode 100644 index ccf26c4de..000000000 --- a/services/app/apps/codebattle/test/codebattle_web/controllers/api/v1/settings_controller_test.exs +++ /dev/null @@ -1,95 +0,0 @@ -defmodule CodebattleWeb.Api.V1.SettingsControllerTest do - use CodebattleWeb.ConnCase, async: true - - alias Codebattle.Repo - - describe "#show" do - test "shows current user settings", %{conn: conn} do - user = - insert(:user, %{ - name: "first", - email: "test1@test.test", - github_id: 1, - github_name: "g_name", - clan: "abc", - rating: 2400, - lang: "dart" - }) - - conn = - conn - |> put_session(:user_id, user.id) - |> get(Routes.api_v1_settings_path(conn, :show)) - - assert json_response(conn, 200) == %{ - "name" => "first", - "lang" => "dart", - "clan" => "abc", - "sound_settings" => %{"level" => 7, "type" => "dendy"}, - "github_id" => 1, - "github_name" => "g_name" - } - end - end - - describe "#update" do - test "updates current user settings", %{conn: conn} do - clan = insert(:clan, name: "Bca") - - new_settings = %{ - "name" => "evgen", - "clan" => " Bca ", - "sound_settings" => %{"level" => 3, "type" => "cs"}, - "lang" => "ruby" - } - - user = insert(:user) - - conn = - conn - |> put_session(:user_id, user.id) - |> patch(Routes.api_v1_settings_path(conn, :update, new_settings)) - - assert json_response(conn, 200) == Map.put(new_settings, "clan", "Bca") - - updated = Repo.get!(Codebattle.User, user.id) - - assert updated.sound_settings.level == 3 - assert updated.sound_settings.type == "cs" - assert updated.clan == "Bca" - assert updated.clan_id == clan.id - assert updated.name == "evgen" - assert updated.lang == "ruby" - end - - test "update with empty name doesn't work", %{conn: conn} do - new_settings = %{"name" => ""} - - user = insert(:user) - - conn = - conn - |> put_session(:user_id, user.id) - |> patch(Routes.api_v1_settings_path(conn, :update, new_settings)) - - assert json_response(conn, 422) == %{"errors" => %{"name" => ["can't be blank"]}} - - updated = Repo.get!(Codebattle.User, user.id) - - assert updated.name == user.name - end - - test "returns validation errors", %{conn: conn} do - new_settings = %{"name" => "evgen"} - user = insert(:user) - insert(:user, %{name: "evgen"}) - - conn = - conn - |> put_session(:user_id, user.id) - |> patch(Routes.api_v1_settings_path(conn, :show, new_settings)) - - assert json_response(conn, 422) == %{"errors" => %{"name" => ["has already been taken"]}} - end - end -end diff --git a/services/app/apps/codebattle/test/codebattle_web/controllers/api/v1/task_controller_test.exs b/services/app/apps/codebattle/test/codebattle_web/controllers/api/v1/task_controller_test.exs deleted file mode 100644 index 8366a682c..000000000 --- a/services/app/apps/codebattle/test/codebattle_web/controllers/api/v1/task_controller_test.exs +++ /dev/null @@ -1,132 +0,0 @@ -defmodule CodebattleWeb.Api.V1.TaskControllerTest do - use CodebattleWeb.ConnCase, async: true - - describe ".index" do - test "lists visible tasks", %{conn: conn} do - u1 = insert(:user) - u2 = insert(:user) - - t1 = - insert(:task, - creator_id: u1.id, - state: "active", - visibility: "hidden", - name: "1", - tags: ["a"] - ) - - t2 = insert(:task, creator_id: u2.id, state: "active", visibility: "public", name: "2") - t3 = insert(:task, creator_id: nil, state: "active", visibility: "public", name: "3") - insert(:task, creator_id: u2.id, state: "active", visibility: "hidden") - insert(:task, creator_id: u2.id, state: "disabled", visibility: "public") - - tasks = - conn - |> put_session(:user_id, u1.id) - |> get(Routes.api_v1_task_path(conn, :index)) - |> json_response(200) - |> Map.get("tasks") - |> Enum.sort_by(&Map.get(&1, "name")) - - assert [ - %{ - "creator_id" => u1.id, - "id" => t1.id, - "level" => "easy", - "name" => "1", - "origin" => "user", - "tags" => ["a"] - }, - %{ - "creator_id" => u2.id, - "id" => t2.id, - "level" => "easy", - "name" => "2", - "origin" => "user", - "tags" => [] - }, - %{ - "creator_id" => nil, - "id" => t3.id, - "level" => "easy", - "name" => "3", - "origin" => "user", - "tags" => [] - } - ] == - tasks - end - end - - describe ".show" do - test "shows visible task", %{conn: conn} do - task = insert(:task, visibility: "public", level: "easy") - - conn = get(conn, Routes.api_v1_task_path(conn, :show, task.id)) - - resp_body = json_response(conn, 200) - - id = task.id - name = task.name - level = task.level - tags = task.tags - - assert %{ - "task" => %{ - "id" => ^id, - "name" => ^name, - "creator_id" => nil, - "origin" => "user", - "level" => ^level, - "tags" => ^tags - } - } = resp_body - end - - test "shows hidden task only for creator", %{conn: conn} do - user = insert(:user) - creator_id = user.id - hidden_task = insert(:task, name: "1", visibility: "hidden", creator_id: creator_id) - - conn - |> get(Routes.api_v1_task_path(conn, :show, hidden_task.id)) - |> json_response(404) - - response = - conn - |> put_session(:user_id, user.id) - |> get(Routes.api_v1_task_path(conn, :show, hidden_task.id)) - |> json_response(200) - - assert %{ - "task" => %{ - "creator_id" => ^creator_id, - "level" => "easy", - "name" => "1", - "origin" => "user", - "tags" => [] - } - } = response - end - end - - describe ".unique" do - test "returns false when task exists", %{conn: conn} do - task = insert(:task, visibility: "public", level: "easy", name: "task_name") - - conn = get(conn, Routes.api_v1_task_path(conn, :unique, task.name)) - - resp_body = json_response(conn, 200) - - assert resp_body == %{"unique" => false} - end - - test "returns true when task not exists", %{conn: conn} do - conn = get(conn, Routes.api_v1_task_path(conn, :unique, "my_unqiue_task")) - - resp_body = json_response(conn, 200) - - assert resp_body == %{"unique" => true} - end - end -end diff --git a/services/app/apps/codebattle/test/codebattle_web/controllers/api/v1/user_controller_test.exs b/services/app/apps/codebattle/test/codebattle_web/controllers/api/v1/user_controller_test.exs deleted file mode 100644 index 20f9e67ae..000000000 --- a/services/app/apps/codebattle/test/codebattle_web/controllers/api/v1/user_controller_test.exs +++ /dev/null @@ -1,179 +0,0 @@ -defmodule CodebattleWeb.Api.V1.UserControllerTest do - use CodebattleWeb.ConnCase, async: true - - describe "#index" do - test "shows rating list", %{conn: conn} do - user1 = - insert(:user, %{name: "first", email: "test1@test.test", github_id: 1, rating: 2400}) - - insert(:user_game, user: user1, inserted_at: ~N[2000-01-01 23:00:07]) - insert(:user, %{name: "second", email: "test2@test.test", github_id: 2, rating: 2310}) - insert(:user, %{name: "third", email: "test3@test.test", github_id: 3, rating: 2210}) - insert(:user, %{name: "forth", email: "test4@test.test", github_id: 4, rating: 2210}) - - conn = get(conn, Routes.api_v1_user_path(conn, :index)) - - resp_body = json_response(conn, 200) - - assert resp_body["page_info"] == %{ - "page_number" => 1, - "page_size" => 50, - "total_entries" => 4, - "total_pages" => 1 - } - - assert resp_body["date_from"] == nil - assert Enum.count(resp_body["users"]) == 4 - end - - test "shows rating list with date_from filter", %{conn: conn} do - date_from = "2020-10-10" - starts_at = ~N[2020-10-10 10:00:00] - - user1 = - insert(:user, %{name: "first", email: "test1@test.test", github_id: 1, rating: 2400}) - - game = insert(:game, starts_at: starts_at) - insert(:user_game, user: user1, game: game) - insert(:user, %{name: "second", email: "test2@test.test", github_id: 2, rating: 2310}) - insert(:user, %{name: "third", email: "test3@test.test", github_id: 3, rating: 2210}) - insert(:user, %{name: "forth", email: "test4@test.test", github_id: 4, rating: 2210}) - - conn = get(conn, Routes.api_v1_user_path(conn, :index), %{"date_from" => date_from}) - - resp_body = json_response(conn, 200) - - assert resp_body["page_info"] == %{ - "page_number" => 1, - "page_size" => 50, - "total_entries" => 1, - "total_pages" => 1 - } - - assert resp_body["date_from"] == date_from - assert Enum.count(resp_body["users"]) == 1 - end - - test "shows rating list with with search by name_ilike", %{conn: conn} do - user1 = insert(:user, %{name: "aaa", email: "test1@test.test", github_id: 1, rating: 2400}) - insert(:user_game, user: user1, inserted_at: ~N[2000-01-01 23:00:07]) - insert(:user, %{name: "bbb", email: "test2@test.test", github_id: 2, rating: 2310}) - insert(:user, %{name: "ab", email: "test3@test.test", github_id: 3, rating: 2210}) - - conn = get(conn, Routes.api_v1_user_path(conn, :index, q: %{name_ilike: "a"})) - - resp_body = json_response(conn, 200) - - assert resp_body["page_info"] == %{ - "page_number" => 1, - "page_size" => 50, - "total_entries" => 2, - "total_pages" => 1 - } - - assert resp_body["date_from"] == nil - assert Enum.count(resp_body["users"]) == 2 - end - - test "shows rating list sorted by inserted at", %{conn: conn} do - insert( - :user, - %{ - name: "aaa", - email: "test1@test.test", - github_id: 1, - rating: 2400, - inserted_at: ~N[2000-01-01 23:00:07] - } - ) - - conn = get(conn, Routes.api_v1_user_path(conn, :index, s: "inserted_at+asc")) - - resp_body = json_response(conn, 200) - - assert resp_body["page_info"] == %{ - "page_number" => 1, - "page_size" => 50, - "total_entries" => 1, - "total_pages" => 1 - } - - assert resp_body["date_from"] == nil - - [first_user | _] = resp_body["users"] - - assert Map.take(first_user, ~w(name email github_id)) == %{ - "name" => "aaa", - "github_id" => 1 - } - end - end - - describe "stats" do - test "shows user stats", %{conn: conn} do - user1 = insert(:user, %{name: "1", github_id: 1, rating: 2400}) - user2 = insert(:user, %{name: "2", github_id: 2, rating: 2310}) - game1 = insert(:game, state: "game_over") - game2 = insert(:game, state: "game_over") - game3 = insert(:game, state: "game_over") - %{id: game4_id} = insert(:game, state: "playing", player_ids: [user1.id]) - insert(:user_game, user: user1, creator: false, game: game1, result: "won", lang: "js") - insert(:user_game, user: user2, creator: false, game: game1, result: "lost", lang: "js") - insert(:user_game, user: user1, creator: false, game: game2, result: "lost", lang: "ruby") - insert(:user_game, user: user2, creator: false, game: game2, result: "won", lang: "ruby") - insert(:user_game, user: user1, creator: false, game: game3, result: "lost", lang: "golang") - insert(:user_game, user: user2, creator: false, game: game3, result: "won", lang: "golang") - - resp_body = - conn - |> get(Routes.api_v1_user_path(conn, :stats, user1.id)) - |> json_response(200) - - assert [ - %{"count" => 1, "lang" => "golang", "result" => "lost"}, - %{"count" => 1, "lang" => "js", "result" => "won"}, - %{"count" => 1, "lang" => "ruby", "result" => "lost"} - ] = Enum.sort_by(resp_body["stats"]["all"], & &1["lang"]) - - assert %{ - "active_game_id" => ^game4_id, - "stats" => %{"games" => %{"gave_up" => 0, "lost" => 2, "won" => 1}}, - "user" => _user - } = resp_body - - resp_body = - conn - |> get(Routes.api_v1_user_path(conn, :stats, user2.id)) - |> json_response(200) - - assert %{ - "active_game_id" => nil, - "stats" => %{"games" => %{"gave_up" => 0, "lost" => 1, "won" => 2}}, - "user" => _user - } = resp_body - end - end - - describe "#current" do - test "shows current_user when logged in", %{conn: conn} do - user = insert(:user) - - conn = - conn - |> put_session(:user_id, user.id) - |> get(Routes.api_v1_user_path(conn, :current)) - - resp_body = json_response(conn, 200) - - assert resp_body == %{"id" => user.id} - end - - test "shows current_user when not logged in", %{conn: conn} do - conn = get(conn, Routes.api_v1_user_path(conn, :current)) - - resp_body = json_response(conn, 200) - - assert resp_body == %{"id" => 0} - end - end -end diff --git a/services/app/apps/codebattle/test/codebattle_web/controllers/auth_bind_controller_test.exs b/services/app/apps/codebattle/test/codebattle_web/controllers/auth_bind_controller_test.exs deleted file mode 100644 index d91288b6b..000000000 --- a/services/app/apps/codebattle/test/codebattle_web/controllers/auth_bind_controller_test.exs +++ /dev/null @@ -1,106 +0,0 @@ -defmodule CodebattleWeb.AuthBindControllerTest do - use CodebattleWeb.ConnCase, async: true - - alias Codebattle.Repo - alias Codebattle.User - - describe "request" do - test "GET /auth/github/bind", %{conn: conn} do - conn = get(conn, "/auth/github/bind") - assert conn.state == :sent - assert conn.status == 302 - assert redirected_to(conn) =~ "https://github.com/login/oauth/authorize?" - end - - test "GET /auth/discord/bind", %{conn: conn} do - conn = get(conn, "/auth/discord/bind") - assert conn.state == :sent - assert conn.status == 302 - assert redirected_to(conn) =~ "https://discord.com/oauth2/authorize?" - end - - test "GET /auth/lol/bind", %{conn: conn} do - conn = get(conn, "/auth/lol/bind") - assert conn.state == :sent - assert conn.status == 302 - assert redirected_to(conn) == "/" - end - end - - describe "callback" do - test "GET /auth/github/callback/bind", %{conn: conn} do - stub_github_oauth_requests() - - user = insert(:user, github_id: 1, discord_id: 1, name: "lol-kek") - - conn = - conn - |> put_session(:user_id, user.id) - |> get("/auth/github/callback/bind", %{"code" => "asfd"}) - - user = Repo.reload(user) - - assert %User{ - discord_id: 1, - name: "lol-kek", - email: "test@gmail.com", - github_name: "test_user", - github_id: 19, - avatar_url: "https://avatars3.githubusercontent.com/u/10835816" - } = user - - assert conn.state == :sent - assert redirected_to(conn) == "/settings" - end - - test "GET /auth/discord/callback/bind", %{conn: conn} do - stub_discord_oauth_requests() - user = insert(:user, github_id: 1, discord_id: 1, name: "lol-kek") - - conn = - conn - |> put_session(:user_id, user.id) - |> get("/auth/discord/callback/bind", %{"code" => "asfd"}) - - user = Repo.reload(user) - - assert %User{ - avatar_url: "https://cdn.discordapp.com/avatars/1234567/12345.jpg", - discord_avatar: "12345", - discord_id: 1_234_567, - discord_name: "test_name", - email: "lol@kek.com", - github_id: 1, - name: "lol-kek" - } = user - - assert conn.state == :sent - assert redirected_to(conn) == "/settings" - end - end - - describe "DELETE /auth/:provider/" do - test "unbinds discord", %{conn: conn} do - user = insert(:user) - conn = put_session(conn, :user_id, user.id) - delete(conn, "/auth/discord") - - user = Repo.reload!(user) - - assert user.discord_id == nil - assert user.discord_name == nil - assert user.discord_avatar == nil - end - - test "unbinds github", %{conn: conn} do - user = insert(:user) - conn = put_session(conn, :user_id, user.id) - delete(conn, "/auth/github") - - user = Repo.reload!(user) - - assert user.github_id == nil - assert user.github_name == nil - end - end -end diff --git a/services/app/apps/codebattle/test/codebattle_web/controllers/auth_controller_test.exs b/services/app/apps/codebattle/test/codebattle_web/controllers/auth_controller_test.exs deleted file mode 100644 index f33022758..000000000 --- a/services/app/apps/codebattle/test/codebattle_web/controllers/auth_controller_test.exs +++ /dev/null @@ -1,126 +0,0 @@ -defmodule CodebattleWeb.AuthControllerTest do - use CodebattleWeb.ConnCase, async: true - - alias Codebattle.Repo - alias Codebattle.User - - describe "request" do - test "GET /auth/github", %{conn: conn} do - conn = get(conn, "/auth/github") - assert conn.state == :sent - assert conn.status == 302 - assert redirected_to(conn) =~ "https://github.com/login/oauth/authorize?" - end - - test "GET /auth/discord", %{conn: conn} do - conn = get(conn, "/auth/discord") - assert conn.state == :sent - assert conn.status == 302 - assert redirected_to(conn) =~ "https://discord.com/oauth2/authorize?" - end - - test "GET /auth/lol", %{conn: conn} do - conn = get(conn, "/auth/lol") - assert conn.state == :sent - assert conn.status == 302 - assert redirected_to(conn) == "/" - end - end - - describe "callback" do - test "/auth/github/callback creates user", %{conn: conn} do - stub_github_oauth_requests() - - conn = get(conn, "/auth/github/callback", %{"code" => "asfd", "next" => "/next_path"}) - user = Repo.get_by(User, name: "test_user") - - assert %User{ - achievements: [], - avatar_url: "https://avatars3.githubusercontent.com/u/10835816", - discord_avatar: nil, - discord_id: nil, - discord_name: nil, - email: "test@gmail.com", - github_id: 19, - github_name: "test_user", - is_bot: false, - is_guest: false, - name: "test_user", - rank: 5432, - rating: 1200 - } = user - - assert conn.state == :sent - assert redirected_to(conn) == "/next_path" - end - - test "/auth/github/callback creates uniq name for user", %{conn: conn} do - stub_github_oauth_requests() - - insert(:user, name: "test_user", github_id: 1111) - conn = get(conn, "/auth/github/callback", %{"code" => "asfd", "next" => "/next_path"}) - user = Repo.get_by(User, github_id: 19) - - assert %User{github_id: 19, github_name: "test_user"} = user - "test_user_" <> code = user.name - assert String.length(code) == 4 - - assert conn.state == :sent - assert redirected_to(conn) == "/next_path" - end - - test "/auth/discord/callback creates user", %{conn: conn} do - stub_discord_oauth_requests() - - conn = get(conn, "/auth/discord/callback", %{"code" => "asfd", "next" => "/next_path"}) - user = Repo.get_by(User, name: "test_name") - - assert %User{ - achievements: [], - avatar_url: "https://cdn.discordapp.com/avatars/1234567/12345.jpg", - discord_avatar: "12345", - discord_id: 1_234_567, - discord_name: "test_name", - editor_mode: nil, - editor_theme: nil, - email: "lol@kek.com", - firebase_uid: nil, - games_played: nil, - github_id: nil, - github_name: nil, - is_bot: false, - is_guest: false, - lang: "js", - name: "test_name", - rank: 5432, - rating: 1200 - } = user - - assert conn.state == :sent - assert redirected_to(conn) == "/next_path" - end - - test "/auth/discord/callback creates uniq name for user", %{conn: conn} do - insert(:user, name: "test_name", discord_id: 123) - - stub_discord_oauth_requests() - - conn = get(conn, "/auth/discord/callback", %{"code" => "asfd", "next" => "/next_path"}) - user = Repo.get_by(User, discord_id: 1_234_567) - - assert %User{discord_id: 1_234_567, discord_name: "test_name"} = user - "test_name_" <> code = user.name - assert String.length(code) == 4 - - assert conn.state == :sent - assert redirected_to(conn) == "/next_path" - end - - test "/auth/github/lol", %{conn: conn} do - conn = get(conn, "/auth/lol/callback") - - assert conn.state == :sent - assert redirected_to(conn) == "/" - end - end -end diff --git a/services/app/apps/codebattle/test/codebattle_web/controllers/ext_api/task_pack_controller_test.exs b/services/app/apps/codebattle/test/codebattle_web/controllers/ext_api/task_pack_controller_test.exs deleted file mode 100644 index 70cd08222..000000000 --- a/services/app/apps/codebattle/test/codebattle_web/controllers/ext_api/task_pack_controller_test.exs +++ /dev/null @@ -1,70 +0,0 @@ -defmodule CodebattleWeb.ExtApi.TaskPackControllerTest do - use CodebattleWeb.ConnCase, async: false - - alias Codebattle.Repo - alias Codebattle.TaskPack - - describe "create/2" do - test "checks auth", %{conn: conn} do - assert conn - |> post(Routes.ext_api_task_pack_path(conn, :create, %{name: "qualification-2025"})) - |> json_response(401) - end - - test "creates task_pack with valid params", %{conn: conn} do - task1 = insert(:task, name: "sum of two") - task2 = insert(:task, name: "tasks") - - conn - |> put_req_header("x-auth-key", "x-key") - |> post( - Routes.ext_api_task_pack_path(conn, :create, %{ - name: "qualification-2025", - state: "active", - visibility: "hidden", - task_names: [ - "sum of two", - "tasks" - ] - }) - ) - |> response(201) - - task_pack = Repo.get_by(TaskPack, name: "qualification-2025") - assert task_pack - assert task_pack.state == "active" - assert task_pack.visibility == "hidden" - assert task_pack.task_ids == [task1.id, task2.id] - end - - test "updates existing task_pack", %{conn: conn} do - task1 = insert(:task, name: "sum of two") - task2 = insert(:task, name: "tasks") - task3 = insert(:task, name: "missing numbers") - - task_pack = insert(:task_pack, name: "qualification-2025", task_ids: [task1.id]) - - conn - |> put_req_header("x-auth-key", "x-key") - |> post( - Routes.ext_api_task_pack_path(conn, :create, %{ - name: "qualification-2025", - state: "active", - visibility: "hidden", - task_names: [ - "sum of two", - "tasks", - "missing numbers" - ] - }) - ) - |> response(201) - - updated_task_pack = Repo.get(TaskPack, task_pack.id) - assert updated_task_pack - assert updated_task_pack.state == "active" - assert updated_task_pack.visibility == "hidden" - assert updated_task_pack.task_ids == [task1.id, task2.id, task3.id] - end - end -end diff --git a/services/app/apps/codebattle/test/codebattle_web/controllers/ext_api/user_controller_test.exs b/services/app/apps/codebattle/test/codebattle_web/controllers/ext_api/user_controller_test.exs deleted file mode 100644 index b67bd02f5..000000000 --- a/services/app/apps/codebattle/test/codebattle_web/controllers/ext_api/user_controller_test.exs +++ /dev/null @@ -1,228 +0,0 @@ -defmodule CodebattleWeb.ExtApi.UserControllerTest do - use CodebattleWeb.ConnCase, async: false - - alias Codebattle.Clan - alias Codebattle.Repo - alias Codebattle.User - alias Codebattle.UserEvent - - describe "create/2" do - test "checks auth", %{conn: conn} do - assert conn - |> post(Routes.ext_api_user_path(conn, :create, %{name: "hacker"})) - |> json_response(401) - end - - test "creates user with clan and auth token", %{conn: conn} do - conn - |> put_req_header("x-auth-key", "x-key") - |> post( - Routes.ext_api_user_path(conn, :create, %{ - name: "lol", - clan: "S2xhbg==", - UID: "asdf", - category: "cat" - }) - ) - |> json_response(200) - - user = Repo.get_by(User, name: "lol") - clan = Repo.get_by(Clan, name: "Klan") - assert "cat" == user.category - assert "asdf" == user.external_oauth_id - assert 1 == clan.creator_id - assert user.clan_id == clan.id - assert user.sound_settings == %User.SoundSettings{level: 0, type: "silent"} - assert user.subscription_type == :premium - end - - test "creates user with empty params", %{conn: conn} do - conn - |> put_req_header("x-auth-key", "x-key") - |> post(Routes.ext_api_user_path(conn, :create, %{UID: "asdf"})) - |> json_response(200) - - user = Repo.get_by(User, external_oauth_id: "asdf") - - assert user.name - assert user.external_oauth_id - assert user.clan - end - - test "creates user with existing name", %{conn: conn} do - conn - |> put_req_header("x-auth-key", "x-key") - |> post(Routes.ext_api_user_path(conn, :create, %{name: "lol", clan: "kek", UID: "uid1"})) - |> json_response(200) - - conn - |> put_req_header("x-auth-key", "x-key") - |> post(Routes.ext_api_user_path(conn, :create, %{name: "lol", clan: "kek", UID: "uid2"})) - |> json_response(200) - - %{id: clan_id} = Repo.get_by(Clan, name: "kek") - users = User |> Repo.all() |> Enum.filter(&(&1.clan == "kek")) - - assert [ - %{name: "lol", clan: "kek", external_oauth_id: "uid1", clan_id: ^clan_id}, - %{name: name, clan: "kek", external_oauth_id: "uid2", clan_id: ^clan_id} - ] = Enum.sort_by(users, & &1.external_oauth_id) - - assert String.starts_with?(name, "lol") - end - - test "creates user with existing clan by name", %{conn: conn} do - clan = insert(:clan, name: "Kek", long_name: "lOl_kEk") - - conn - |> put_req_header("x-auth-key", "x-key") - |> post(Routes.ext_api_user_path(conn, :create, %{name: "oiblz", clan: "Kek ", UID: "asdf"})) - |> json_response(200) - - users = User |> Repo.all() |> Enum.filter(&(&1.clan == "Kek")) - assert [clan.id] == Enum.map(users, & &1.clan_id) - assert ["Kek"] == Enum.map(users, & &1.clan) - end - - test "creates user with existing clan by long_name", %{conn: conn} do - clan = insert(:clan, name: "kEk", long_name: "LoL_KeK") - - conn - |> put_req_header("x-auth-key", "x-key") - |> post( - Routes.ext_api_user_path(conn, :create, %{ - name: "oiblz", - clan: "LoL_KeK", - UID: "asdf" - }) - ) - |> json_response(200) - - users = User |> Repo.all() |> Enum.filter(&(&1.clan == "kEk")) - assert [clan.id] == Enum.map(users, & &1.clan_id) - assert ["kEk"] == Enum.map(users, & &1.clan) - end - - test "updates user by UID", %{conn: conn} do - clan = insert(:clan, name: "Kek", long_name: "lOl_kEk") - - user = - insert(:user, - name: "whatever", - clan_id: nil, - subscription_type: :free, - external_oauth_id: "asdf" - ) - - conn - |> put_req_header("x-auth-key", "x-key") - |> post( - Routes.ext_api_user_path(conn, :create, %{ - category: "lol", - name: "oiblz", - clan: "Kek ", - UID: "asdf" - }) - ) - |> json_response(200) - - user = Repo.get(User, user.id) - - assert %{ - id: user.id, - name: "oiblz", - clan_id: clan.id, - category: "lol", - external_oauth_id: "asdf", - subscription_type: :premium - } == - Map.take(user, [ - :id, - :name, - :clan_id, - :external_oauth_id, - :subscription_type, - :category - ]) - end - - test "updates user with duplicated name by UID", %{conn: conn} do - clan = insert(:clan, name: "Kek", long_name: "lOl_kEk") - insert(:user, name: "oiblz") - - user = - insert(:user, - name: "whatever", - clan_id: nil, - subscription_type: :free, - external_oauth_id: "asdf" - ) - - conn - |> put_req_header("x-auth-key", "x-key") - |> post( - Routes.ext_api_user_path(conn, :create, %{ - category: "lol", - name: "oiblz", - clan: "Kek ", - UID: "asdf" - }) - ) - |> json_response(200) - - user = Repo.get(User, user.id) - assert String.starts_with?(user.name, "oiblz") - - assert %{ - id: user.id, - clan_id: clan.id, - external_oauth_id: "asdf", - category: "lol", - subscription_type: :premium - } == - Map.take(user, [:id, :clan_id, :external_oauth_id, :subscription_type, :category]) - end - - test "finds or creates user with user_event", %{conn: conn} do - Application.put_env(:codebattle, :main_event_slug, "e") - - insert(:event, slug: "e") - - conn - |> put_req_header("x-auth-key", "x-key") - |> post( - Routes.ext_api_user_path(conn, :create, %{ - name: "lol", - clan: "S2xhbg==", - UID: "asdf", - category: "cat" - }) - ) - |> json_response(200) - - user = Repo.get_by(User, name: "lol") - user_event = Repo.get_by(UserEvent, user_id: user.id) - - assert user_event - assert user_event.stages == [] - - conn - |> put_req_header("x-auth-key", "x-key") - |> post( - Routes.ext_api_user_path(conn, :create, %{ - name: "lol", - clan: "S2xhbg==", - UID: "asdf", - category: "cat" - }) - ) - |> json_response(200) - - user_event = Repo.get_by(UserEvent, user_id: user.id) - - assert user_event.stages == [] - - Application.delete_env(:codebattle, :main_event_slug) - end - end -end diff --git a/services/app/apps/codebattle/test/codebattle_web/controllers/game_controller_test.exs b/services/app/apps/codebattle/test/codebattle_web/controllers/game_controller_test.exs deleted file mode 100644 index 3a1e2d4cb..000000000 --- a/services/app/apps/codebattle/test/codebattle_web/controllers/game_controller_test.exs +++ /dev/null @@ -1,110 +0,0 @@ -defmodule CodebattleWeb.GameControllerTest do - use CodebattleWeb.ConnCase, async: false - - import Ecto.Query, warn: false - - alias Codebattle.Game - - describe "GET games/:id" do - test "shows live waiting_opponent game", %{conn: conn} do - users = build_list(1, :user) - task = build(:task) - - {:ok, game} = - Game.Context.create_game(%{state: "waiting_opponent", players: users, task: task}) - - conn - |> get(Routes.game_path(conn, :show, game.id)) - |> html_response(200) - end - - test "shows live playing game", %{conn: conn} do - users = build_list(2, :user) - task = build(:task) - {:ok, game} = Game.Context.create_game(%{state: "playing", players: users, task: task}) - - conn - |> get(Routes.game_path(conn, :show, game.id)) - |> html_response(200) - end - - test "shows live game_over game", %{conn: conn} do - users = build_list(2, :user) - task = build(:task) - {:ok, game} = Game.Context.create_game(%{state: "game_over", players: users, task: task}) - - conn - |> get(Routes.game_path(conn, :show, game.id)) - |> html_response(200) - end - - test "return 200 when game is not live", %{conn: conn} do - users = build_list(2, :user) - task = build(:task) - {:ok, game} = Game.Context.create_game(%{state: "game_over", players: users, task: task}) - Game.Context.terminate_game(game) - - conn - |> get(Routes.game_path(conn, :show, game.id)) - |> html_response(200) - end - - test "return 404 when game over does not exists", %{conn: conn} do - assert_error_sent(:not_found, fn -> - get(conn, Routes.game_path(conn, :show, 1_231_223)) - end) - end - end - - describe "DELETE /games/:id" do - test "cancels game", %{conn: conn} do - [user1 | _] = users = insert_list(1, :user) - task = build(:task) - - {:ok, game} = - Game.Context.create_game(%{state: "waiting_opponent", players: users, task: task}) - - conn - |> put_session(:user_id, user1.id) - |> delete(Routes.game_path(conn, :delete, game.id)) - |> html_response(302) - - updated = Game.Context.get_game!(game.id) - assert updated.is_live == false - assert updated.state == "canceled" - end - end - - describe "POST /games/:id/join" do - test "joins game", %{conn: conn} do - task = insert(:task, level: "elementary") - - [user1, user2] = insert_list(2, :user) - - {:ok, game} = - Game.Context.create_game(%{state: "waiting_opponent", players: [user1], task: task}) - - conn - |> put_session(:user_id, user2.id) - |> post(Routes.game_path(conn, :join, game.id)) - |> html_response(302) - - updated = Game.Context.get_game!(game.id) - user1_id = user1.id - user2_id = user2.id - assert updated.is_live == true - assert updated.state == "playing" - assert [%{id: ^user1_id}, %{id: ^user2_id}] = updated.players - end - end - - describe "POST /games/training" do - test "creates training game", %{conn: conn} do - insert(:task, level: "elementary", tags: ["training"]) - - conn - |> post(Routes.game_path(conn, :create_training)) - |> html_response(302) - end - end -end diff --git a/services/app/apps/codebattle/test/codebattle_web/controllers/health_controller_test.exs b/services/app/apps/codebattle/test/codebattle_web/controllers/health_controller_test.exs deleted file mode 100644 index 8e03a2e50..000000000 --- a/services/app/apps/codebattle/test/codebattle_web/controllers/health_controller_test.exs +++ /dev/null @@ -1,11 +0,0 @@ -defmodule CodebattleWeb.HealthControllerTest do - use CodebattleWeb.ConnCase, async: true - - describe ".index" do - test "works", %{conn: conn} do - conn - |> get(Routes.health_path(conn, :index)) - |> json_response(200) - end - end -end diff --git a/services/app/apps/codebattle/test/codebattle_web/controllers/live_view_tournament_controller_test.exs b/services/app/apps/codebattle/test/codebattle_web/controllers/live_view_tournament_controller_test.exs deleted file mode 100644 index abfc4a3ba..000000000 --- a/services/app/apps/codebattle/test/codebattle_web/controllers/live_view_tournament_controller_test.exs +++ /dev/null @@ -1,81 +0,0 @@ -defmodule CodebattleWeb.LiveViewTournamentControllerTest do - use CodebattleWeb.ConnCase - - alias Codebattle.Tournament - - test "renders index for signed_user", %{conn: conn} do - user = insert(:user) - - conn = - conn - |> put_session(:user_id, user.id) - |> get(Routes.tournament_path(conn, :index)) - - assert conn.status == 200 - end - - test "authorizes to tournaments", %{conn: conn} do - creator = insert(:user) - admin = insert(:admin) - user = insert(:user) - - {:ok, tournament} = - Tournament.Context.create(%{ - "starts_at" => "2022-02-24T06:00", - "name" => "Test Arena 2", - "user_timezone" => "Etc/UTC", - "level" => "easy", - "creator" => creator, - "access_type" => "token", - "access_token" => "access_token", - "break_duration_seconds" => 0, - "type" => "arena", - "state" => "waiting_participants", - "players_limit" => 200 - }) - - Tournament.Server.handle_event(tournament.id, :join, %{user: user}) - - new_conn = - conn - |> put_session(:user_id, admin.id) - |> get(Routes.tournament_path(conn, :show, tournament.id)) - - assert new_conn.status == 200 - - new_conn = - conn - |> put_session(:user_id, creator.id) - |> get(Routes.tournament_path(conn, :show, tournament.id)) - - assert new_conn.status == 200 - - new_conn = - conn - |> put_session(:user_id, user.id) - |> get(Routes.tournament_path(conn, :show, tournament.id)) - - assert new_conn.status == 200 - - new_conn = - conn - |> put_session(:user_id, user.id) - |> get(Routes.tournament_path(conn, :show, tournament.id, access_token: tournament.access_token)) - - assert new_conn.status == 200 - - new_conn = get(conn, Routes.tournament_path(conn, :show, tournament.id)) - - assert new_conn.status == 302 - end - - test "renders not found", %{conn: conn} do - user = insert(:user) - - assert_raise Ecto.NoResultsError, fn -> - conn - |> put_session(:user_id, user.id) - |> get(Routes.tournament_path(conn, :show, 12_313_221)) - end - end -end diff --git a/services/app/apps/codebattle/test/codebattle_web/controllers/locale_test.exs b/services/app/apps/codebattle/test/codebattle_web/controllers/locale_test.exs deleted file mode 100644 index 640301299..000000000 --- a/services/app/apps/codebattle/test/codebattle_web/controllers/locale_test.exs +++ /dev/null @@ -1,13 +0,0 @@ -defmodule CodebattleWeb.LocaleTest do - use CodebattleWeb.ConnCase, async: true - - # test "get en locale as default", %{conn: conn} do - # conn = get(conn, Routes.root_path(conn, :index)) - # assert html_response(conn, 200) =~ "Welcome to Codebattle!" - # end - - # test "get ru locale when it is specified", %{conn: conn} do - # conn = get(conn, Routes.root_path(conn, :index), locale: "ru") - # assert html_response(conn, 200) =~ "Добро пожаловать в Codebattle" - # end -end diff --git a/services/app/apps/codebattle/test/codebattle_web/controllers/public_event_controller_test.exs b/services/app/apps/codebattle/test/codebattle_web/controllers/public_event_controller_test.exs deleted file mode 100644 index 97792c3b1..000000000 --- a/services/app/apps/codebattle/test/codebattle_web/controllers/public_event_controller_test.exs +++ /dev/null @@ -1,151 +0,0 @@ -defmodule CodebattleWeb.PublicEventControllerTest do - use CodebattleWeb.ConnCase, async: false - - alias Codebattle.Tournament - alias Codebattle.UserEvent - - describe ".show" do - setup do - FunWithFlags.enable(:allow_event_page) - :ok - end - - test "renders event page when user is authenticated", %{conn: conn} do - user = insert(:user) - event = insert(:event, slug: "q", ticker_text: "Test Event") - insert(:user_event, user_id: user.id, event_id: event.id) - - conn = - conn - |> put_session(:user_id, user.id) - |> get(Routes.public_event_path(conn, :show, event.slug)) - - assert html_response(conn, 200) =~ event.ticker_text - end - - test "redirects to login when user is not authenticated", %{conn: conn} do - event = insert(:event, slug: "q") - - conn = get(conn, Routes.public_event_path(conn, :show, event.slug)) - - assert redirected_to(conn) =~ Routes.session_path(conn, :new) - end - end - - describe ".stage" do - setup do - FunWithFlags.enable(:allow_event_page) - user = insert(:user) - - event = - insert(:event, - slug: "q", - ticker_text: "Test Event", - stages: [ - %{ - name: "Qualification", - slug: "q", - status: :active, - type: :tournament, - playing_type: :single, - tournament_meta: %{ - type: :swiss, - rounds_limit: 7, - access_type: "token", - score_strategy: "win_loss", - state: :waiting_participants, - task_pack_name: "7_elementary", - tournament_timeout_seconds: 75 * 60, - players_limit: 128, - ranking_type: "void", - task_provider: "task_pack", - task_strategy: "sequential" - } - } - ] - ) - - {:ok, user: user, event: event} - end - - test "redirects to tournament when starting a stage", %{ - conn: conn, - user: user, - event: event - } do - insert(:user_event, - user_id: user.id, - event_id: event.id, - stages: [%{slug: "q", status: :pending}] - ) - - insert(:task_pack, name: "7_elementary") - - conn = - conn - |> put_session(:user_id, user.id) - |> post(Routes.public_event_path(conn, :stage, event.slug, %{stage_slug: "q"})) - - assert [db_tournament] = Repo.all(Tournament) - tournament_id = db_tournament.id - - assert tournament = Tournament.Context.get!(tournament_id) - assert tournament.state == "active" - assert tournament.type == "swiss" - assert tournament.access_type == "token" - assert players = Tournament.Helpers.get_players(tournament) - assert tournament.tournament_timeout_seconds == 75 * 60 - assert tournament.players_limit == 128 - assert tournament.ranking_type == "void" - assert tournament.task_provider == "task_pack" - assert tournament.task_strategy == "sequential" - assert tournament.task_pack_name == "7_elementary" - - assert [_bot, player] = Enum.sort_by(players, & &1.id) - assert player.id == user.id - - assert redirected_to(conn) == Routes.tournament_path(conn, :show, tournament_id) - - assert [user_event] = Repo.all(UserEvent) - - assert [stage = %{slug: "q", status: :started, tournament_id: ^tournament_id}] = - user_event.stages - - assert stage.started_at - end - - test "shows error when starting a stage fails", %{ - conn: conn, - user: user, - event: event - } do - insert(:user_event, user_id: user.id, event_id: event.id) - - conn = - conn - |> put_session(:user_id, user.id) - |> post(Routes.public_event_path(conn, :stage, event.slug, %{stage_slug: "q"})) - - assert redirected_to(conn) == Routes.public_event_path(conn, :show, event.slug) - end - - test "shows error when user has already passed the stage", %{ - conn: conn, - user: user, - event: event - } do - insert(:user_event, - user_id: user.id, - event_id: event.id, - stages: [%{"slug" => "q", "status" => :passed}] - ) - - conn = - conn - |> put_session(:user_id, user.id) - |> post(Routes.public_event_path(conn, :stage, event.slug, %{stage_slug: "q"})) - - assert redirected_to(conn) == Routes.public_event_path(conn, :show, event.slug) - end - end -end diff --git a/services/app/apps/codebattle/test/codebattle_web/controllers/root_controller_test.exs b/services/app/apps/codebattle/test/codebattle_web/controllers/root_controller_test.exs deleted file mode 100644 index dfa3a1669..000000000 --- a/services/app/apps/codebattle/test/codebattle_web/controllers/root_controller_test.exs +++ /dev/null @@ -1,19 +0,0 @@ -defmodule Codebattle.RootControllerTest do - use CodebattleWeb.ConnCase, async: true - - test "index", %{conn: conn} do - conn = get(conn, "/") - assert html_response(conn, 200) - end - - test "index for signed_user", %{conn: conn} do - user = insert(:user) - - conn = - conn - |> put_session(:user_id, user.id) - |> get(Routes.user_path(conn, :index)) - - assert conn.status == 200 - end -end diff --git a/services/app/apps/codebattle/test/codebattle_web/controllers/session_controller_test.exs b/services/app/apps/codebattle/test/codebattle_web/controllers/session_controller_test.exs deleted file mode 100644 index befc19c1d..000000000 --- a/services/app/apps/codebattle/test/codebattle_web/controllers/session_controller_test.exs +++ /dev/null @@ -1,23 +0,0 @@ -defmodule CodebattleWeb.SessionControllerTest do - use CodebattleWeb.ConnCase, async: true - - test "new", %{conn: conn} do - conn = - get( - conn, - Routes.session_path(conn, :new) - ) - - assert conn.status == 200 - end - - test "remind_password", %{conn: conn} do - conn = - get( - conn, - Routes.session_path(conn, :remind_password) - ) - - assert conn.status == 200 - end -end diff --git a/services/app/apps/codebattle/test/codebattle_web/controllers/task_controller_test.exs b/services/app/apps/codebattle/test/codebattle_web/controllers/task_controller_test.exs deleted file mode 100644 index 366f2b346..000000000 --- a/services/app/apps/codebattle/test/codebattle_web/controllers/task_controller_test.exs +++ /dev/null @@ -1,253 +0,0 @@ -defmodule CodebattleWeb.TaskControllerTest do - use CodebattleWeb.ConnCase, async: true - - test ".index", %{conn: conn} do - user = insert(:user) - insert_list(3, :task) - - conn = - conn - |> put_session(:user_id, user.id) - |> get(Routes.task_path(conn, :index)) - - assert conn.status == 200 - end - - test ".show", %{conn: conn} do - user = insert(:user) - admin = insert(:admin) - visible_task = insert(:task, visibility: "public") - hidden_task = insert(:task, visibility: "hidden") - hidden_created_task = insert(:task, visibility: "hidden", creator_id: user.id) - - # guest redirected - new_conn = get(conn, Routes.task_path(conn, :show, visible_task.id)) - - assert new_conn.status == 302 - - # user can see public tasks - new_conn = - conn - |> put_session(:user_id, user.id) - |> get(Routes.task_path(conn, :show, visible_task.id)) - - assert new_conn.status == 200 - - # user can't see hidden tasks - new_conn = - conn - |> put_session(:user_id, user.id) - |> get(Routes.task_path(conn, :show, hidden_task.id)) - - assert new_conn.status == 404 - - # user can see his hidden tasks - new_conn = - conn - |> put_session(:user_id, user.id) - |> get(Routes.task_path(conn, :show, hidden_created_task.id)) - - assert new_conn.status == 200 - - # admin can see hidden tasks - new_conn = - conn - |> put_session(:user_id, admin.id) - |> get(Routes.task_path(conn, :show, hidden_task.id)) - - assert new_conn.status == 200 - end - - @tag :skip - # move to api/v1/task_controller - test ".create", %{conn: conn} do - user = insert(:user) - - params = %{ - "asserts" => ~s([{"arguments":[1,1],"expected":2}, {"arguments":[1,1],"expected":2}]), - "description_en" => "test sum: for ruby", - "description_ru" => "проверка суммирования: для руби", - "examples" => "```\n2 == solution(1,1)\n10 == solution(9,1)\n```", - "input_signature" => - ~s([{"argument_name":"a","type":{"name":"integer"}},{"argument_name":"b","type":{"name":"integer"}}]), - "level" => "easy", - "name" => "asdfasdf", - "output_signature" => ~s({"type":{"name":"integer"}}), - "tags" => " kek,lol, asdf " - } - - conn = - conn - |> put_session(:user_id, user.id) - |> post(Routes.task_path(conn, :create), task: params) - - assert %{id: id} = redirected_params(conn) - assert redirected_to(conn) == Routes.task_path(conn, :show, id) - - conn = get(conn, Routes.task_path(conn, :show, id)) - assert html_response(conn, 200) - - task = Codebattle.Task.get!(id) - user_id = user.id - - assert %{ - asserts: [ - %{arguments: [1, 1], expected: 2}, - %{arguments: [1, 1], expected: 2} - ], - creator_id: ^user_id, - description_en: "test sum: for ruby", - description_ru: "проверка суммирования: для руби", - examples: "```\n2 == solution(1,1)\n10 == solution(9,1)\n```", - input_signature: [ - %{argument_name: "a", type: %{name: "integer"}}, - %{argument_name: "b", type: %{name: "integer"}} - ], - level: "easy", - name: "asdfasdf", - origin: "user", - output_signature: %{type: %{name: "integer"}}, - state: "draft", - tags: ["kek", "lol", "asdf"], - visibility: "public" - } = task - end - - @tag :skip - # move to api/v1/task_controller - test ".update", %{conn: conn} do - user = insert(:user) - task = insert(:task, creator_id: user.id) - - params = %{ - "asserts" => ~s([{"arguments":[1,1],"expected":2}, {"arguments":[1,1],"expected":2}]), - "description_en" => "test sum: for ruby", - "description_ru" => "проверка суммирования: для руби", - "examples" => "```\n2 == solution(1,1)\n10 == solution(9,1)\n```", - "input_signature" => - ~s([{"argument_name":"a","type":{"name":"integer"}},{"argument_name":"b","type":{"name":"integer"}}]), - "level" => "hard", - "name" => "mega_task", - "output_signature" => ~s({"type":{"name":"string"}}), - "tags" => " kek,lol" - } - - conn = - conn - |> put_session(:user_id, user.id) - |> patch(Routes.task_path(conn, :update, task), task: params) - - assert %{id: id} = redirected_params(conn) - assert redirected_to(conn) == Routes.task_path(conn, :edit, id) - - task = Codebattle.Task.get!(id) - - assert %{ - asserts: [ - %{arguments: [1, 1], expected: 2}, - %{arguments: [1, 1], expected: 2} - ], - description_en: "test sum: for ruby", - description_ru: "проверка суммирования: для руби", - examples: "```\n2 == solution(1,1)\n10 == solution(9,1)\n```", - input_signature: [ - %{argument_name: "a", type: %{name: "integer"}}, - %{argument_name: "b", type: %{name: "integer"}} - ], - level: "hard", - name: "mega_task", - origin: "user", - output_signature: %{type: %{name: "string"}}, - tags: ["kek", "lol"] - } = task - end - - test ".activate", %{conn: conn} do - user = insert(:user) - admin = insert(:admin) - task = insert(:task, creator_id: user.id, state: "disabled") - - new_conn = - conn - |> put_session(:user_id, user.id) - |> patch(Routes.task_activate_path(conn, :activate, task)) - - assert new_conn.status == 404 - - new_conn = - conn - |> put_session(:user_id, admin.id) - |> patch(Routes.task_activate_path(conn, :activate, task)) - - assert redirected_to(new_conn) == Routes.task_path(conn, :index) - - task = Codebattle.Task.get!(task.id) - - assert task.state == "active" - end - - test ".disable", %{conn: conn} do - user = insert(:user) - admin = insert(:admin) - task = insert(:task, creator_id: user.id, state: "active") - - new_conn = - conn - |> put_session(:user_id, user.id) - |> patch(Routes.task_disable_path(conn, :disable, task)) - - assert new_conn.status == 404 - - new_conn = - conn - |> put_session(:user_id, admin.id) - |> patch(Routes.task_disable_path(conn, :disable, task)) - - assert redirected_to(new_conn) == Routes.task_path(conn, :index) - - task = Codebattle.Task.get!(task.id) - - assert task.state == "disabled" - end - - test ".delete", %{conn: conn} do - user = insert(:user) - admin = insert(:admin) - task = insert(:task, creator_id: admin.id, state: "active", origin: "user") - - # unrelated user - new_conn = - conn - |> put_session(:user_id, user.id) - |> delete(Routes.task_path(conn, :delete, task)) - - assert new_conn.status == 404 - - # admin or creator - new_conn = - conn - |> put_session(:user_id, admin.id) - |> delete(Routes.task_path(conn, :delete, task)) - - assert redirected_to(new_conn) == Routes.task_path(conn, :index) - - # task from github - task = insert(:task, creator_id: admin.id, state: "active", origin: "github") - - # unrelated user - new_conn = - conn - |> put_session(:user_id, user.id) - |> delete(Routes.task_path(conn, :delete, task)) - - assert new_conn.status == 404 - - # admin or creator - new_conn = - conn - |> put_session(:user_id, admin.id) - |> delete(Routes.task_path(conn, :delete, task)) - - assert new_conn.status == 404 - end -end diff --git a/services/app/apps/codebattle/test/codebattle_web/controllers/task_pack_controller_test.exs b/services/app/apps/codebattle/test/codebattle_web/controllers/task_pack_controller_test.exs deleted file mode 100644 index e83ac014d..000000000 --- a/services/app/apps/codebattle/test/codebattle_web/controllers/task_pack_controller_test.exs +++ /dev/null @@ -1,185 +0,0 @@ -defmodule CodebattleWeb.TaskPackControllerTest do - use CodebattleWeb.ConnCase, async: true - - test ".index", %{conn: conn} do - user = insert(:user) - insert_list(3, :task_pack) - - conn = - conn - |> put_session(:user_id, user.id) - |> get(Routes.task_pack_path(conn, :index)) - - assert conn.status == 200 - end - - test ".show", %{conn: conn} do - user = insert(:user) - admin = insert(:admin) - visible_task_pack = insert(:task_pack, visibility: "public") - hidden_task_pack = insert(:task_pack, visibility: "hidden") - hidden_created_task_pack = insert(:task_pack, visibility: "hidden", creator_id: user.id) - - # guest redirected - new_conn = get(conn, Routes.task_pack_path(conn, :show, visible_task_pack.id)) - - assert new_conn.status == 302 - - # user can see public tasks - new_conn = - conn - |> put_session(:user_id, user.id) - |> get(Routes.task_pack_path(conn, :show, visible_task_pack)) - - assert new_conn.status == 200 - - # user can't see hidden tasks - new_conn = - conn - |> put_session(:user_id, user.id) - |> get(Routes.task_pack_path(conn, :show, hidden_task_pack.id)) - - assert new_conn.status == 404 - - # user can see his hidden tasks - new_conn = - conn - |> put_session(:user_id, user.id) - |> get(Routes.task_pack_path(conn, :show, hidden_created_task_pack.id)) - - assert new_conn.status == 200 - - # admin can see hidden tasks - new_conn = - conn - |> put_session(:user_id, admin.id) - |> get(Routes.task_pack_path(conn, :show, hidden_task_pack.id)) - - assert new_conn.status == 200 - end - - test ".create", %{conn: conn} do - user = insert(:user) - - params = %{ - "name" => "mega_pack", - "task_ids" => " 1, 37, 42 ", - "visibility" => "public" - } - - conn = - conn - |> put_session(:user_id, user.id) - |> post(Routes.task_pack_path(conn, :create), task_pack: params) - - assert %{id: id} = redirected_params(conn) - assert redirected_to(conn) == Routes.task_pack_path(conn, :show, id) - - conn = get(conn, Routes.task_pack_path(conn, :show, id)) - assert html_response(conn, 200) - - task_pack = Codebattle.TaskPack.get!(id) - user_id = user.id - - assert %{ - creator_id: ^user_id, - name: "mega_pack", - task_ids: [1, 37, 42], - visibility: "public", - state: "draft" - } = task_pack - end - - test ".update", %{conn: conn} do - user = insert(:user) - task_pack = insert(:task_pack, creator_id: user.id) - - params = %{ - "name" => "new_mega_task_pack", - "task_ids" => " 22", - "visibility" => "public" - } - - conn = - conn - |> put_session(:user_id, user.id) - |> patch(Routes.task_pack_path(conn, :update, task_pack), task_pack: params) - - assert %{id: id} = redirected_params(conn) - assert redirected_to(conn) == Routes.task_pack_path(conn, :edit, id) - - task_pack = Codebattle.TaskPack.get!(id) - - assert %{name: "new_mega_task_pack", task_ids: [22]} = task_pack - end - - test ".activate", %{conn: conn} do - user = insert(:user) - admin = insert(:admin) - task_pack = insert(:task_pack, creator_id: user.id, state: "disabled") - - new_conn = - conn - |> put_session(:user_id, user.id) - |> patch(Routes.task_pack_activate_path(conn, :activate, task_pack)) - - assert new_conn.status == 404 - - new_conn = - conn - |> put_session(:user_id, admin.id) - |> patch(Routes.task_pack_activate_path(conn, :activate, task_pack)) - - assert redirected_to(new_conn) == Routes.task_pack_path(conn, :index) - - task_pack = Codebattle.TaskPack.get!(task_pack.id) - - assert task_pack.state == "active" - end - - test ".disable", %{conn: conn} do - user = insert(:user) - admin = insert(:admin) - task_pack = insert(:task_pack, creator_id: user.id, state: "active") - - new_conn = - conn - |> put_session(:user_id, user.id) - |> patch(Routes.task_pack_disable_path(conn, :disable, task_pack)) - - assert new_conn.status == 404 - - new_conn = - conn - |> put_session(:user_id, admin.id) - |> patch(Routes.task_pack_disable_path(conn, :disable, task_pack)) - - assert redirected_to(new_conn) == Routes.task_pack_path(conn, :index) - - task_pack = Codebattle.TaskPack.get!(task_pack.id) - - assert task_pack.state == "disabled" - end - - test ".delete", %{conn: conn} do - user = insert(:user) - admin = insert(:admin) - task_pack = insert(:task_pack, creator_id: admin.id, state: "active") - - # unrelated user - new_conn = - conn - |> put_session(:user_id, user.id) - |> delete(Routes.task_pack_path(conn, :delete, task_pack)) - - assert new_conn.status == 404 - - # admin or creator - new_conn = - conn - |> put_session(:user_id, admin.id) - |> delete(Routes.task_pack_path(conn, :delete, task_pack)) - - assert redirected_to(new_conn) == Routes.task_pack_path(conn, :index) - end -end diff --git a/services/app/apps/codebattle/test/codebattle_web/controllers/user_controller_test.exs b/services/app/apps/codebattle/test/codebattle_web/controllers/user_controller_test.exs deleted file mode 100644 index a059c5054..000000000 --- a/services/app/apps/codebattle/test/codebattle_web/controllers/user_controller_test.exs +++ /dev/null @@ -1,62 +0,0 @@ -defmodule CodebattleWeb.UserControllerTest do - use CodebattleWeb.ConnCase, async: true - - test "index for signed_user", %{conn: conn} do - user = insert(:user) - - conn = - conn - |> put_session(:user_id, user.id) - |> get(Routes.user_path(conn, :index)) - - assert conn.status == 200 - end - - test "index", %{conn: conn} do - conn = get(conn, Routes.user_path(conn, :index)) - - assert redirected_to(conn, 302) == - Routes.session_path(CodebattleWeb.Endpoint, :new, next: Routes.user_path(conn, :index)) - end - - test "new", %{conn: conn} do - conn = - get( - conn, - Routes.user_path(conn, :new) - ) - - assert conn.status == 200 - end - - test "show user: signed in", %{conn: conn} do - user = insert(:user) - - conn = - conn - |> put_session(:user_id, user.id) - |> get(Routes.user_path(conn, :show, user.id)) - - assert conn.status == 200 - end - - test "show user: not signed in", %{conn: conn} do - user = insert(:user) - - conn = get(conn, Routes.user_path(conn, :show, user.id)) - - assert redirected_to(conn, 302) == - Routes.session_path(CodebattleWeb.Endpoint, :new, next: Routes.user_path(conn, :show, user.id)) - end - - test "edit user", %{conn: conn} do - user = insert(:user) - - conn = - conn - |> put_session(:user_id, user.id) - |> get(Routes.user_setting_path(conn, :edit)) - - assert conn.status == 200 - end -end diff --git a/services/app/apps/codebattle/test/codebattle_web/integration/game/recalculate_achivements_test.exs b/services/app/apps/codebattle/test/codebattle_web/integration/game/recalculate_achivements_test.exs deleted file mode 100644 index cdeb93a6d..000000000 --- a/services/app/apps/codebattle/test/codebattle_web/integration/game/recalculate_achivements_test.exs +++ /dev/null @@ -1,109 +0,0 @@ -defmodule CodebattleWeb.Integration.Game.RecalculateAchivementsTest do - use Codebattle.IntegrationCase - - import CodebattleWeb.Factory - - alias Codebattle.User - alias CodebattleWeb.UserSocket - - setup %{conn: conn} do - insert(:task) - - user1 = - insert(:user, %{ - name: "first", - email: "test1@test.test", - github_id: 1, - rating: 1000, - achievements: [] - }) - - user2 = - insert(:user, %{ - name: "second", - email: "test2@test.test", - github_id: 2, - rating: 1000, - achievements: [] - }) - - conn2 = put_session(conn, :user_id, user2.id) - - socket1 = socket(UserSocket, "user_id", %{user_id: user1.id, current_user: user1}) - socket2 = socket(UserSocket, "user_id", %{user_id: user2.id, current_user: user2}) - - {:ok, %{conn2: conn2, socket1: socket1, socket2: socket2, user1: user1, user2: user2}} - end - - test "calculate new achievement", %{ - conn2: conn2, - socket1: socket1, - socket2: socket2, - user1: user1, - user2: _user2 - } do - insert_list(9, :user_game, %{user: user1}) - - {:ok, _response, socket1} = subscribe_and_join(socket1, LobbyChannel, "lobby") - - ref = Phoenix.ChannelTest.push(socket1, "game:create", %{level: "easy"}) - Phoenix.ChannelTest.assert_reply(ref, :ok, %{game_id: game_id}) - - game_topic = "game:" <> to_string(game_id) - {:ok, _response, socket1} = subscribe_and_join(socket1, GameChannel, game_topic) - - # Second player join game - post(conn2, game_path(conn2, :join, game_id)) - subscribe_and_join(socket2, GameChannel, game_topic) - # First player won - editor_text1 = "Hello world1!" - - Phoenix.ChannelTest.push(socket1, "check_result", %{ - editor_text: editor_text1, - lang_slug: "js" - }) - - :timer.sleep(100) - - user = Repo.get!(User, user1.id) - assert user.achievements == ["played_ten_games"] - end - - test "calculate polyglot achievement", %{ - conn2: conn2, - socket1: socket1, - socket2: socket2, - user1: user1, - user2: _user2 - } do - Enum.each(["js", "php", "ruby"], fn x -> - insert_list(3, :user_game, %{user: user1, lang: x, result: "won"}) - end) - - # Create game - {:ok, _response, socket1} = subscribe_and_join(socket1, LobbyChannel, "lobby") - - ref = Phoenix.ChannelTest.push(socket1, "game:create", %{level: "easy"}) - :timer.sleep(100) - Phoenix.ChannelTest.assert_reply(ref, :ok, %{game_id: game_id}) - - game_topic = "game:" <> to_string(game_id) - {:ok, _response, socket1} = subscribe_and_join(socket1, GameChannel, game_topic) - - # Second player join game - post(conn2, game_path(conn2, :join, game_id)) - subscribe_and_join(socket2, GameChannel, game_topic) - # First player won - editor_text1 = "Hello world1!" - - Phoenix.ChannelTest.push(socket1, "check_result", %{ - editor_text: editor_text1, - lang_slug: "js" - }) - - :timer.sleep(200) - - user = User.get!(user1.id) - assert user.achievements == ["played_ten_games", "win_games_with?js_php_ruby"] - end -end diff --git a/services/app/apps/codebattle/test/codebattle_web/integration/tournament/arena_clan_95_percentile_test.exs b/services/app/apps/codebattle/test/codebattle_web/integration/tournament/arena_clan_95_percentile_test.exs deleted file mode 100644 index fc6cfb947..000000000 --- a/services/app/apps/codebattle/test/codebattle_web/integration/tournament/arena_clan_95_percentile_test.exs +++ /dev/null @@ -1,345 +0,0 @@ -defmodule CodebattleWeb.Integration.Tournament.ArenaClan95PercentileTest do - use Codebattle.IntegrationCase - - alias Codebattle.Tournament - alias Phoenix.Socket.Broadcast - alias Phoenix.Socket.Message - - test "Arena Clan 1 round sequential 95_percentile task_pack" do - %{id: t1_id} = insert(:task, level: "easy") - %{id: t2_id} = insert(:task, level: "medium") - %{id: t3_id} = insert(:task, level: "hard") - - insert(:task_pack, name: "tp", task_ids: [t1_id, t2_id, t3_id]) - admin = insert(:user, %{name: "a"}) - - {:ok, tournament} = - Tournament.Context.create(%{ - "starts_at" => "2022-02-24T06:00", - "name" => "Test Personal Clan Arena", - "user_timezone" => "Etc/UTC", - "level" => "easy", - "task_pack_name" => "tp", - "creator" => admin, - "break_duration_seconds" => 0, - "score_strategy" => "win_loss", - "task_provider" => "task_pack_per_round", - "task_strategy" => "sequential", - "ranking_type" => "by_player_95th_percentile", - "type" => "arena", - "state" => "waiting_participants", - "use_clan" => "true", - "rounds_limit" => "1", - "players_limit" => 200 - }) - - tournament_topic = "tournament:#{tournament.id}" - tournament_admin_topic = "tournament_admin:#{tournament.id}" - - clan1 = %{id: c1_id} = insert(:clan, %{name: "c1", long_name: "cl1"}) - clan2 = %{id: c2_id} = insert(:clan, %{name: "c2", long_name: "cl2"}) - clan3 = %{id: c3_id} = insert(:clan, %{name: "c3", long_name: "cl3"}) - clan4 = %{id: c4_id} = insert(:clan, %{name: "c4", long_name: "cl4"}) - - user1 = %{id: u1_id} = insert(:user, name: "1", clan_id: clan1.id, clan: clan1.name) - user2 = insert(:user, name: "2", clan_id: clan1.id, clan: clan1.name) - user3 = insert(:user, name: "3", clan_id: clan2.id, clan: clan2.name) - user4 = insert(:user, name: "4", clan_id: clan2.id, clan: clan2.name) - user5 = insert(:user, name: "5", clan_id: clan3.id, clan: clan3.name) - user6 = insert(:user, name: "6", clan_id: clan3.id, clan: clan3.name) - user7 = insert(:user, name: "7", clan_id: clan4.id, clan: clan4.name) - user8 = insert(:user, name: "8", clan_id: clan4.id, clan: clan4.name) - - admin_socket = socket(UserSocket, "user_id", %{user_id: admin.id, current_user: admin}) - socket1 = socket(UserSocket, "user_id", %{user_id: user1.id, current_user: user1}) - socket2 = socket(UserSocket, "user_id", %{user_id: user2.id, current_user: user2}) - socket3 = socket(UserSocket, "user_id", %{user_id: user3.id, current_user: user3}) - socket4 = socket(UserSocket, "user_id", %{user_id: user4.id, current_user: user4}) - socket5 = socket(UserSocket, "user_id", %{user_id: user5.id, current_user: user5}) - socket6 = socket(UserSocket, "user_id", %{user_id: user6.id, current_user: user6}) - socket7 = socket(UserSocket, "user_id", %{user_id: user7.id, current_user: user7}) - socket8 = socket(UserSocket, "user_id", %{user_id: user8.id, current_user: user8}) - - {:ok, _response, socket1} = subscribe_and_join(socket1, TournamentChannel, tournament_topic) - {:ok, _response, socket2} = subscribe_and_join(socket2, TournamentChannel, tournament_topic) - {:ok, _response, socket3} = subscribe_and_join(socket3, TournamentChannel, tournament_topic) - {:ok, _response, socket4} = subscribe_and_join(socket4, TournamentChannel, tournament_topic) - {:ok, _response, socket5} = subscribe_and_join(socket5, TournamentChannel, tournament_topic) - {:ok, _response, socket6} = subscribe_and_join(socket6, TournamentChannel, tournament_topic) - - Phoenix.ChannelTest.push(socket1, "tournament:join", %{}) - :timer.sleep(10) - Phoenix.ChannelTest.push(socket2, "tournament:join", %{}) - :timer.sleep(10) - Phoenix.ChannelTest.push(socket3, "tournament:join", %{}) - :timer.sleep(10) - Phoenix.ChannelTest.push(socket4, "tournament:join", %{}) - :timer.sleep(10) - Phoenix.ChannelTest.push(socket5, "tournament:join", %{}) - :timer.sleep(10) - Phoenix.ChannelTest.push(socket6, "tournament:join", %{}) - - # 7 users joined for 7 user sockets - Enum.each(1..36, fn _i -> - assert_receive %Message{ - event: "tournament:player:joined", - payload: %{ - player: %Tournament.Player{clan_id: _, id: _, name: _, state: "active"}, - tournament: %{players_count: _} - } - } - end) - - {:ok, user_response, socket7} = - subscribe_and_join(socket7, TournamentChannel, tournament_topic) - - assert %{ - matches: [], - players: [_p1, _p2, _p3, _p4, _p5, _p6], - ranking: %{ - page_size: 10, - entries: [ - %{clan: "c1", clan_id: _, id: _, place: 1, score: 0, name: "1"}, - %{clan: "c1", clan_id: _, id: _, place: 2, score: 0, name: "2"}, - %{clan: "c2", clan_id: _, id: _, place: 3, score: 0, name: "3"}, - %{clan: "c2", clan_id: _, id: _, place: 4, score: 0, name: "4"}, - %{clan: "c3", clan_id: _, id: _, place: 5, score: 0, name: "5"}, - %{clan: "c3", clan_id: _, id: _, place: 6, score: 0, name: "6"} - ], - page_number: 1, - total_entries: 6 - }, - tournament: %{ - access_type: "public", - type: "arena", - players_count: 6, - state: "waiting_participants", - break_state: "off", - current_round_position: 0 - } - } = user_response - - Phoenix.ChannelTest.push(socket7, "tournament:join", %{}) - - Enum.each(1..7, fn _i -> - assert_receive %Message{ - event: "tournament:player:joined", - payload: %{ - player: %Tournament.Player{clan_id: _, id: _, name: _, state: "active"}, - tournament: %{players_count: _} - } - } - - assert_receive %Message{ - event: "tournament:ranking_update", - payload: %{ranking: %{}, clans: %{}} - } - end) - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - {:ok, admin_join_response, admin_socket} = - subscribe_and_join(admin_socket, TournamentAdminChannel, tournament_admin_topic) - - assert %{ - clans: %{ - ^c1_id => %{id: ^c1_id, name: "c1", long_name: "cl1"}, - ^c2_id => %{id: ^c2_id, name: "c2", long_name: "cl2"}, - ^c3_id => %{id: ^c3_id, name: "c3", long_name: "cl3"}, - ^c4_id => %{id: ^c4_id, name: "c4", long_name: "cl4"} - }, - matches: [], - players: [%{}, %{}, %{}, %{}, %{}, %{}, %{}], - ranking: %{ - page_size: 42, - entries: [ - %{clan: "c1", clan_id: _, id: _, place: 1, score: 0, name: "1"}, - %{clan: "c1", clan_id: _, id: _, place: 2, score: 0, name: "2"}, - %{clan: "c2", clan_id: _, id: _, place: 3, score: 0, name: "3"}, - %{clan: "c2", clan_id: _, id: _, place: 4, score: 0, name: "4"}, - %{clan: "c3", clan_id: _, id: _, place: 5, score: 0, name: "5"}, - %{clan: "c3", clan_id: _, id: _, place: 6, score: 0, name: "6"}, - %{clan: "c4", clan_id: _, id: _, place: 7, score: 0, name: "7"} - ], - page_number: 1, - total_entries: 7 - }, - tasks_info: %{}, - tournament: %{ - access_type: "public", - type: "arena", - state: "waiting_participants", - break_state: "off", - current_round_position: 0 - } - } = admin_join_response - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - Phoenix.ChannelTest.push(admin_socket, "tournament:start", %{}) - - :timer.sleep(100) - - Enum.each(1..8, fn _i -> - assert_receive %Message{ - event: "tournament:round_created", - payload: %{ - tournament: %{ - break_state: "off", - current_round_position: 0, - last_round_ended_at: nil, - # todo use time mock - last_round_started_at: _ - } - } - } - end) - - assert_receive %Message{ - event: "waiting_room:player:match_created", - payload: %{ - current_player: %{id: ^u1_id, state: "active"}, - players: [%{state: "active"}, %{state: "active"}], - match: %{game_id: game_id, state: "playing"} - } - } - - Enum.each(1..6, fn _i -> - assert_receive %Message{ - event: "waiting_room:player:match_created", - payload: %{ - current_player: %{state: "active"}, - players: [%{state: "active"}, %{state: "active"}], - match: %{state: "playing"} - } - } - end) - - assert_receive %Message{ - event: "tournament:update", - payload: %{tournament: %{}}, - topic: ^tournament_admin_topic - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - {:ok, _response, socket8} = - subscribe_and_join(socket8, TournamentChannel, tournament_topic) - - Phoenix.ChannelTest.push(socket8, "tournament:join", %{}) - - Enum.each(1..9, fn _i -> - assert_receive %Message{ - event: "tournament:player:joined", - payload: %{ - player: %Tournament.Player{clan_id: _, id: _, name: _, state: "matchmaking_active"}, - tournament: %{players_count: _} - } - } - end) - - assert_receive %Message{ - event: "tournament:ranking_update", - payload: %{ranking: %{}, clans: %{}} - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - game_topic = "game:#{game_id}" - {:ok, _response, socket1} = subscribe_and_join(socket1, GameChannel, game_topic) - - Phoenix.ChannelTest.push(socket1, "check_result", %{ - editor_text: "lol", - lang_slug: "js" - }) - - assert_receive %Broadcast{ - event: "user:start_check", - payload: %{user_id: ^u1_id}, - topic: ^game_topic - } - - assert_receive %Broadcast{ - event: "user:check_complete", - payload: %{user_id: ^u1_id, solution_status: true}, - topic: ^game_topic - } - - assert_receive %Message{ - event: "user:check_complete", - payload: %{user_id: ^u1_id, solution_status: true}, - topic: ^game_topic - } - - assert_receive %Message{ - event: "waiting_room:player:matchmaking_started", - payload: %{ - current_player: %{ - id: ^u1_id, - state: "matchmaking_active", - task_ids: [^t1_id], - score: 3, - place: 0, - wins_count: 1 - } - }, - topic: ^game_topic - } - - Process.unlink(socket1.channel_pid) - ref_1 = leave(socket1) - Phoenix.ChannelTest.assert_reply(ref_1, :ok) - assert_receive {:socket_close, _, {:shutdown, :left}} - - assert_receive %Message{ - event: "waiting_room:player:matchmaking_started", - payload: %{ - current_player: %{ - id: ^u1_id, - state: "matchmaking_active", - task_ids: [^t1_id], - score: 3, - place: 0, - wins_count: 1 - } - }, - topic: ^tournament_topic - } - - assert_receive %Message{ - event: "waiting_room:player:matchmaking_started", - payload: %{ - current_player: %{ - state: "matchmaking_active", - task_ids: [^t1_id], - score: 1, - place: 0, - wins_count: 0 - } - }, - topic: ^tournament_topic - } - - assert_receive %Message{ - event: "tournament:match:upserted", - payload: %{ - players: [%{state: "active"}, %{state: "active"}], - match: %{state: "game_over"} - }, - topic: ^tournament_topic - } - - assert_receive %Message{ - event: "tournament:match:upserted", - payload: %{ - players: [%{state: "active"}, %{state: "active"}], - match: %{state: "game_over"} - }, - topic: ^tournament_topic - } - - :timer.sleep(100) - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - end -end diff --git a/services/app/apps/codebattle/test/codebattle_web/integration/tournament/arena_clan_test.exs b/services/app/apps/codebattle/test/codebattle_web/integration/tournament/arena_clan_test.exs deleted file mode 100644 index a491e9836..000000000 --- a/services/app/apps/codebattle/test/codebattle_web/integration/tournament/arena_clan_test.exs +++ /dev/null @@ -1,337 +0,0 @@ -defmodule CodebattleWeb.Integration.Tournament.ArenaClanTest do - use Codebattle.IntegrationCase - - alias Codebattle.Tournament - alias Phoenix.Socket.Broadcast - alias Phoenix.Socket.Message - - test "Arena Clan 1 round sequential task_pack" do - %{id: t1_id} = insert(:task, level: "easy") - %{id: t2_id} = insert(:task, level: "medium") - %{id: t3_id} = insert(:task, level: "hard") - - insert(:task_pack, name: "tp", task_ids: [t1_id, t2_id, t3_id]) - admin = insert(:user, %{name: "a"}) - - {:ok, tournament} = - Tournament.Context.create(%{ - "starts_at" => "2022-02-24T06:00", - "name" => "Test Clan Arena", - "user_timezone" => "Etc/UTC", - "level" => "easy", - "task_pack_name" => "tp", - "creator" => admin, - "break_duration_seconds" => 0, - "score_strategy" => "win_loss", - "task_provider" => "task_pack_per_round", - "task_strategy" => "sequential", - "ranking_type" => "by_clan", - "type" => "arena", - "state" => "waiting_participants", - "use_clan" => "true", - "rounds_limit" => "1", - "players_limit" => 200 - }) - - tournament_topic = "tournament:#{tournament.id}" - tournament_admin_topic = "tournament_admin:#{tournament.id}" - - clan1 = %{id: _c1_id} = insert(:clan, %{name: "c1", long_name: "cl1"}) - clan2 = %{id: _c2_id} = insert(:clan, %{name: "c2", long_name: "cl2"}) - clan3 = %{id: _c3_id} = insert(:clan, %{name: "c3", long_name: "cl3"}) - clan4 = %{id: _c4_id} = insert(:clan, %{name: "c4", long_name: "cl4"}) - - user1 = %{id: u1_id} = insert(:user, name: "1", clan_id: clan1.id, clan: clan1.name) - user2 = insert(:user, name: "2", clan_id: clan1.id, clan: clan1.name) - user3 = insert(:user, name: "3", clan_id: clan2.id, clan: clan2.name) - user4 = insert(:user, name: "4", clan_id: clan2.id, clan: clan2.name) - user5 = insert(:user, name: "5", clan_id: clan3.id, clan: clan3.name) - user6 = insert(:user, name: "6", clan_id: clan3.id, clan: clan3.name) - user7 = insert(:user, name: "7", clan_id: clan4.id, clan: clan4.name) - user8 = insert(:user, name: "8", clan_id: clan4.id, clan: clan4.name) - - admin_socket = socket(UserSocket, "user_id", %{user_id: admin.id, current_user: admin}) - socket1 = socket(UserSocket, "user_id", %{user_id: user1.id, current_user: user1}) - socket2 = socket(UserSocket, "user_id", %{user_id: user2.id, current_user: user2}) - socket3 = socket(UserSocket, "user_id", %{user_id: user3.id, current_user: user3}) - socket4 = socket(UserSocket, "user_id", %{user_id: user4.id, current_user: user4}) - socket5 = socket(UserSocket, "user_id", %{user_id: user5.id, current_user: user5}) - socket6 = socket(UserSocket, "user_id", %{user_id: user6.id, current_user: user6}) - socket7 = socket(UserSocket, "user_id", %{user_id: user7.id, current_user: user7}) - socket8 = socket(UserSocket, "user_id", %{user_id: user8.id, current_user: user8}) - - {:ok, _response, socket1} = subscribe_and_join(socket1, TournamentChannel, tournament_topic) - {:ok, _response, socket2} = subscribe_and_join(socket2, TournamentChannel, tournament_topic) - {:ok, _response, socket3} = subscribe_and_join(socket3, TournamentChannel, tournament_topic) - {:ok, _response, socket4} = subscribe_and_join(socket4, TournamentChannel, tournament_topic) - {:ok, _response, socket5} = subscribe_and_join(socket5, TournamentChannel, tournament_topic) - {:ok, _response, socket6} = subscribe_and_join(socket6, TournamentChannel, tournament_topic) - - Phoenix.ChannelTest.push(socket1, "tournament:join", %{}) - Phoenix.ChannelTest.push(socket2, "tournament:join", %{}) - Phoenix.ChannelTest.push(socket3, "tournament:join", %{}) - Phoenix.ChannelTest.push(socket4, "tournament:join", %{}) - Phoenix.ChannelTest.push(socket5, "tournament:join", %{}) - Phoenix.ChannelTest.push(socket6, "tournament:join", %{}) - - # 7 users joined for 7 user sockets - Enum.each(1..36, fn _i -> - assert_receive %Message{ - event: "tournament:player:joined", - payload: %{ - player: %Tournament.Player{clan_id: _, id: _, name: _, state: "active"}, - tournament: %{players_count: _} - } - } - end) - - {:ok, user_response, socket7} = - subscribe_and_join(socket7, TournamentChannel, tournament_topic) - - assert %{ - # clans: %{ - # ^c1_id => %{id: ^c1_id, name: "c1", long_name: "cl1"}, - # ^c2_id => %{id: ^c2_id, name: "c2", long_name: "cl2"}, - # ^c3_id => %{id: ^c3_id, name: "c3", long_name: "cl3"} - # }, - matches: [], - players: [_p1, _p2, _p3, _p4, _p5, _p6], - ranking: %{ - page_size: 10, - entries: [ - %{id: _, score: 0, players_count: 2, place: 1}, - %{id: _, score: 0, players_count: 2, place: 2}, - %{id: _, score: 0, players_count: 2, place: 3} - ], - page_number: 1, - total_entries: 3 - }, - tournament: %{ - access_type: "public", - type: "arena", - players_count: 6, - state: "waiting_participants", - break_state: "off", - current_round_position: 0 - } - } = user_response - - Phoenix.ChannelTest.push(socket7, "tournament:join", %{}) - - Enum.each(1..7, fn _i -> - assert_receive %Message{ - event: "tournament:player:joined", - payload: %{ - player: %Tournament.Player{clan_id: _, id: _, name: _, state: "active"}, - tournament: %{players_count: _} - } - } - - assert_receive %Message{ - event: "tournament:ranking_update", - payload: %{ranking: %{}, clans: %{}} - } - end) - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - {:ok, admin_join_response, admin_socket} = - subscribe_and_join(admin_socket, TournamentAdminChannel, tournament_admin_topic) - - assert %{ - # clans: %{ - # ^c1_id => %{id: ^c1_id, name: "c1", long_name: "cl1"}, - # ^c2_id => %{id: ^c2_id, name: "c2", long_name: "cl2"}, - # ^c3_id => %{id: ^c3_id, name: "c3", long_name: "cl3"}, - # ^c4_id => %{id: ^c4_id, name: "c4", long_name: "cl4"} - # }, - matches: [], - players: [%{}, %{}, %{}, %{}, %{}, %{}, %{}], - ranking: %{ - page_size: 42, - entries: [ - %{id: _, score: 0, players_count: 2, place: 1}, - %{id: _, score: 0, players_count: 2, place: 2}, - %{id: _, score: 0, players_count: 2, place: 3}, - %{id: _, score: 0, players_count: 1, place: 4} - ], - page_number: 1, - total_entries: 4 - }, - tasks_info: %{}, - tournament: %{ - access_type: "public", - type: "arena", - state: "waiting_participants", - break_state: "off", - current_round_position: 0 - } - } = admin_join_response - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - Phoenix.ChannelTest.push(admin_socket, "tournament:start", %{}) - - :timer.sleep(100) - - Enum.each(1..8, fn _i -> - assert_receive %Message{ - event: "tournament:round_created", - payload: %{ - tournament: %{ - break_state: "off", - current_round_position: 0, - last_round_ended_at: nil, - # todo use time mock - last_round_started_at: _ - } - } - } - end) - - assert_receive %Message{ - event: "waiting_room:player:match_created", - payload: %{ - current_player: %{id: ^u1_id, state: "active"}, - players: [%{state: "active"}, %{state: "active"}], - match: %{game_id: game_id, state: "playing"} - } - } - - Enum.each(1..6, fn _i -> - assert_receive %Message{ - event: "waiting_room:player:match_created", - payload: %{ - current_player: %{state: "active"}, - players: [%{state: "active"}, %{state: "active"}], - match: %{state: "playing"} - } - } - end) - - assert_receive %Message{ - event: "tournament:update", - payload: %{tournament: %{}}, - topic: ^tournament_admin_topic - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - {:ok, _response, socket8} = - subscribe_and_join(socket8, TournamentChannel, tournament_topic) - - Phoenix.ChannelTest.push(socket8, "tournament:join", %{}) - - Enum.each(1..9, fn _i -> - assert_receive %Message{ - event: "tournament:player:joined", - payload: %{ - player: %Tournament.Player{clan_id: _, id: _, name: _, state: "matchmaking_active"}, - tournament: %{players_count: _} - } - } - end) - - assert_receive %Message{ - event: "tournament:ranking_update", - payload: %{ranking: %{}, clans: %{}} - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - game_topic = "game:#{game_id}" - {:ok, _response, socket1} = subscribe_and_join(socket1, GameChannel, game_topic) - - Phoenix.ChannelTest.push(socket1, "check_result", %{ - editor_text: "lol", - lang_slug: "js" - }) - - assert_receive %Broadcast{ - event: "user:start_check", - payload: %{user_id: ^u1_id}, - topic: ^game_topic - } - - assert_receive %Broadcast{ - event: "user:check_complete", - payload: %{user_id: ^u1_id, solution_status: true}, - topic: ^game_topic - } - - assert_receive %Message{ - event: "user:check_complete", - payload: %{user_id: ^u1_id, solution_status: true}, - topic: ^game_topic - } - - assert_receive %Message{ - event: "waiting_room:player:matchmaking_started", - payload: %{ - current_player: %{ - id: ^u1_id, - state: "matchmaking_active", - task_ids: [^t1_id], - score: 3, - place: 0, - wins_count: 1 - } - }, - topic: ^game_topic - } - - Process.unlink(socket1.channel_pid) - ref_1 = leave(socket1) - Phoenix.ChannelTest.assert_reply(ref_1, :ok) - assert_receive {:socket_close, _, {:shutdown, :left}} - - assert_receive %Message{ - event: "waiting_room:player:matchmaking_started", - payload: %{ - current_player: %{ - id: ^u1_id, - state: "matchmaking_active", - task_ids: [^t1_id], - score: 3, - place: 0, - wins_count: 1 - } - }, - topic: ^tournament_topic - } - - assert_receive %Message{ - event: "waiting_room:player:matchmaking_started", - payload: %{ - current_player: %{ - state: "matchmaking_active", - task_ids: [^t1_id], - score: 1, - place: 0, - wins_count: 0 - } - }, - topic: ^tournament_topic - } - - assert_receive %Message{ - event: "tournament:match:upserted", - payload: %{ - players: [%{state: "active"}, %{state: "active"}], - match: %{state: "game_over"} - }, - topic: ^tournament_topic - } - - assert_receive %Message{ - event: "tournament:match:upserted", - payload: %{ - players: [%{state: "active"}, %{state: "active"}], - match: %{state: "game_over"} - }, - topic: ^tournament_topic - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - end -end diff --git a/services/app/apps/codebattle/test/codebattle_web/integration/tournament/swiss_95_percentile_test.exs b/services/app/apps/codebattle/test/codebattle_web/integration/tournament/swiss_95_percentile_test.exs deleted file mode 100644 index 9707ecf8f..000000000 --- a/services/app/apps/codebattle/test/codebattle_web/integration/tournament/swiss_95_percentile_test.exs +++ /dev/null @@ -1,889 +0,0 @@ -defmodule CodebattleWeb.Integration.Tournament.SwissClan95PercentileTest do - use Codebattle.IntegrationCase - - alias Codebattle.Tournament - alias Phoenix.Socket.Broadcast - alias Phoenix.Socket.Message - alias Phoenix.Socket.Reply - - @tag :skip - # TODO: fix flaky test - test "Swiss round sequential 95_percentile task_pack" do - %{id: t1_id} = insert(:task, level: "easy") - %{id: t2_id} = insert(:task, level: "medium") - %{id: t3_id} = insert(:task, level: "hard") - - insert(:task_pack, name: "tp", task_ids: [t1_id, t2_id, t3_id]) - admin = insert(:user, %{name: "a"}) - - {:ok, tournament} = - Tournament.Context.create(%{ - "starts_at" => "2022-02-24T06:00", - "name" => "Test Swiss 95 percentile", - "user_timezone" => "Etc/UTC", - "level" => "easy", - "task_pack_name" => "tp", - "creator" => admin, - "break_duration_seconds" => 0, - "score_strategy" => "win_loss", - "task_provider" => "task_pack", - "task_strategy" => "sequential", - "ranking_type" => "by_player_95th_percentile", - "type" => "swiss", - "state" => "waiting_participants", - "use_clan" => "false", - "rounds_limit" => "3", - "players_limit" => 200 - }) - - tournament_topic = "tournament:#{tournament.id}" - tournament_admin_topic = "tournament_admin:#{tournament.id}" - - # create 8 players for tournament - user1 = %{id: u1_id} = insert(:user, name: "1") - user2 = insert(:user, name: "2") - user3 = insert(:user, name: "3") - user4 = insert(:user, name: "4") - user5 = insert(:user, name: "5") - user6 = insert(:user, name: "6") - user7 = insert(:user, name: "7") - user8 = insert(:user, name: "8") - - admin_socket = socket(UserSocket, "user_id", %{user_id: admin.id, current_user: admin}) - socket1 = socket(UserSocket, "user_id", %{user_id: user1.id, current_user: user1}) - socket2 = socket(UserSocket, "user_id", %{user_id: user2.id, current_user: user2}) - socket3 = socket(UserSocket, "user_id", %{user_id: user3.id, current_user: user3}) - socket4 = socket(UserSocket, "user_id", %{user_id: user4.id, current_user: user4}) - socket5 = socket(UserSocket, "user_id", %{user_id: user5.id, current_user: user5}) - socket6 = socket(UserSocket, "user_id", %{user_id: user6.id, current_user: user6}) - socket7 = socket(UserSocket, "user_id", %{user_id: user7.id, current_user: user7}) - socket8 = socket(UserSocket, "user_id", %{user_id: user8.id, current_user: user8}) - - {:ok, _response, socket1} = subscribe_and_join(socket1, TournamentChannel, tournament_topic) - {:ok, _response, socket2} = subscribe_and_join(socket2, TournamentChannel, tournament_topic) - {:ok, _response, socket3} = subscribe_and_join(socket3, TournamentChannel, tournament_topic) - {:ok, _response, socket4} = subscribe_and_join(socket4, TournamentChannel, tournament_topic) - {:ok, _response, socket5} = subscribe_and_join(socket5, TournamentChannel, tournament_topic) - {:ok, _response, socket6} = subscribe_and_join(socket6, TournamentChannel, tournament_topic) - - Phoenix.ChannelTest.push(socket1, "tournament:join", %{}) - :timer.sleep(10) - Phoenix.ChannelTest.push(socket2, "tournament:join", %{}) - :timer.sleep(10) - Phoenix.ChannelTest.push(socket3, "tournament:join", %{}) - :timer.sleep(10) - Phoenix.ChannelTest.push(socket4, "tournament:join", %{}) - :timer.sleep(10) - Phoenix.ChannelTest.push(socket5, "tournament:join", %{}) - :timer.sleep(10) - Phoenix.ChannelTest.push(socket6, "tournament:join", %{}) - - # all 6 users got notification about joined player - Enum.each(1..36, fn _i -> - assert_receive %Message{ - event: "tournament:player:joined", - payload: %{ - player: %Tournament.Player{clan_id: _, id: _, name: _, state: "active"}, - tournament: %{players_count: _} - } - } - end) - - {:ok, user_response, socket7} = - subscribe_and_join(socket7, TournamentChannel, tournament_topic) - - assert %{ - matches: [], - players: [_p1, _p2, _p3, _p4, _p5, _p6], - ranking: %{ - page_size: 10, - entries: [ - %{id: _, place: 1, score: 0, name: "1"}, - %{id: _, place: 2, score: 0, name: "2"}, - %{id: _, place: 3, score: 0, name: "3"}, - %{id: _, place: 4, score: 0, name: "4"}, - %{id: _, place: 5, score: 0, name: "5"}, - %{id: _, place: 6, score: 0, name: "6"} - ], - page_number: 1, - total_entries: 6 - }, - tournament: %{ - access_type: "public", - type: "swiss", - state: "waiting_participants", - players_count: 6, - break_state: "off", - current_round_position: 0 - } - } = user_response - - Phoenix.ChannelTest.push(socket7, "tournament:join", %{}) - - # 7 users got notification about joined player - Enum.each(1..7, fn _i -> - assert_receive %Message{ - event: "tournament:player:joined", - payload: %{ - player: %Tournament.Player{clan_id: _, id: _, name: _, state: "active"}, - tournament: %{players_count: _} - } - } - - assert_receive %Message{ - event: "tournament:ranking_update", - payload: %{ranking: %{}, clans: %{}} - } - end) - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - # admin join to tournament - {:ok, admin_join_response, admin_socket} = - subscribe_and_join(admin_socket, TournamentAdminChannel, tournament_admin_topic) - - assert %{ - matches: [], - players: [%{}, %{}, %{}, %{}, %{}, %{}, %{}], - ranking: %{ - page_size: 10, - entries: [ - %{id: _, place: 1, score: 0, name: "1"}, - %{id: _, place: 2, score: 0, name: "2"}, - %{id: _, place: 3, score: 0, name: "3"}, - %{id: _, place: 4, score: 0, name: "4"}, - %{id: _, place: 5, score: 0, name: "5"}, - %{id: _, place: 6, score: 0, name: "6"}, - %{id: _, place: 7, score: 0, name: "7"} - ], - page_number: 1, - total_entries: 7 - }, - tasks_info: %{}, - tournament: %{ - access_type: "public", - type: "swiss", - state: "waiting_participants", - break_state: "off", - current_round_position: 0 - } - } = admin_join_response - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - # ---------------- - # Start tournament - # 1 round - # ---------------- - - Phoenix.ChannelTest.push(admin_socket, "tournament:start", %{}) - - :timer.sleep(200) - - # all 7 users and admin got notification about round created - Enum.each(1..8, fn _i -> - assert_receive %Message{ - event: "tournament:round_created", - payload: %{ - tournament: %{ - round_timeout_seconds: 180, - break_state: "off", - current_round_position: 0, - last_round_ended_at: nil, - # todo use time mock - last_round_started_at: _ - } - } - } - end) - - # user1 got notification about match created - assert_receive %Message{ - event: "tournament:match:upserted", - payload: %{ - players: [%{state: "active"}, %{state: "active"}], - match: %{player_ids: [^u1_id, _], game_id: game_id, state: "playing"} - } - } - - # rest users got notification about match created - Enum.each(1..6, fn _i -> - assert_receive %Message{ - event: "tournament:match:upserted", - payload: %{ - players: [%{state: "active"}, %{state: "active"}], - match: %{state: "playing"} - } - } - end) - - # admin got notification about round started and tournament updated - assert_receive %Message{ - event: "tournament:update", - payload: %{tournament: %{}}, - topic: ^tournament_admin_topic - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - # user8 join to tournament - {:ok, _response, socket8} = - subscribe_and_join(socket8, TournamentChannel, tournament_topic) - - Phoenix.ChannelTest.push(socket8, "tournament:join", %{}) - - Enum.each(1..9, fn _i -> - assert_receive %Message{ - event: "tournament:player:joined", - payload: %{ - player: %Tournament.Player{id: _, name: "8", state: "active"}, - tournament: %{players_count: 9} - } - } - end) - - assert_receive %Message{ - event: "tournament:ranking_update", - payload: %{ranking: %{}, clans: %{}} - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - game_topic = "game:#{game_id}" - {:ok, _response, socket1} = subscribe_and_join(socket1, GameChannel, game_topic) - - # user1 win game - Phoenix.ChannelTest.push(socket1, "check_result", %{ - editor_text: "lol", - lang_slug: "js" - }) - - assert_receive %Broadcast{ - event: "user:start_check", - payload: %{user_id: ^u1_id}, - topic: ^game_topic - } - - assert_receive %Broadcast{ - event: "user:check_complete", - payload: %{user_id: ^u1_id, solution_status: true}, - topic: ^game_topic - } - - :timer.sleep(200) - - assert_receive %Message{ - event: "user:check_complete", - payload: %{user_id: ^u1_id, solution_status: true}, - topic: ^game_topic - } - - assert_receive %Message{ - event: "tournament:match:upserted", - payload: %{ - match: %{ - player_ids: [^u1_id, _], - task_id: ^t1_id - } - } - } - - Process.unlink(socket1.channel_pid) - ref_1 = leave(socket1) - Phoenix.ChannelTest.assert_reply(ref_1, :ok) - assert_receive {:socket_close, _, {:shutdown, :left}} - - assert_receive %Message{ - event: "tournament:match:upserted", - payload: %{ - players: [%{state: "active"}, %{state: "active"}], - match: %{state: "game_over"} - }, - topic: ^tournament_topic - } - - # user1 received wait for next round message - assert_receive %Message{ - event: "tournament:game:wait", - payload: %{type: "round"}, - topic: ^game_topic - } - - :timer.sleep(200) - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - # ---------------- - # somebody leave - # ---------------- - # - Phoenix.ChannelTest.push(socket6, "tournament:leave", %{}) - - :timer.sleep(200) - left_id = user6.id - - Enum.each(1..10, fn _i -> - assert_receive %Message{ - event: "tournament:player:left", - payload: %{ - player_id: ^left_id, - tournament: %{players_count: 8} - } - } - end) - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - # ---------------- - # finish 1 round - # start 2 round - # ---------------- - - Phoenix.ChannelTest.push(admin_socket, "tournament:finish_round", %{}) - - :timer.sleep(200) - - # 4 players got match timeout notification - Enum.each(1..3, fn _i -> - assert_receive %Message{ - event: "tournament:match:upserted", - payload: %{ - players: [%{state: "active"}, %{state: "active"}], - match: %{state: "timeout", task_id: ^t1_id} - } - } - end) - - # event without left_player - assert_receive %Message{ - event: "tournament:match:upserted", - payload: %{ - players: [%{state: "active"}], - match: %{state: "timeout", task_id: ^t1_id} - } - } - - # 8 users got notification about round finished - Enum.each(1..8, fn _i -> - assert_receive %Message{ - event: "tournament:round_finished", - payload: %{ - tournament: %{ - state: "active", - break_state: "on", - current_round_position: 0 - } - }, - topic: ^tournament_topic - } - end) - - # admin got notification round finished - assert_receive %Message{ - event: "tournament:round_finished", - payload: %{ - tournament: %{ - state: "active", - break_state: "on", - current_round_position: 0 - } - }, - topic: ^tournament_admin_topic - } - - # admin got notification tournament updated - assert_receive %Message{ - event: "tournament:update", - payload: %{tournament: %{}}, - topic: ^tournament_admin_topic - } - - # 8 users got notification about round created - Enum.each(1..8, fn _i -> - assert_receive %Message{ - event: "tournament:round_created", - payload: %{ - tournament: %{ - state: "active", - break_state: "off", - current_round_position: 1 - } - }, - topic: ^tournament_topic - } - end) - - # admin got notification round created - assert_receive %Message{ - event: "tournament:round_created", - payload: %{ - tournament: %{ - state: "active", - break_state: "off", - current_round_position: 1 - } - }, - topic: ^tournament_admin_topic - } - - # admin got notification tournament updated - assert_receive %Message{ - event: "tournament:update", - payload: %{tournament: %{}}, - topic: ^tournament_admin_topic - } - - :timer.sleep(200) - # 8 players got notification about new match - assert_receive %Message{ - event: "tournament:match:upserted", - payload: %{ - players: [%{id: ^u1_id, state: "active"}, %{state: "active"}], - match: %{game_id: game_id, state: "playing", task_id: ^t2_id} - } - } - - Enum.each(1..6, fn _i -> - assert_receive %Message{ - event: "tournament:match:upserted", - payload: %{ - players: [%{state: "active"}, %{state: "active"}], - match: %{state: "playing", task_id: ^t2_id} - } - } - end) - - # admin got notification tournament updated - assert_receive %Message{ - event: "tournament:update", - payload: %{tournament: %{}}, - topic: ^tournament_admin_topic - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - # ---------------- - # Check ranking - # ---------------- - - Phoenix.ChannelTest.push(admin_socket, "tournament:ranking:request", %{}) - - assert_receive %Reply{ - payload: %{ - ranking: %{ - entries: [ - %{id: _, score: 100, user_name: "1", place: 1}, - _player2, - _player3, - _player4, - _player5, - _player6, - _player7, - _player8 - ], - page_number: 1, - page_size: 10, - total_entries: 8 - } - } - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - ### finish game in the 2 round - game_topic = "game:#{game_id}" - {:ok, _response, socket1} = subscribe_and_join(socket1, GameChannel, game_topic) - - # user1 win game - Phoenix.ChannelTest.push(socket1, "check_result", %{ - editor_text: "lol", - lang_slug: "js" - }) - - assert_receive %Broadcast{ - event: "user:start_check", - payload: %{user_id: ^u1_id}, - topic: ^game_topic - } - - assert_receive %Broadcast{ - event: "user:check_complete", - payload: %{user_id: ^u1_id, solution_status: true}, - topic: ^game_topic - } - - assert_receive %Message{ - event: "user:check_complete", - payload: %{user_id: ^u1_id, solution_status: true}, - topic: ^game_topic - } - - assert_receive %Message{ - event: "tournament:match:upserted", - payload: %{ - match: %{ - player_ids: [^u1_id, _], - task_id: ^t2_id - } - } - } - - Process.unlink(socket1.channel_pid) - ref_1 = leave(socket1) - Phoenix.ChannelTest.assert_reply(ref_1, :ok) - assert_receive {:socket_close, _, {:shutdown, :left}} - - assert_receive %Message{ - event: "tournament:match:upserted", - payload: %{ - players: [%{state: "active"}, %{state: "active"}], - match: %{state: "game_over"} - }, - topic: ^tournament_topic - } - - # user1 received wait for next round message - assert_receive %Message{ - event: "tournament:game:wait", - payload: %{type: "round"}, - topic: ^game_topic - } - - :timer.sleep(200) - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - # ---------------- - # finish 2 round - # start 3 round - # ---------------- - - Phoenix.ChannelTest.push(admin_socket, "tournament:finish_round", %{}) - - :timer.sleep(200) - - # 5 players got match timeout notification - Enum.each(1..5, fn _i -> - assert_receive %Message{ - event: "tournament:match:upserted", - payload: %{ - players: [%{state: "active"}, %{state: "active"}], - match: %{state: "timeout", task_id: ^t2_id} - } - } - end) - - # 8 users got notification about round finished - Enum.each(1..8, fn _i -> - assert_receive %Message{ - event: "tournament:round_finished", - payload: %{ - tournament: %{ - state: "active", - break_state: "on", - current_round_position: 1 - } - }, - topic: ^tournament_topic - } - end) - - # admin got notification round finished - assert_receive %Message{ - event: "tournament:round_finished", - payload: %{ - tournament: %{ - state: "active", - break_state: "on", - current_round_position: 1 - } - }, - topic: ^tournament_admin_topic - } - - # admin got notification tournament updated - assert_receive %Message{ - event: "tournament:update", - payload: %{tournament: %{}}, - topic: ^tournament_admin_topic - } - - # 8 users got notification about round created - Enum.each(1..8, fn _i -> - assert_receive %Message{ - event: "tournament:round_created", - payload: %{ - tournament: %{ - state: "active", - break_state: "off", - current_round_position: 2 - } - }, - topic: ^tournament_topic - } - end) - - # admin got notification round created - assert_receive %Message{ - event: "tournament:round_created", - payload: %{ - tournament: %{ - state: "active", - break_state: "off", - current_round_position: 2 - } - }, - topic: ^tournament_admin_topic - } - - # admin got notification tournament updated - assert_receive %Message{ - event: "tournament:update", - payload: %{tournament: %{}}, - topic: ^tournament_admin_topic - } - - # 8 players got notification about new match - assert_receive %Message{ - event: "tournament:match:upserted", - payload: %{ - players: [%{id: ^u1_id, state: "active"}, %{state: "active"}], - match: %{game_id: game_id, state: "playing", task_id: ^t3_id} - } - } - - Enum.each(1..6, fn _i -> - assert_receive %Message{ - event: "tournament:match:upserted", - payload: %{ - players: [%{state: "active"}, %{state: "active"}], - match: %{state: "playing", task_id: ^t3_id} - } - } - end) - - # admin got notification tournament updated - assert_receive %Message{ - event: "tournament:update", - payload: %{tournament: %{}}, - topic: ^tournament_admin_topic - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - # ---------------- - # Check ranking - # ---------------- - - Phoenix.ChannelTest.push(admin_socket, "tournament:ranking:request", %{}) - - assert_receive %Reply{ - payload: %{ - ranking: %{ - entries: [ - %{id: _, score: 400, user_name: "1", place: 1}, - _player2, - _player3, - _player4, - _player5, - _player6, - _player7, - _player8, - _bot - ], - page_number: 1, - page_size: 10, - total_entries: 9 - } - } - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - ### finish game in the 3 round - game_topic = "game:#{game_id}" - {:ok, _response, socket1} = subscribe_and_join(socket1, GameChannel, game_topic) - - # user1 win game - Phoenix.ChannelTest.push(socket1, "check_result", %{ - editor_text: "lol", - lang_slug: "js" - }) - - assert_receive %Broadcast{ - event: "user:start_check", - payload: %{user_id: ^u1_id}, - topic: ^game_topic - } - - :timer.sleep(200) - - assert_receive %Broadcast{ - event: "user:check_complete", - payload: %{user_id: ^u1_id, solution_status: true}, - topic: ^game_topic - } - - assert_receive %Message{ - event: "user:check_complete", - payload: %{user_id: ^u1_id, solution_status: true}, - topic: ^game_topic - } - - assert_receive %Message{ - event: "tournament:match:upserted", - payload: %{ - match: %{ - player_ids: [^u1_id, _], - task_id: ^t3_id - } - } - } - - Process.unlink(socket1.channel_pid) - ref_1 = leave(socket1) - Phoenix.ChannelTest.assert_reply(ref_1, :ok) - assert_receive {:socket_close, _, {:shutdown, :left}} - - assert_receive %Message{ - event: "tournament:match:upserted", - payload: %{ - players: [%{state: "active"}, %{state: "active"}], - match: %{state: "game_over"} - }, - topic: ^tournament_topic - } - - # user1 received wait for next round message - assert_receive %Message{ - event: "tournament:game:wait", - payload: %{type: "tournament"}, - topic: ^game_topic - } - - :timer.sleep(200) - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - # ---------------- - # finish 3 round - # Tournament finished - # ---------------- - - Phoenix.ChannelTest.push(admin_socket, "tournament:finish_round", %{}) - - :timer.sleep(200) - - # 5 players got match timeout notification - Enum.each(1..5, fn _i -> - assert_receive %Message{ - event: "tournament:match:upserted", - payload: %{ - players: [%{state: "active"}, %{state: "active"}], - match: %{state: "timeout", task_id: ^t3_id} - } - } - end) - - # 8 users got notification about round finished - Enum.each(1..8, fn _i -> - assert_receive %Message{ - event: "tournament:round_finished", - payload: %{ - tournament: %{ - state: "active", - break_state: "on", - current_round_position: 2 - } - }, - topic: ^tournament_topic - } - end) - - # admin got notification round finished - assert_receive %Message{ - event: "tournament:round_finished", - payload: %{ - tournament: %{ - state: "active", - break_state: "on", - current_round_position: 2 - } - }, - topic: ^tournament_admin_topic - } - - # admin got notification tournament updated - assert_receive %Message{ - event: "tournament:update", - payload: %{tournament: %{}}, - topic: ^tournament_admin_topic - } - - # 8 users got notification about tournament finished - Enum.each(1..8, fn _i -> - assert_receive %Message{ - event: "tournament:finished", - payload: %{ - tournament: %{ - state: "finished", - break_state: "off", - current_round_position: 2 - } - }, - topic: ^tournament_topic - } - end) - - # admin got notification tournament finished - assert_receive %Message{ - event: "tournament:finished", - payload: %{ - tournament: %{ - state: "finished", - break_state: "off", - current_round_position: 2 - } - }, - topic: ^tournament_admin_topic - } - - # admin got notification tournament updated - assert_receive %Message{ - event: "tournament:update", - payload: %{tournament: %{}}, - topic: ^tournament_admin_topic - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - - # ---------------- - # Check ranking - # ---------------- - - Phoenix.ChannelTest.push(admin_socket, "tournament:ranking:request", %{}) - - assert_receive %Reply{ - payload: %{ - ranking: %{ - entries: [ - %{id: _, score: 1400, user_name: "1", place: 1}, - _player2, - _player3, - _player4, - _player5, - _player6, - _player7, - _player8, - _bot - ], - page_number: 1, - page_size: 10, - total_entries: 9 - } - } - } - - assert Process.info(self(), :message_queue_len) == {:message_queue_len, 0} - end -end diff --git a/services/app/apps/codebattle/test/codebattle_web/plugs/assign_current_user_test.exs b/services/app/apps/codebattle/test/codebattle_web/plugs/assign_current_user_test.exs deleted file mode 100644 index 82d9656cd..000000000 --- a/services/app/apps/codebattle/test/codebattle_web/plugs/assign_current_user_test.exs +++ /dev/null @@ -1,13 +0,0 @@ -defmodule CodebattleWeb.Plugs.AssignCurrentUserTest do - use CodebattleWeb.ConnCase, async: true - - test "clear session if user have id in session, but doesn't have db record", %{conn: conn} do - conn = - conn - |> put_session(:user_id, 1_000_000) - |> get(Routes.root_path(conn, :index)) - - assert conn.status == 302 - assert get_session(conn, :user_id) == nil - end -end diff --git a/services/app/apps/codebattle/test/docker_execution/haskell_test.exs b/services/app/apps/codebattle/test/docker_execution/haskell_test.exs deleted file mode 100644 index 6830fc177..000000000 --- a/services/app/apps/codebattle/test/docker_execution/haskell_test.exs +++ /dev/null @@ -1,109 +0,0 @@ -defmodule Codebattle.DockerExecution.HaskellTest do - use Codebattle.IntegrationCase - - alias Codebattle.CodeCheck.Result - alias Codebattle.Game - alias CodebattleWeb.GameChannel - alias CodebattleWeb.UserSocket - alias Phoenix.Socket.Broadcast - - setup do - user1 = insert(:user) - user2 = insert(:user) - task = insert(:task) - socket1 = socket(UserSocket, "user_id", %{user_id: user1.id, current_user: user1}) - socket2 = socket(UserSocket, "user_id", %{user_id: user2.id, current_user: user2}) - game_params = %{state: "playing", players: [user1, user2], task: task} - - {:ok, %{game_params: game_params, socket1: socket1, socket2: socket2}} - end - - @tag :docker_executor - test "failure code, game playing", %{ - game_params: game_params, - socket1: socket1, - socket2: socket2 - } do - {:ok, game} = Game.Context.create_game(game_params) - game_topic = "game:" <> to_string(game.id) - - {:ok, _response, socket1} = subscribe_and_join(socket1, GameChannel, game_topic) - {:ok, _response, _socket2} = subscribe_and_join(socket2, GameChannel, game_topic) - Mix.Shell.Process.flush() - - Phoenix.ChannelTest.push(socket1, "check_result", %{ - editor_text: "module Check.Solution where\n\nsolution :: Int -> Int -> Int\nsolution x y = x - y", - lang_slug: "haskell" - }) - - assert_code_check() - - assert_receive %Broadcast{ - payload: %{check_result: check_result} - } - - assert %Result{status: "failure", success_count: 0} = check_result - - game = Game.Context.get_game!(game.id) - - assert game.state == "playing" - end - - @tag :docker_executor - test "error code, game playing", %{ - game_params: game_params, - socket1: socket1, - socket2: socket2 - } do - {:ok, game} = Game.Context.create_game(game_params) - game_topic = "game:" <> to_string(game.id) - - {:ok, _response, socket1} = subscribe_and_join(socket1, GameChannel, game_topic) - {:ok, _response, _socket2} = subscribe_and_join(socket2, GameChannel, game_topic) - Mix.Shell.Process.flush() - - Phoenix.ChannelTest.push(socket1, "check_result", %{editor_text: "sdf", lang_slug: "haskell"}) - - assert_code_check() - - assert_receive %Broadcast{ - payload: %{check_result: check_result} - } - - assert %Result{status: "error", success_count: 0} = check_result - - game = Game.Context.get_game!(game.id) - - assert game.state == "playing" - end - - @tag :docker_executor - test "good code, player won", %{ - game_params: game_params, - socket1: socket1, - socket2: socket2 - } do - {:ok, game} = Game.Context.create_game(game_params) - game_topic = "game:" <> to_string(game.id) - - {:ok, _response, socket1} = subscribe_and_join(socket1, GameChannel, game_topic) - {:ok, _response, _socket2} = subscribe_and_join(socket2, GameChannel, game_topic) - Mix.Shell.Process.flush() - - Phoenix.ChannelTest.push(socket1, "editor:data", %{editor_text: "test", lang_slug: "js"}) - - Phoenix.ChannelTest.push(socket1, "check_result", %{ - editor_text: "module Check.Solution where\n\nsolution :: Int -> Int -> Int\nsolution x y = x + y", - lang_slug: "haskell" - }) - - assert_code_check() - - assert_receive %Broadcast{ - payload: %{solution_status: true, state: "game_over"} - } - - game = Game.Context.get_game!(game.id) - assert game.state == "game_over" - end -end diff --git a/services/app/apps/codebattle/test/support/conn_case.ex b/services/app/apps/codebattle/test/support/conn_case.ex deleted file mode 100644 index e96c83945..000000000 --- a/services/app/apps/codebattle/test/support/conn_case.ex +++ /dev/null @@ -1,56 +0,0 @@ -defmodule CodebattleWeb.ConnCase do - @moduledoc """ - This module defines the test case to be used by - tests that require setting up a connection. - - Such tests rely on `Phoenix.ConnTest` and also - import other functionality to make it easier - to build and query models. - - Finally, if the test case interacts with the database, - it cannot be async. For this reason, every test runs - inside a transaction which is reset at the beginning - of the test unless the test case is marked as async. - """ - - use ExUnit.CaseTemplate - - @session Plug.Session.init( - store: :cookie, - key: "_app", - encryption_salt: "yadayada", - signing_salt: "yadayada" - ) - - using do - quote do - import Codebattle.OauthTestHelpers - import CodebattleWeb.Factory - import Phoenix.ConnTest - import Phoenix.LiveViewTest - # Import conveniences for testing with connections - import Plug.Conn - - alias Codebattle.Game - alias Codebattle.Game.Player - alias Codebattle.Repo - alias Codebattle.User - alias Codebattle.UserGame - alias CodebattleWeb.Router.Helpers, as: Routes - - # The default endpoint for testing - @endpoint CodebattleWeb.Endpoint - end - end - - setup tags do - Codebattle.DataCase.setup_sandbox(tags) - - conn = - Phoenix.ConnTest.build_conn() - |> Plug.Session.call(@session) - |> Plug.Conn.fetch_session() - - {:ok, conn: conn} - end -end diff --git a/services/app/apps/codebattle/test/support/data_case.ex b/services/app/apps/codebattle/test/support/data_case.ex deleted file mode 100644 index 95ca2df9f..000000000 --- a/services/app/apps/codebattle/test/support/data_case.ex +++ /dev/null @@ -1,35 +0,0 @@ -defmodule Codebattle.DataCase do - @moduledoc false - use ExUnit.CaseTemplate - - alias Codebattle.Repo - alias Ecto.Adapters.SQL.Sandbox - - using do - quote do - import Codebattle.DataCase - import CodebattleWeb.Factory - import Ecto - import Ecto.Changeset - import Ecto.Query - - alias Codebattle.Game - alias Codebattle.Repo - alias Codebattle.User - alias Codebattle.UserGame - end - end - - setup tags do - setup_sandbox(tags) - :ok - end - - @doc """ - Sets up the sandbox based on the test tags. - """ - def setup_sandbox(tags) do - pid = Sandbox.start_owner!(Repo, shared: not tags[:async]) - on_exit(fn -> Sandbox.stop_owner(pid) end) - end -end diff --git a/services/app/apps/codebattle/test/support/oauth_helpers.ex b/services/app/apps/codebattle/test/support/oauth_helpers.ex deleted file mode 100644 index 0d325a087..000000000 --- a/services/app/apps/codebattle/test/support/oauth_helpers.ex +++ /dev/null @@ -1,53 +0,0 @@ -defmodule Codebattle.OauthTestHelpers do - @moduledoc false - @valid_github_body %{ - "access_token" => "12345", - "login" => "test_user", - "name" => "Testy McTestface", - "email" => "test@gmail.com", - "avatar_url" => "https://avatars3.githubusercontent.com/u/10835816", - "id" => "19" - } - - @valid_discord_body %{ - "accent_color" => nil, - "avatar" => "12345", - "avatar_decoration" => nil, - "banner" => nil, - "banner_color" => nil, - "discriminator" => "0123", - "display_name" => nil, - "email" => "lol@kek.com", - "flags" => 0, - "id" => "1234567", - "locale" => "ab", - "premium_type" => 0, - "public_flags" => 0, - "username" => "test_name", - "verified" => true - } - - def stub_github_oauth_requests do - Req.Test.stub(Codebattle.Auth, fn req -> - case req do - %{request_path: "/login/oauth/access_token", method: "POST", host: "github.com"} -> - Req.Test.text(req, URI.encode_query(@valid_github_body)) - - %{request_path: "/user", method: "GET", host: "api.github.com"} -> - Req.Test.json(req, @valid_github_body) - end - end) - end - - def stub_discord_oauth_requests do - Req.Test.stub(Codebattle.Auth, fn req -> - case req do - %{request_path: "/api/v10/oauth2/token", method: "POST", host: "discord.com"} -> - Req.Test.text(req, URI.encode_query(%{access_token: "asfd"})) - - %{request_path: "/api/users/@me", method: "GET", host: "discord.com"} -> - Req.Test.json(req, @valid_discord_body) - end - end) - end -end diff --git a/services/app/apps/codebattle/test/support/tournament_test_helpers.ex b/services/app/apps/codebattle/test/support/tournament_test_helpers.ex deleted file mode 100644 index 4f0b4f6bb..000000000 --- a/services/app/apps/codebattle/test/support/tournament_test_helpers.ex +++ /dev/null @@ -1,37 +0,0 @@ -defmodule Codebattle.TournamentTestHelpers do - @moduledoc false - import Codebattle.Tournament.Helpers - - def win_active_match(tournament, user, params \\ %{opponent_percent: 0}) do - match = - tournament - |> get_matches("playing") - |> Enum.find(fn m -> user.id in m.player_ids end) - - %{game_id: game_id, player_ids: player_ids} = match - - opponen_id = player_ids |> Enum.reject(&(&1 == user.id)) |> hd() - - check_game(game_id, opponen_id, params.opponent_percent) - check_game(game_id, user.id, 100) - end - - def tournament_admin_topic(tournament_id) do - "tournament:#{tournament_id}" - end - - def tournament_common_topic(tournament_id) do - "tournament:#{tournament_id}:common" - end - - def tournament_player_topic(tournament_id, player_id) do - "tournament:#{tournament_id}:player:#{player_id}" - end - - def check_game(_game_id, _user_id, 0), do: :noop - - def check_game(game_id, user_id, percent) do - params = %{user: %{id: user_id}, editor_text: "solve_percent_#{percent}", editor_lang: "js"} - Codebattle.Game.Context.check_result(game_id, params) - end -end diff --git a/services/app/apps/codebattle/test/test_helper.exs b/services/app/apps/codebattle/test/test_helper.exs deleted file mode 100644 index 1499f94cc..000000000 --- a/services/app/apps/codebattle/test/test_helper.exs +++ /dev/null @@ -1,4 +0,0 @@ -{:ok, _} = Application.ensure_all_started(:fun_with_flags) -ExUnit.start(timeout: 99_999_999) -ExUnit.configure(timeout: :infinity, exclude: [pending: true], trace: false) -Ecto.Adapters.SQL.Sandbox.mode(Codebattle.Repo, :manual) diff --git a/services/app/apps/codebattle/test/views/layout_view_test.exs b/services/app/apps/codebattle/test/views/layout_view_test.exs deleted file mode 100644 index 371a74ca4..000000000 --- a/services/app/apps/codebattle/test/views/layout_view_test.exs +++ /dev/null @@ -1,3 +0,0 @@ -defmodule Codebattle.LayoutViewTest do - use CodebattleWeb.ConnCase, async: true -end diff --git a/services/app/apps/codebattle/webpack/webpack.base.config.js b/services/app/apps/codebattle/webpack/webpack.base.config.js deleted file mode 100644 index 7d9cae0d5..000000000 --- a/services/app/apps/codebattle/webpack/webpack.base.config.js +++ /dev/null @@ -1,142 +0,0 @@ -const path = require("path"); - -const CopyWebpackPlugin = require("copy-webpack-plugin"); -const MiniCssExtractPlugin = require("mini-css-extract-plugin"); -const MonacoWebpackPlugin = require("monaco-editor-webpack-plugin"); -const webpack = require("webpack"); - -// const env = process.env.NODE_ENV || 'development'; -// const isProd = env === 'production'; - -function recursiveIssuer(m) { - if (m.issuer) { - return recursiveIssuer(m.issuer); - } - - if (m.name) { - return m.name; - } - - return false; -} - -module.exports = { - target: "browserslist", - entry: { - app: ["./assets/js/app.js", "./assets/css/style.scss"], - landing: ["./assets/js/landing.js", "./assets/css/landing.scss"], - external: ["./assets/js/external.js", "./assets/css/external.scss"], - }, - output: { - path: path.resolve(__dirname, "../priv/static/assets"), - filename: "[name].js", - sourceMapFilename: "[name].js.map", - chunkFilename: "[id].[contenthash].js", - publicPath: "/assets/", - clean: true, - }, - externals: { - gon: "Gon", - }, - module: { - rules: [ - { - test: /\.po$/, - loader: "i18next-po-loader", - }, - { - test: /\.(js|jsx)$/, - exclude: /node_modules/, - use: { - loader: "babel-loader", - }, - }, - { - test: /\.(sa|sc|c)ss$/, - use: [ - { loader: MiniCssExtractPlugin.loader }, - { loader: "css-loader" }, - { loader: "sass-loader" }, - ], - }, - // { - // test: /\.(eot|svg|ttf|woff|woff2)$/, - // type: 'asset/inline', - // }, - { - test: /\.(png|jpg|gif|ttf|otf|svg|woff)$/, - type: "asset/resource", - generator: { - filename: "[name].[ext]", - }, - }, - ], - }, - optimization: { - splitChunks: { - cacheGroups: { - appStyles: { - name: "app", - test: (m, _, entry = "app") => - m.constructor.name === "CssModule" && recursiveIssuer(m) === entry, - chunks: "all", - enforce: true, - }, - landingStyles: { - name: "landing", - test: (m, _, entry = "landing") => - m.constructor.name === "CssModule" && recursiveIssuer(m) === entry, - chunks: "all", - enforce: true, - }, - }, - }, - }, - plugins: [ - new MonacoWebpackPlugin(), - new webpack.ProvidePlugin({ - process: "process/browser", - }), - new CopyWebpackPlugin({ - patterns: [{ from: "assets/static" }], - }), - new webpack.ProvidePlugin({ - $: "jquery", - jQuery: "jquery", - "window.jQuery": "jquery", - Popper: ["popper.js", "default"], - }), - new MiniCssExtractPlugin({ - filename: "[name].css", - }), - new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /(en|ru)$/), - ], - watchOptions: { - aggregateTimeout: 300, - poll: 1000, - }, - resolve: { - alias: { - "./defineProperty": "@babel/runtime/helpers/esm/defineProperty", - "@/": path.resolve(__dirname, "../assets/js/widgets"), - "@/components": path.resolve( - __dirname, - "../assets/js/widgets/components", - ), - "@/lib": path.resolve(__dirname, "../assets/js/widgets/lib"), - "@/machines": path.resolve(__dirname, "../assets/js/widgets/machines"), - "@/middlewares": path.resolve( - __dirname, - "../assets/js/widgets/middlewares", - ), - "@/pages": path.resolve(__dirname, "../assets/js/widgets/pages"), - "@/selectors": path.resolve(__dirname, "../assets/js/widgets/selectors"), - "@/slices": path.resolve(__dirname, "../assets/js/widgets/slices"), - "@/utils": path.resolve(__dirname, "../assets/js/widgets/utils"), - }, - fallback: { - path: require.resolve("path-browserify"), - }, - extensions: [".js", ".jsx"], - }, -}; diff --git a/services/app/apps/codebattle/webpack/webpack.build.config.js b/services/app/apps/codebattle/webpack/webpack.build.config.js deleted file mode 100644 index 375b6ad49..000000000 --- a/services/app/apps/codebattle/webpack/webpack.build.config.js +++ /dev/null @@ -1,22 +0,0 @@ -const CssMinimizerPlugin = require('css-minimizer-webpack-plugin'); -const TerserPlugin = require('terser-webpack-plugin'); -const { merge } = require('webpack-merge'); - -const baseWebpackConfig = require('./webpack.base.config'); - -const buildWebpackConfig = merge(baseWebpackConfig, { - mode: 'production', - optimization: { - minimize: true, - minimizer: [ - new TerserPlugin(), // minimize JS code - new CssMinimizerPlugin({ - test: /\.css$/i, // specify which files to minimize - }), - ], - }, -}); - -module.exports = new Promise(resolve => { - resolve(buildWebpackConfig); -}); diff --git a/services/app/apps/codebattle/webpack/webpack.dev.config.js b/services/app/apps/codebattle/webpack/webpack.dev.config.js deleted file mode 100644 index 7e8a20799..000000000 --- a/services/app/apps/codebattle/webpack/webpack.dev.config.js +++ /dev/null @@ -1,58 +0,0 @@ -const ReactRefreshWebpackPlugin = require("@pmmmwh/react-refresh-webpack-plugin"); -const webpack = require("webpack"); -// const { WebpackPluginServe } = require('webpack-plugin-serve'); -const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer"); -const { merge } = require("webpack-merge"); - -const baseWebpackConfig = require("./webpack.base.config"); - -const devWebpackConfig = merge(baseWebpackConfig, { - mode: "development", - devtool: "eval-cheap-module-source-map", - devServer: { - host: "0.0.0.0", // allows external connections - port: 8080, // Choose your preferred port - headers: { - "Access-Control-Allow-Origin": "*", - }, - static: { - directory: "/assets", - }, - devMiddleware: { - writeToDisk: true, - }, - hot: true, - compress: true, - // publicPath: '/assets' - // overlay: { - // warnings: true, - // errors: true, - // }, - }, - // module: { - // rules: [ - // { - // test: /\.(js|jsx)$/, - // exclude: /node_modules/, - // use: { - // loader: 'babel-loader', - // options: { - // plugins: ['react-refresh/babel'], - // }, - // }, - // }, - // ], - // }, - plugins: [ - new webpack.SourceMapDevToolPlugin({ - filename: "[file].map", - }), - new webpack.HotModuleReplacementPlugin(), - new ReactRefreshWebpackPlugin(), - // new BundleAnalyzerPlugin(), - ], -}); - -module.exports = new Promise((resolve) => { - resolve(devWebpackConfig); -}); diff --git a/services/app/apps/codebattle/yarn.lock b/services/app/apps/codebattle/yarn.lock deleted file mode 100644 index f18e09339..000000000 --- a/services/app/apps/codebattle/yarn.lock +++ /dev/null @@ -1,13718 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@adobe/css-tools@^4.0.1": - version "4.3.2" - resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.3.2.tgz#a6abc715fb6884851fca9dad37fc34739a04fd11" - integrity sha512-DA5a1C0gD/pLOvhv33YMrbf2FK3oUzwNl9oOJqE4XVjuEtt6XIakRcsd7eLiOSPkp1kTRQGICTA8cKra/vFbjw== - -"@ampproject/remapping@^2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d" - integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w== - dependencies: - "@jridgewell/gen-mapping" "^0.1.0" - "@jridgewell/trace-mapping" "^0.3.9" - -"@babel/cli@^7.21.0": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.21.0.tgz#1868eb70e9824b427fc607610cce8e9e7889e7e1" - integrity sha512-xi7CxyS8XjSyiwUGCfwf+brtJxjW1/ZTcBUkP10xawIEXLX5HzLn+3aXkgxozcP2UhRhtKTmQurw9Uaes7jZrA== - dependencies: - "@jridgewell/trace-mapping" "^0.3.17" - commander "^4.0.1" - convert-source-map "^1.1.0" - fs-readdir-recursive "^1.1.0" - glob "^7.2.0" - make-dir "^2.1.0" - slash "^2.0.0" - optionalDependencies: - "@nicolo-ribaudo/chokidar-2" "2.1.8-no-fsevents.3" - chokidar "^3.4.0" - -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz" - integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg== - dependencies: - "@babel/highlight" "^7.10.4" - -"@babel/code-frame@^7.14.5": - version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.23.5.tgz#9009b69a8c602293476ad598ff53e4562e15c244" - integrity sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA== - dependencies: - "@babel/highlight" "^7.23.4" - chalk "^2.4.2" - -"@babel/code-frame@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" - integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== - dependencies: - "@babel/highlight" "^7.18.6" - -"@babel/code-frame@^7.22.10", "@babel/code-frame@^7.22.5": - version "7.22.10" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.10.tgz#1c20e612b768fefa75f6e90d6ecb86329247f0a3" - integrity sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA== - dependencies: - "@babel/highlight" "^7.22.10" - chalk "^2.4.2" - -"@babel/code-frame@^7.22.13": - version "7.22.13" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.13.tgz#e3c1c099402598483b7a8c46a721d1038803755e" - integrity sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w== - dependencies: - "@babel/highlight" "^7.22.13" - chalk "^2.4.2" - -"@babel/compat-data@^7.17.7", "@babel/compat-data@^7.20.1", "@babel/compat-data@^7.20.5": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.21.0.tgz#c241dc454e5b5917e40d37e525e2f4530c399298" - integrity sha512-gMuZsmsgxk/ENC3O/fRw5QY8A9/uxQbbCEypnLIiYYc/qVJtEV7ouxC3EllIIwNzMqAQee5tanFabWsUOutS7g== - -"@babel/compat-data@^7.22.9": - version "7.22.9" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.22.9.tgz#71cdb00a1ce3a329ce4cbec3a44f9fef35669730" - integrity sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ== - -"@babel/core@^7.1.0", "@babel/core@^7.7.5": - version "7.10.5" - resolved "https://registry.npmjs.org/@babel/core/-/core-7.10.5.tgz" - integrity sha512-O34LQooYVDXPl7QWCdW9p4NR+QlzOr7xShPPJz8GsuCU3/8ua/wqTr7gmnxXv+WBESiGU/G5s16i6tUvHkNb+w== - dependencies: - "@babel/code-frame" "^7.10.4" - "@babel/generator" "^7.10.5" - "@babel/helper-module-transforms" "^7.10.5" - "@babel/helpers" "^7.10.4" - "@babel/parser" "^7.10.5" - "@babel/template" "^7.10.4" - "@babel/traverse" "^7.10.5" - "@babel/types" "^7.10.5" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.1" - json5 "^2.1.2" - lodash "^4.17.19" - resolve "^1.3.2" - semver "^5.4.1" - source-map "^0.5.0" - -"@babel/core@^7.11.6", "@babel/core@^7.12.3": - version "7.22.10" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.22.10.tgz#aad442c7bcd1582252cb4576747ace35bc122f35" - integrity sha512-fTmqbbUBAwCcre6zPzNngvsI0aNrPZe77AeqvDxWM9Nm+04RrJ3CAmGHA9f7lJQY6ZMhRztNemy4uslDxTX4Qw== - dependencies: - "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.22.10" - "@babel/generator" "^7.22.10" - "@babel/helper-compilation-targets" "^7.22.10" - "@babel/helper-module-transforms" "^7.22.9" - "@babel/helpers" "^7.22.10" - "@babel/parser" "^7.22.10" - "@babel/template" "^7.22.5" - "@babel/traverse" "^7.22.10" - "@babel/types" "^7.22.10" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.2.2" - semver "^6.3.1" - -"@babel/core@^7.21.0": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.21.0.tgz#1341aefdcc14ccc7553fcc688dd8986a2daffc13" - integrity sha512-PuxUbxcW6ZYe656yL3EAhpy7qXKq0DmYsrJLpbB8XrsCP9Nm+XCg9XFMb5vIDliPD7+U/+M+QJlH17XOcB7eXA== - dependencies: - "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.18.6" - "@babel/generator" "^7.21.0" - "@babel/helper-compilation-targets" "^7.20.7" - "@babel/helper-module-transforms" "^7.21.0" - "@babel/helpers" "^7.21.0" - "@babel/parser" "^7.21.0" - "@babel/template" "^7.20.7" - "@babel/traverse" "^7.21.0" - "@babel/types" "^7.21.0" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.2.2" - semver "^6.3.0" - -"@babel/eslint-parser@^7.22.10": - version "7.22.10" - resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.22.10.tgz#bfdf3d1b32ad573fe7c1c3447e0b485e3a41fd09" - integrity sha512-0J8DNPRXQRLeR9rPaUMM3fA+RbixjnVLe/MRMYCkp3hzgsSuxCHQ8NN8xQG1wIHKJ4a1DTROTvFJdW+B5/eOsg== - dependencies: - "@nicolo-ribaudo/eslint-scope-5-internals" "5.1.1-v1" - eslint-visitor-keys "^2.1.0" - semver "^6.3.1" - -"@babel/generator@^7.10.5": - version "7.10.5" - resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.10.5.tgz" - integrity sha512-3vXxr3FEW7E7lJZiWQ3bM4+v/Vyr9C+hpolQ8BGFr9Y8Ri2tFLWTixmwKBafDujO1WVah4fhZBeU1bieKdghig== - dependencies: - "@babel/types" "^7.10.5" - jsesc "^2.5.1" - source-map "^0.5.0" - -"@babel/generator@^7.21.0": - version "7.21.1" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.21.1.tgz#951cc626057bc0af2c35cd23e9c64d384dea83dd" - integrity sha512-1lT45bAYlQhFn/BHivJs43AiW2rg3/UbLyShGfF3C0KmHvO5fSghWd5kBJy30kpRRucGzXStvnnCFniCR2kXAA== - dependencies: - "@babel/types" "^7.21.0" - "@jridgewell/gen-mapping" "^0.3.2" - "@jridgewell/trace-mapping" "^0.3.17" - jsesc "^2.5.1" - -"@babel/generator@^7.22.10": - version "7.22.10" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.22.10.tgz#c92254361f398e160645ac58831069707382b722" - integrity sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A== - dependencies: - "@babel/types" "^7.22.10" - "@jridgewell/gen-mapping" "^0.3.2" - "@jridgewell/trace-mapping" "^0.3.17" - jsesc "^2.5.1" - -"@babel/generator@^7.23.0": - version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.0.tgz#df5c386e2218be505b34837acbcb874d7a983420" - integrity sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g== - dependencies: - "@babel/types" "^7.23.0" - "@jridgewell/gen-mapping" "^0.3.2" - "@jridgewell/trace-mapping" "^0.3.17" - jsesc "^2.5.1" - -"@babel/helper-annotate-as-pure@^7.0.0": - version "7.12.10" - resolved "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.10.tgz" - integrity sha512-XplmVbC1n+KY6jL8/fgLVXXUauDIB+lD5+GsQEh6F6GBF1dq1qy4DP4yXWzDKcoqXB3X58t61e85Fitoww4JVQ== - dependencies: - "@babel/types" "^7.12.10" - -"@babel/helper-annotate-as-pure@^7.10.4": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz" - integrity sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA== - dependencies: - "@babel/types" "^7.10.4" - -"@babel/helper-annotate-as-pure@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb" - integrity sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA== - dependencies: - "@babel/types" "^7.18.6" - -"@babel/helper-builder-binary-assignment-operator-visitor@^7.18.6": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz#acd4edfd7a566d1d51ea975dff38fd52906981bb" - integrity sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw== - dependencies: - "@babel/helper-explode-assignable-expression" "^7.18.6" - "@babel/types" "^7.18.9" - -"@babel/helper-compilation-targets@^7.17.7", "@babel/helper-compilation-targets@^7.18.9", "@babel/helper-compilation-targets@^7.20.0", "@babel/helper-compilation-targets@^7.20.7": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz#a6cd33e93629f5eb473b021aac05df62c4cd09bb" - integrity sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ== - dependencies: - "@babel/compat-data" "^7.20.5" - "@babel/helper-validator-option" "^7.18.6" - browserslist "^4.21.3" - lru-cache "^5.1.1" - semver "^6.3.0" - -"@babel/helper-compilation-targets@^7.22.10": - version "7.22.10" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.10.tgz#01d648bbc25dd88f513d862ee0df27b7d4e67024" - integrity sha512-JMSwHD4J7SLod0idLq5PKgI+6g/hLD/iuWBq08ZX49xE14VpVEojJ5rHWptpirV2j020MvypRLAXAO50igCJ5Q== - dependencies: - "@babel/compat-data" "^7.22.9" - "@babel/helper-validator-option" "^7.22.5" - browserslist "^4.21.9" - lru-cache "^5.1.1" - semver "^6.3.1" - -"@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.21.0": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.21.0.tgz#64f49ecb0020532f19b1d014b03bccaa1ab85fb9" - integrity sha512-Q8wNiMIdwsv5la5SPxNYzzkPnjgC0Sy0i7jLkVOCdllu/xcVNkr3TeZzbHBJrj+XXRqzX5uCyCoV9eu6xUG7KQ== - dependencies: - "@babel/helper-annotate-as-pure" "^7.18.6" - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-function-name" "^7.21.0" - "@babel/helper-member-expression-to-functions" "^7.21.0" - "@babel/helper-optimise-call-expression" "^7.18.6" - "@babel/helper-replace-supers" "^7.20.7" - "@babel/helper-skip-transparent-expression-wrappers" "^7.20.0" - "@babel/helper-split-export-declaration" "^7.18.6" - -"@babel/helper-create-regexp-features-plugin@^7.10.4": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.4.tgz" - integrity sha512-2/hu58IEPKeoLF45DBwx3XFqsbCXmkdAay4spVr2x0jYgRxrSNp+ePwvSsy9g6YSaNDcKIQVPXk1Ov8S2edk2g== - dependencies: - "@babel/helper-annotate-as-pure" "^7.10.4" - "@babel/helper-regex" "^7.10.4" - regexpu-core "^4.7.0" - -"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.20.5": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.21.0.tgz#53ff78472e5ce10a52664272a239787107603ebb" - integrity sha512-N+LaFW/auRSWdx7SHD/HiARwXQju1vXTW4fKr4u5SgBUTm51OKEjKgj+cs00ggW3kEvNqwErnlwuq7Y3xBe4eg== - dependencies: - "@babel/helper-annotate-as-pure" "^7.18.6" - regexpu-core "^5.3.1" - -"@babel/helper-define-polyfill-provider@^0.3.3": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz#8612e55be5d51f0cd1f36b4a5a83924e89884b7a" - integrity sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww== - dependencies: - "@babel/helper-compilation-targets" "^7.17.7" - "@babel/helper-plugin-utils" "^7.16.7" - debug "^4.1.1" - lodash.debounce "^4.0.8" - resolve "^1.14.2" - semver "^6.1.2" - -"@babel/helper-environment-visitor@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be" - integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg== - -"@babel/helper-environment-visitor@^7.22.20": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" - integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== - -"@babel/helper-environment-visitor@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz#f06dd41b7c1f44e1f8da6c4055b41ab3a09a7e98" - integrity sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q== - -"@babel/helper-explode-assignable-expression@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz#41f8228ef0a6f1a036b8dfdfec7ce94f9a6bc096" - integrity sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg== - dependencies: - "@babel/types" "^7.18.6" - -"@babel/helper-function-name@^7.18.9", "@babel/helper-function-name@^7.19.0", "@babel/helper-function-name@^7.21.0": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz#d552829b10ea9f120969304023cd0645fa00b1b4" - integrity sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg== - dependencies: - "@babel/template" "^7.20.7" - "@babel/types" "^7.21.0" - -"@babel/helper-function-name@^7.23.0": - version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759" - integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== - dependencies: - "@babel/template" "^7.22.15" - "@babel/types" "^7.23.0" - -"@babel/helper-hoist-variables@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678" - integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q== - dependencies: - "@babel/types" "^7.18.6" - -"@babel/helper-hoist-variables@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" - integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-member-expression-to-functions@^7.10.4": - version "7.10.5" - resolved "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.10.5.tgz" - integrity sha512-HiqJpYD5+WopCXIAbQDG0zye5XYVvcO9w/DHp5GsaGkRUaamLj2bEtu6i8rnGGprAhHM3qidCMgp71HF4endhA== - dependencies: - "@babel/types" "^7.10.5" - -"@babel/helper-member-expression-to-functions@^7.20.7", "@babel/helper-member-expression-to-functions@^7.21.0": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.21.0.tgz#319c6a940431a133897148515877d2f3269c3ba5" - integrity sha512-Muu8cdZwNN6mRRNG6lAYErJ5X3bRevgYR2O8wN0yn7jJSnGDu6eG59RfT29JHxGUovyfrh6Pj0XzmR7drNVL3Q== - dependencies: - "@babel/types" "^7.21.0" - -"@babel/helper-module-imports@^7.0.0": - version "7.12.1" - resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.1.tgz" - integrity sha512-ZeC1TlMSvikvJNy1v/wPIazCu3NdOwgYZLIkmIyAsGhqkNpiDoQQRmaCK8YP4Pq3GPTLPV9WXaPCJKvx06JxKA== - dependencies: - "@babel/types" "^7.12.1" - -"@babel/helper-module-imports@^7.0.0-beta.49", "@babel/helper-module-imports@^7.10.4": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz" - integrity sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw== - dependencies: - "@babel/types" "^7.10.4" - -"@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz#1a8f4c9f4027d23f520bd76b364d44434a72660c" - integrity sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-module-imports@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e" - integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA== - dependencies: - "@babel/types" "^7.18.6" - -"@babel/helper-module-transforms@^7.10.5": - version "7.10.5" - resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.10.5.tgz" - integrity sha512-4P+CWMJ6/j1W915ITJaUkadLObmCRRSC234uctJfn/vHrsLNxsR8dwlcXv9ZhJWzl77awf+mWXSZEKt5t0OnlA== - dependencies: - "@babel/helper-module-imports" "^7.10.4" - "@babel/helper-replace-supers" "^7.10.4" - "@babel/helper-simple-access" "^7.10.4" - "@babel/helper-split-export-declaration" "^7.10.4" - "@babel/template" "^7.10.4" - "@babel/types" "^7.10.5" - lodash "^4.17.19" - -"@babel/helper-module-transforms@^7.18.6", "@babel/helper-module-transforms@^7.20.11", "@babel/helper-module-transforms@^7.21.0", "@babel/helper-module-transforms@^7.21.2": - version "7.21.2" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz#160caafa4978ac8c00ac66636cb0fa37b024e2d2" - integrity sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ== - dependencies: - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-module-imports" "^7.18.6" - "@babel/helper-simple-access" "^7.20.2" - "@babel/helper-split-export-declaration" "^7.18.6" - "@babel/helper-validator-identifier" "^7.19.1" - "@babel/template" "^7.20.7" - "@babel/traverse" "^7.21.2" - "@babel/types" "^7.21.2" - -"@babel/helper-module-transforms@^7.22.9": - version "7.22.9" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz#92dfcb1fbbb2bc62529024f72d942a8c97142129" - integrity sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ== - dependencies: - "@babel/helper-environment-visitor" "^7.22.5" - "@babel/helper-module-imports" "^7.22.5" - "@babel/helper-simple-access" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/helper-validator-identifier" "^7.22.5" - -"@babel/helper-optimise-call-expression@^7.10.4": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz" - integrity sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg== - dependencies: - "@babel/types" "^7.10.4" - -"@babel/helper-optimise-call-expression@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz#9369aa943ee7da47edab2cb4e838acf09d290ffe" - integrity sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA== - dependencies: - "@babel/types" "^7.18.6" - -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz" - integrity sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg== - -"@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.18.9", "@babel/helper-plugin-utils@^7.19.0", "@babel/helper-plugin-utils@^7.20.2": - version "7.20.2" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz#d1b9000752b18d0877cff85a5c376ce5c3121629" - integrity sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ== - -"@babel/helper-regex@^7.10.4": - version "7.10.5" - resolved "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.10.5.tgz" - integrity sha512-68kdUAzDrljqBrio7DYAEgCoJHxppJOERHOgOrDN7WjOzP0ZQ1LsSDRXcemzVZaLvjaJsJEESb6qt+znNuENDg== - dependencies: - lodash "^4.17.19" - -"@babel/helper-remap-async-to-generator@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz#997458a0e3357080e54e1d79ec347f8a8cd28519" - integrity sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA== - dependencies: - "@babel/helper-annotate-as-pure" "^7.18.6" - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-wrap-function" "^7.18.9" - "@babel/types" "^7.18.9" - -"@babel/helper-replace-supers@^7.10.4": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz" - integrity sha512-sPxZfFXocEymYTdVK1UNmFPBN+Hv5mJkLPsYWwGBxZAxaWfFu+xqp7b6qWD0yjNuNL2VKc6L5M18tOXUP7NU0A== - dependencies: - "@babel/helper-member-expression-to-functions" "^7.10.4" - "@babel/helper-optimise-call-expression" "^7.10.4" - "@babel/traverse" "^7.10.4" - "@babel/types" "^7.10.4" - -"@babel/helper-replace-supers@^7.18.6", "@babel/helper-replace-supers@^7.20.7": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.20.7.tgz#243ecd2724d2071532b2c8ad2f0f9f083bcae331" - integrity sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A== - dependencies: - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-member-expression-to-functions" "^7.20.7" - "@babel/helper-optimise-call-expression" "^7.18.6" - "@babel/template" "^7.20.7" - "@babel/traverse" "^7.20.7" - "@babel/types" "^7.20.7" - -"@babel/helper-simple-access@^7.10.4": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz" - integrity sha512-0fMy72ej/VEvF8ULmX6yb5MtHG4uH4Dbd6I/aHDb/JVg0bbivwt9Wg+h3uMvX+QSFtwr5MeItvazbrc4jtRAXw== - dependencies: - "@babel/template" "^7.10.4" - "@babel/types" "^7.10.4" - -"@babel/helper-simple-access@^7.20.2": - version "7.20.2" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz#0ab452687fe0c2cfb1e2b9e0015de07fc2d62dd9" - integrity sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA== - dependencies: - "@babel/types" "^7.20.2" - -"@babel/helper-simple-access@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de" - integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-skip-transparent-expression-wrappers@^7.20.0": - version "7.20.0" - resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz#fbe4c52f60518cab8140d77101f0e63a8a230684" - integrity sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg== - dependencies: - "@babel/types" "^7.20.0" - -"@babel/helper-split-export-declaration@^7.10.4": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.4.tgz" - integrity sha512-pySBTeoUff56fL5CBU2hWm9TesA4r/rOkI9DyJLvvgz09MB9YtfIYe3iBriVaYNaPe+Alua0vBIOVOLs2buWhg== - dependencies: - "@babel/types" "^7.10.4" - -"@babel/helper-split-export-declaration@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075" - integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA== - dependencies: - "@babel/types" "^7.18.6" - -"@babel/helper-split-export-declaration@^7.22.6": - version "7.22.6" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" - integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-string-parser@^7.19.4": - version "7.19.4" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz#38d3acb654b4701a9b77fb0615a96f775c3a9e63" - integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw== - -"@babel/helper-string-parser@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f" - integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw== - -"@babel/helper-string-parser@^7.23.4": - version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz#9478c707febcbbe1ddb38a3d91a2e054ae622d83" - integrity sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ== - -"@babel/helper-validator-identifier@^7.10.4": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz" - integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw== - -"@babel/helper-validator-identifier@^7.12.11": - version "7.12.11" - resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz" - integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw== - -"@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1": - version "7.19.1" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" - integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== - -"@babel/helper-validator-identifier@^7.22.20": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" - integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== - -"@babel/helper-validator-identifier@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz#9544ef6a33999343c8740fa51350f30eeaaaf193" - integrity sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ== - -"@babel/helper-validator-option@^7.18.6": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz#8224c7e13ace4bafdc4004da2cf064ef42673180" - integrity sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ== - -"@babel/helper-validator-option@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz#de52000a15a177413c8234fa3a8af4ee8102d0ac" - integrity sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw== - -"@babel/helper-wrap-function@^7.18.9": - version "7.20.5" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.20.5.tgz#75e2d84d499a0ab3b31c33bcfe59d6b8a45f62e3" - integrity sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q== - dependencies: - "@babel/helper-function-name" "^7.19.0" - "@babel/template" "^7.18.10" - "@babel/traverse" "^7.20.5" - "@babel/types" "^7.20.5" - -"@babel/helpers@^7.10.4": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.10.4.tgz" - integrity sha512-L2gX/XeUONeEbI78dXSrJzGdz4GQ+ZTA/aazfUsFaWjSe95kiCuOZ5HsXvkiw3iwF+mFHSRUfJU8t6YavocdXA== - dependencies: - "@babel/template" "^7.10.4" - "@babel/traverse" "^7.10.4" - "@babel/types" "^7.10.4" - -"@babel/helpers@^7.21.0": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.21.0.tgz#9dd184fb5599862037917cdc9eecb84577dc4e7e" - integrity sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA== - dependencies: - "@babel/template" "^7.20.7" - "@babel/traverse" "^7.21.0" - "@babel/types" "^7.21.0" - -"@babel/helpers@^7.22.10": - version "7.22.10" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.22.10.tgz#ae6005c539dfbcb5cd71fb51bfc8a52ba63bc37a" - integrity sha512-a41J4NW8HyZa1I1vAndrraTlPZ/eZoga2ZgS7fEr0tZJGVU4xqdE80CEm0CcNjha5EZ8fTBYLKHF0kqDUuAwQw== - dependencies: - "@babel/template" "^7.22.5" - "@babel/traverse" "^7.22.10" - "@babel/types" "^7.22.10" - -"@babel/highlight@^7.10.4": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz" - integrity sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA== - dependencies: - "@babel/helper-validator-identifier" "^7.10.4" - chalk "^2.0.0" - js-tokens "^4.0.0" - -"@babel/highlight@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" - integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== - dependencies: - "@babel/helper-validator-identifier" "^7.18.6" - chalk "^2.0.0" - js-tokens "^4.0.0" - -"@babel/highlight@^7.22.10": - version "7.22.10" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.10.tgz#02a3f6d8c1cb4521b2fd0ab0da8f4739936137d7" - integrity sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ== - dependencies: - "@babel/helper-validator-identifier" "^7.22.5" - chalk "^2.4.2" - js-tokens "^4.0.0" - -"@babel/highlight@^7.22.13": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.20.tgz#4ca92b71d80554b01427815e06f2df965b9c1f54" - integrity sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg== - dependencies: - "@babel/helper-validator-identifier" "^7.22.20" - chalk "^2.4.2" - js-tokens "^4.0.0" - -"@babel/highlight@^7.23.4": - version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.23.4.tgz#edaadf4d8232e1a961432db785091207ead0621b" - integrity sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A== - dependencies: - "@babel/helper-validator-identifier" "^7.22.20" - chalk "^2.4.2" - js-tokens "^4.0.0" - -"@babel/parser@^7.1.0", "@babel/parser@^7.10.4", "@babel/parser@^7.10.5": - version "7.10.5" - resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.10.5.tgz" - integrity sha512-wfryxy4bE1UivvQKSQDU4/X6dr+i8bctjUjj8Zyt3DQy7NtPizJXT8M52nqpNKL+nq2PW8lxk4ZqLj0fD4B4hQ== - -"@babel/parser@^7.14.7", "@babel/parser@^7.22.10", "@babel/parser@^7.22.5": - version "7.22.10" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.10.tgz#e37634f9a12a1716136c44624ef54283cabd3f55" - integrity sha512-lNbdGsQb9ekfsnjFGhEiF4hfFqGgfOP3H3d27re3n+CGhNuTSUEQdfWk556sTLNTloczcdM5TYF2LhzmDQKyvQ== - -"@babel/parser@^7.15.4": - version "7.23.6" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.6.tgz#ba1c9e512bda72a47e285ae42aff9d2a635a9e3b" - integrity sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ== - -"@babel/parser@^7.18.10": - version "7.20.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.3.tgz#5358cf62e380cf69efcb87a7bb922ff88bfac6e2" - integrity sha512-OP/s5a94frIPXwjzEcv5S/tpQfc6XhxYUnmWpgdqMWGgYCuErA3SzozaRAMQgSZWKeTJxht9aWAkUY+0UzvOFg== - -"@babel/parser@^7.20.7", "@babel/parser@^7.21.0": - version "7.21.2" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.2.tgz#dacafadfc6d7654c3051a66d6fe55b6cb2f2a0b3" - integrity sha512-URpaIJQwEkEC2T9Kn+Ai6Xe/02iNaVCuT/PtoRz3GPVJVDpPd7mLo+VddTbhCRU9TXqW5mSrQfXZyi8kDKOVpQ== - -"@babel/parser@^7.22.15", "@babel/parser@^7.23.0": - version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.0.tgz#da950e622420bf96ca0d0f2909cdddac3acd8719" - integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw== - -"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz#da5b8f9a580acdfbe53494dba45ea389fb09a4d2" - integrity sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.18.9": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.20.7.tgz#d9c85589258539a22a901033853101a6198d4ef1" - integrity sha512-sbr9+wNE5aXMBBFBICk01tt7sBf2Oc9ikRFEcem/ZORup9IMUdNhW7/wVLEbbtlWOsEubJet46mHAL2C8+2jKQ== - dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/helper-skip-transparent-expression-wrappers" "^7.20.0" - "@babel/plugin-proposal-optional-chaining" "^7.20.7" - -"@babel/plugin-proposal-async-generator-functions@^7.20.1": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz#bfb7276d2d573cb67ba379984a2334e262ba5326" - integrity sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA== - dependencies: - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/helper-remap-async-to-generator" "^7.18.9" - "@babel/plugin-syntax-async-generators" "^7.8.4" - -"@babel/plugin-proposal-class-properties@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz#b110f59741895f7ec21a6fff696ec46265c446a3" - integrity sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-proposal-class-static-block@^7.18.6": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.21.0.tgz#77bdd66fb7b605f3a61302d224bdfacf5547977d" - integrity sha512-XP5G9MWNUskFuP30IfFSEFB0Z6HzLIUcjYM4bYOPHXl7eiJ9HFv8tWj6TXTN5QODiEhDZAeI4hLok2iHFFV4hw== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.21.0" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/plugin-syntax-class-static-block" "^7.14.5" - -"@babel/plugin-proposal-decorators@^7.21.0": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.21.0.tgz#70e0c89fdcd7465c97593edb8f628ba6e4199d63" - integrity sha512-MfgX49uRrFUTL/HvWtmx3zmpyzMMr4MTj3d527MLlr/4RTT9G/ytFFP7qet2uM2Ve03b+BkpWUpK+lRXnQ+v9w== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.21.0" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/helper-replace-supers" "^7.20.7" - "@babel/helper-split-export-declaration" "^7.18.6" - "@babel/plugin-syntax-decorators" "^7.21.0" - -"@babel/plugin-proposal-dynamic-import@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz#72bcf8d408799f547d759298c3c27c7e7faa4d94" - integrity sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/plugin-syntax-dynamic-import" "^7.8.3" - -"@babel/plugin-proposal-export-namespace-from@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz#5f7313ab348cdb19d590145f9247540e94761203" - integrity sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA== - dependencies: - "@babel/helper-plugin-utils" "^7.18.9" - "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - -"@babel/plugin-proposal-json-strings@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz#7e8788c1811c393aff762817e7dbf1ebd0c05f0b" - integrity sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/plugin-syntax-json-strings" "^7.8.3" - -"@babel/plugin-proposal-logical-assignment-operators@^7.18.9": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz#dfbcaa8f7b4d37b51e8bfb46d94a5aea2bb89d83" - integrity sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug== - dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" - -"@babel/plugin-proposal-nullish-coalescing-operator@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz#fdd940a99a740e577d6c753ab6fbb43fdb9467e1" - integrity sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - -"@babel/plugin-proposal-numeric-separator@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz#899b14fbafe87f053d2c5ff05b36029c62e13c75" - integrity sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" - -"@babel/plugin-proposal-object-rest-spread@^7.20.2": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz#aa662940ef425779c75534a5c41e9d936edc390a" - integrity sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg== - dependencies: - "@babel/compat-data" "^7.20.5" - "@babel/helper-compilation-targets" "^7.20.7" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.20.7" - -"@babel/plugin-proposal-optional-catch-binding@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz#f9400d0e6a3ea93ba9ef70b09e72dd6da638a2cb" - integrity sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - -"@babel/plugin-proposal-optional-chaining@^7.18.9", "@babel/plugin-proposal-optional-chaining@^7.20.7": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz#886f5c8978deb7d30f678b2e24346b287234d3ea" - integrity sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA== - dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/helper-skip-transparent-expression-wrappers" "^7.20.0" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - -"@babel/plugin-proposal-private-methods@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz#5209de7d213457548a98436fa2882f52f4be6bea" - integrity sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-proposal-private-property-in-object@^7.18.6": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0.tgz#19496bd9883dd83c23c7d7fc45dcd9ad02dfa1dc" - integrity sha512-ha4zfehbJjc5MmXBlHec1igel5TJXXLDDRbuJ4+XT2TJcyD9/V1919BA8gMvsdHcNMBy4WBUBiRb3nw/EQUtBw== - dependencies: - "@babel/helper-annotate-as-pure" "^7.18.6" - "@babel/helper-create-class-features-plugin" "^7.21.0" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/plugin-syntax-private-property-in-object" "^7.14.5" - -"@babel/plugin-proposal-unicode-property-regex@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz#af613d2cd5e643643b65cded64207b15c85cb78e" - integrity sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-proposal-unicode-property-regex@^7.4.4": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.10.4.tgz" - integrity sha512-H+3fOgPnEXFL9zGYtKQe4IDOPKYlZdF1kqFDQRRb8PK4B8af1vAGK04tF5iQAAsui+mHNBQSAtd2/ndEDe9wuA== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-async-generators@^7.8.4": - version "7.8.4" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz" - integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-bigint@^7.8.3": - version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz" - integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-class-properties@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" - integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - -"@babel/plugin-syntax-class-properties@^7.8.3": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.10.4.tgz" - integrity sha512-GCSBF7iUle6rNugfURwNmCGG3Z/2+opxAMLs1nND4bhEG5PuxTIggDBoeYYSujAlLtsupzOHYJQgPS3pivwXIA== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-class-static-block@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" - integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-decorators@^7.21.0": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.21.0.tgz#d2b3f31c3e86fa86e16bb540b7660c55bd7d0e78" - integrity sha512-tIoPpGBR8UuM4++ccWN3gifhVvQu7ZizuR1fklhRJrd5ewgbkUS+0KVFeWWxELtn18NTLoW32XV7zyOgIAiz+w== - dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - -"@babel/plugin-syntax-dynamic-import@^7.8.3": - version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz" - integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-export-namespace-from@^7.8.3": - version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz" - integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-syntax-import-assertions@^7.20.0": - version "7.20.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.20.0.tgz#bb50e0d4bea0957235390641209394e87bdb9cc4" - integrity sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ== - dependencies: - "@babel/helper-plugin-utils" "^7.19.0" - -"@babel/plugin-syntax-import-meta@^7.8.3": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz" - integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-json-strings@^7.8.3": - version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz" - integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-jsx@7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.14.5.tgz#000e2e25d8673cce49300517a3eda44c263e4201" - integrity sha512-ohuFIsOMXJnbOMRfX7/w7LocdR6R7whhuRD4ax8IipLcLPlZGJKkBxgHp++U4N/vKyU16/YDQr2f5seajD3jIw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-jsx@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz#a8feef63b010150abd97f1649ec296e849943ca0" - integrity sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz" - integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": - version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz" - integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-numeric-separator@^7.10.4", "@babel/plugin-syntax-numeric-separator@^7.8.3": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz" - integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-object-rest-spread@^7.8.3": - version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz" - integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-optional-catch-binding@^7.8.3": - version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz" - integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-optional-chaining@^7.8.3": - version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz" - integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-private-property-in-object@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" - integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-top-level-await@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" - integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-top-level-await@^7.8.3": - version "7.12.1" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.1.tgz" - integrity sha512-i7ooMZFS+a/Om0crxZodrTzNEPJHZrlMVGMTEpFAj6rYY/bKCddB0Dk/YxfPuYXOopuhKk/e1jV6h+WUU9XN3A== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-transform-arrow-functions@^7.18.6": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.20.7.tgz#bea332b0e8b2dab3dafe55a163d8227531ab0551" - integrity sha512-3poA5E7dzDomxj9WXWwuD6A5F3kc7VXwIJO+E+J8qtDtS+pXPAhrgEyh+9GBwBgPq1Z+bB+/JD60lp5jsN7JPQ== - dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - -"@babel/plugin-transform-async-to-generator@^7.18.6": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.20.7.tgz#dfee18623c8cb31deb796aa3ca84dda9cea94354" - integrity sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q== - dependencies: - "@babel/helper-module-imports" "^7.18.6" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/helper-remap-async-to-generator" "^7.18.9" - -"@babel/plugin-transform-block-scoped-functions@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz#9187bf4ba302635b9d70d986ad70f038726216a8" - integrity sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-transform-block-scoping@^7.20.2": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.21.0.tgz#e737b91037e5186ee16b76e7ae093358a5634f02" - integrity sha512-Mdrbunoh9SxwFZapeHVrwFmri16+oYotcZysSzhNIVDwIAb1UV+kvnxULSYq9J3/q5MDG+4X6w8QVgD1zhBXNQ== - dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - -"@babel/plugin-transform-classes@^7.20.2": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.21.0.tgz#f469d0b07a4c5a7dbb21afad9e27e57b47031665" - integrity sha512-RZhbYTCEUAe6ntPehC4hlslPWosNHDox+vAs4On/mCLRLfoDVHf6hVEd7kuxr1RnHwJmxFfUM3cZiZRmPxJPXQ== - dependencies: - "@babel/helper-annotate-as-pure" "^7.18.6" - "@babel/helper-compilation-targets" "^7.20.7" - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-function-name" "^7.21.0" - "@babel/helper-optimise-call-expression" "^7.18.6" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/helper-replace-supers" "^7.20.7" - "@babel/helper-split-export-declaration" "^7.18.6" - globals "^11.1.0" - -"@babel/plugin-transform-computed-properties@^7.18.9": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.20.7.tgz#704cc2fd155d1c996551db8276d55b9d46e4d0aa" - integrity sha512-Lz7MvBK6DTjElHAmfu6bfANzKcxpyNPeYBGEafyA6E5HtRpjpZwU+u7Qrgz/2OR0z+5TvKYbPdphfSaAcZBrYQ== - dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/template" "^7.20.7" - -"@babel/plugin-transform-destructuring@^7.20.2": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.20.7.tgz#8bda578f71620c7de7c93af590154ba331415454" - integrity sha512-Xwg403sRrZb81IVB79ZPqNQME23yhugYVqgTxAhT99h485F4f+GMELFhhOsscDUB7HCswepKeCKLn/GZvUKoBA== - dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - -"@babel/plugin-transform-dotall-regex@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz#b286b3e7aae6c7b861e45bed0a2fafd6b1a4fef8" - integrity sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-transform-dotall-regex@^7.4.4": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.10.4.tgz" - integrity sha512-ZEAVvUTCMlMFAbASYSVQoxIbHm2OkG2MseW6bV2JjIygOjdVv8tuxrCTzj1+Rynh7ODb8GivUy7dzEXzEhuPaA== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-transform-duplicate-keys@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz#687f15ee3cdad6d85191eb2a372c4528eaa0ae0e" - integrity sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw== - dependencies: - "@babel/helper-plugin-utils" "^7.18.9" - -"@babel/plugin-transform-exponentiation-operator@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz#421c705f4521888c65e91fdd1af951bfefd4dacd" - integrity sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw== - dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-transform-for-of@^7.18.8": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.21.0.tgz#964108c9988de1a60b4be2354a7d7e245f36e86e" - integrity sha512-LlUYlydgDkKpIY7mcBWvyPPmMcOphEyYA27Ef4xpbh1IiDNLr0kZsos2nf92vz3IccvJI25QUwp86Eo5s6HmBQ== - dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - -"@babel/plugin-transform-function-name@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz#cc354f8234e62968946c61a46d6365440fc764e0" - integrity sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ== - dependencies: - "@babel/helper-compilation-targets" "^7.18.9" - "@babel/helper-function-name" "^7.18.9" - "@babel/helper-plugin-utils" "^7.18.9" - -"@babel/plugin-transform-literals@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz#72796fdbef80e56fba3c6a699d54f0de557444bc" - integrity sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg== - dependencies: - "@babel/helper-plugin-utils" "^7.18.9" - -"@babel/plugin-transform-member-expression-literals@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz#ac9fdc1a118620ac49b7e7a5d2dc177a1bfee88e" - integrity sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-transform-modules-amd@^7.19.6": - version "7.20.11" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.20.11.tgz#3daccca8e4cc309f03c3a0c4b41dc4b26f55214a" - integrity sha512-NuzCt5IIYOW0O30UvqktzHYR2ud5bOWbY0yaxWZ6G+aFzOMJvrs5YHNikrbdaT15+KNO31nPOy5Fim3ku6Zb5g== - dependencies: - "@babel/helper-module-transforms" "^7.20.11" - "@babel/helper-plugin-utils" "^7.20.2" - -"@babel/plugin-transform-modules-commonjs@^7.19.6": - version "7.21.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.21.2.tgz#6ff5070e71e3192ef2b7e39820a06fb78e3058e7" - integrity sha512-Cln+Yy04Gxua7iPdj6nOV96smLGjpElir5YwzF0LBPKoPlLDNJePNlrGGaybAJkd0zKRnOVXOgizSqPYMNYkzA== - dependencies: - "@babel/helper-module-transforms" "^7.21.2" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/helper-simple-access" "^7.20.2" - -"@babel/plugin-transform-modules-systemjs@^7.19.6": - version "7.20.11" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.20.11.tgz#467ec6bba6b6a50634eea61c9c232654d8a4696e" - integrity sha512-vVu5g9BPQKSFEmvt2TA4Da5N+QVS66EX21d8uoOihC+OCpUoGvzVsXeqFdtAEfVa5BILAeFt+U7yVmLbQnAJmw== - dependencies: - "@babel/helper-hoist-variables" "^7.18.6" - "@babel/helper-module-transforms" "^7.20.11" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/helper-validator-identifier" "^7.19.1" - -"@babel/plugin-transform-modules-umd@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz#81d3832d6034b75b54e62821ba58f28ed0aab4b9" - integrity sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ== - dependencies: - "@babel/helper-module-transforms" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-transform-named-capturing-groups-regex@^7.19.1": - version "7.20.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.20.5.tgz#626298dd62ea51d452c3be58b285d23195ba69a8" - integrity sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.20.5" - "@babel/helper-plugin-utils" "^7.20.2" - -"@babel/plugin-transform-new-target@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz#d128f376ae200477f37c4ddfcc722a8a1b3246a8" - integrity sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-transform-object-super@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz#fb3c6ccdd15939b6ff7939944b51971ddc35912c" - integrity sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/helper-replace-supers" "^7.18.6" - -"@babel/plugin-transform-parameters@^7.20.1", "@babel/plugin-transform-parameters@^7.20.7": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.7.tgz#0ee349e9d1bc96e78e3b37a7af423a4078a7083f" - integrity sha512-WiWBIkeHKVOSYPO0pWkxGPfKeWrCJyD3NJ53+Lrp/QMSZbsVPovrVl2aWZ19D/LTVnaDv5Ap7GJ/B2CTOZdrfA== - dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - -"@babel/plugin-transform-property-literals@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz#e22498903a483448e94e032e9bbb9c5ccbfc93a3" - integrity sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-transform-react-display-name@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.18.6.tgz#8b1125f919ef36ebdfff061d664e266c666b9415" - integrity sha512-TV4sQ+T013n61uMoygyMRm+xf04Bd5oqFpv2jAEQwSZ8NwQA7zeRPg1LMVg2PWi3zWBz+CLKD+v5bcpZ/BS0aA== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-transform-react-jsx-development@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.18.6.tgz#dbe5c972811e49c7405b630e4d0d2e1380c0ddc5" - integrity sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA== - dependencies: - "@babel/plugin-transform-react-jsx" "^7.18.6" - -"@babel/plugin-transform-react-jsx@^7.18.6": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.21.0.tgz#656b42c2fdea0a6d8762075d58ef9d4e3c4ab8a2" - integrity sha512-6OAWljMvQrZjR2DaNhVfRz6dkCAVV+ymcLUmaf8bccGOHn2v5rHJK3tTpij0BuhdYWP4LLaqj5lwcdlpAAPuvg== - dependencies: - "@babel/helper-annotate-as-pure" "^7.18.6" - "@babel/helper-module-imports" "^7.18.6" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/plugin-syntax-jsx" "^7.18.6" - "@babel/types" "^7.21.0" - -"@babel/plugin-transform-react-pure-annotations@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.18.6.tgz#561af267f19f3e5d59291f9950fd7b9663d0d844" - integrity sha512-I8VfEPg9r2TRDdvnHgPepTKvuRomzA8+u+nhY7qSI1fR2hRNebasZEETLyM5mAUr0Ku56OkXJ0I7NHJnO6cJiQ== - dependencies: - "@babel/helper-annotate-as-pure" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-transform-regenerator@^7.18.6": - version "7.20.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.20.5.tgz#57cda588c7ffb7f4f8483cc83bdcea02a907f04d" - integrity sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ== - dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - regenerator-transform "^0.15.1" - -"@babel/plugin-transform-reserved-words@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz#b1abd8ebf8edaa5f7fe6bbb8d2133d23b6a6f76a" - integrity sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-transform-runtime@^7.21.0": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.21.0.tgz#2a884f29556d0a68cd3d152dcc9e6c71dfb6eee8" - integrity sha512-ReY6pxwSzEU0b3r2/T/VhqMKg/AkceBT19X0UptA3/tYi5Pe2eXgEUH+NNMC5nok6c6XQz5tyVTUpuezRfSMSg== - dependencies: - "@babel/helper-module-imports" "^7.18.6" - "@babel/helper-plugin-utils" "^7.20.2" - babel-plugin-polyfill-corejs2 "^0.3.3" - babel-plugin-polyfill-corejs3 "^0.6.0" - babel-plugin-polyfill-regenerator "^0.4.1" - semver "^6.3.0" - -"@babel/plugin-transform-shorthand-properties@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz#6d6df7983d67b195289be24909e3f12a8f664dc9" - integrity sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-transform-spread@^7.19.0": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.20.7.tgz#c2d83e0b99d3bf83e07b11995ee24bf7ca09401e" - integrity sha512-ewBbHQ+1U/VnH1fxltbJqDeWBU1oNLG8Dj11uIv3xVf7nrQu0bPGe5Rf716r7K5Qz+SqtAOVswoVunoiBtGhxw== - dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/helper-skip-transparent-expression-wrappers" "^7.20.0" - -"@babel/plugin-transform-sticky-regex@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz#c6706eb2b1524028e317720339583ad0f444adcc" - integrity sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-transform-template-literals@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz#04ec6f10acdaa81846689d63fae117dd9c243a5e" - integrity sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA== - dependencies: - "@babel/helper-plugin-utils" "^7.18.9" - -"@babel/plugin-transform-typeof-symbol@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz#c8cea68263e45addcd6afc9091429f80925762c0" - integrity sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw== - dependencies: - "@babel/helper-plugin-utils" "^7.18.9" - -"@babel/plugin-transform-unicode-escapes@^7.18.10": - version "7.18.10" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz#1ecfb0eda83d09bbcb77c09970c2dd55832aa246" - integrity sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ== - dependencies: - "@babel/helper-plugin-utils" "^7.18.9" - -"@babel/plugin-transform-unicode-regex@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz#194317225d8c201bbae103364ffe9e2cea36cdca" - integrity sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/preset-env@^7.20.2": - version "7.20.2" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.20.2.tgz#9b1642aa47bb9f43a86f9630011780dab7f86506" - integrity sha512-1G0efQEWR1EHkKvKHqbG+IN/QdgwfByUpM5V5QroDzGV2t3S/WXNQd693cHiHTlCFMpr9B6FkPFXDA2lQcKoDg== - dependencies: - "@babel/compat-data" "^7.20.1" - "@babel/helper-compilation-targets" "^7.20.0" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/helper-validator-option" "^7.18.6" - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.18.6" - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.18.9" - "@babel/plugin-proposal-async-generator-functions" "^7.20.1" - "@babel/plugin-proposal-class-properties" "^7.18.6" - "@babel/plugin-proposal-class-static-block" "^7.18.6" - "@babel/plugin-proposal-dynamic-import" "^7.18.6" - "@babel/plugin-proposal-export-namespace-from" "^7.18.9" - "@babel/plugin-proposal-json-strings" "^7.18.6" - "@babel/plugin-proposal-logical-assignment-operators" "^7.18.9" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.18.6" - "@babel/plugin-proposal-numeric-separator" "^7.18.6" - "@babel/plugin-proposal-object-rest-spread" "^7.20.2" - "@babel/plugin-proposal-optional-catch-binding" "^7.18.6" - "@babel/plugin-proposal-optional-chaining" "^7.18.9" - "@babel/plugin-proposal-private-methods" "^7.18.6" - "@babel/plugin-proposal-private-property-in-object" "^7.18.6" - "@babel/plugin-proposal-unicode-property-regex" "^7.18.6" - "@babel/plugin-syntax-async-generators" "^7.8.4" - "@babel/plugin-syntax-class-properties" "^7.12.13" - "@babel/plugin-syntax-class-static-block" "^7.14.5" - "@babel/plugin-syntax-dynamic-import" "^7.8.3" - "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - "@babel/plugin-syntax-import-assertions" "^7.20.0" - "@babel/plugin-syntax-json-strings" "^7.8.3" - "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - "@babel/plugin-syntax-private-property-in-object" "^7.14.5" - "@babel/plugin-syntax-top-level-await" "^7.14.5" - "@babel/plugin-transform-arrow-functions" "^7.18.6" - "@babel/plugin-transform-async-to-generator" "^7.18.6" - "@babel/plugin-transform-block-scoped-functions" "^7.18.6" - "@babel/plugin-transform-block-scoping" "^7.20.2" - "@babel/plugin-transform-classes" "^7.20.2" - "@babel/plugin-transform-computed-properties" "^7.18.9" - "@babel/plugin-transform-destructuring" "^7.20.2" - "@babel/plugin-transform-dotall-regex" "^7.18.6" - "@babel/plugin-transform-duplicate-keys" "^7.18.9" - "@babel/plugin-transform-exponentiation-operator" "^7.18.6" - "@babel/plugin-transform-for-of" "^7.18.8" - "@babel/plugin-transform-function-name" "^7.18.9" - "@babel/plugin-transform-literals" "^7.18.9" - "@babel/plugin-transform-member-expression-literals" "^7.18.6" - "@babel/plugin-transform-modules-amd" "^7.19.6" - "@babel/plugin-transform-modules-commonjs" "^7.19.6" - "@babel/plugin-transform-modules-systemjs" "^7.19.6" - "@babel/plugin-transform-modules-umd" "^7.18.6" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.19.1" - "@babel/plugin-transform-new-target" "^7.18.6" - "@babel/plugin-transform-object-super" "^7.18.6" - "@babel/plugin-transform-parameters" "^7.20.1" - "@babel/plugin-transform-property-literals" "^7.18.6" - "@babel/plugin-transform-regenerator" "^7.18.6" - "@babel/plugin-transform-reserved-words" "^7.18.6" - "@babel/plugin-transform-shorthand-properties" "^7.18.6" - "@babel/plugin-transform-spread" "^7.19.0" - "@babel/plugin-transform-sticky-regex" "^7.18.6" - "@babel/plugin-transform-template-literals" "^7.18.9" - "@babel/plugin-transform-typeof-symbol" "^7.18.9" - "@babel/plugin-transform-unicode-escapes" "^7.18.10" - "@babel/plugin-transform-unicode-regex" "^7.18.6" - "@babel/preset-modules" "^0.1.5" - "@babel/types" "^7.20.2" - babel-plugin-polyfill-corejs2 "^0.3.3" - babel-plugin-polyfill-corejs3 "^0.6.0" - babel-plugin-polyfill-regenerator "^0.4.1" - core-js-compat "^3.25.1" - semver "^6.3.0" - -"@babel/preset-modules@^0.1.5": - version "0.1.5" - resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.5.tgz#ef939d6e7f268827e1841638dc6ff95515e115d9" - integrity sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" - "@babel/plugin-transform-dotall-regex" "^7.4.4" - "@babel/types" "^7.4.4" - esutils "^2.0.2" - -"@babel/preset-react@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.18.6.tgz#979f76d6277048dc19094c217b507f3ad517dd2d" - integrity sha512-zXr6atUmyYdiWRVLOZahakYmOBHtWc2WGCkP8PYTgZi0iJXDY2CN180TdrIW4OGOAdLc7TifzDIvtx6izaRIzg== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/helper-validator-option" "^7.18.6" - "@babel/plugin-transform-react-display-name" "^7.18.6" - "@babel/plugin-transform-react-jsx" "^7.18.6" - "@babel/plugin-transform-react-jsx-development" "^7.18.6" - "@babel/plugin-transform-react-pure-annotations" "^7.18.6" - -"@babel/regjsgen@^0.8.0": - version "0.8.0" - resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310" - integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA== - -"@babel/runtime-corejs3@^7.10.2": - version "7.12.5" - resolved "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.12.5.tgz" - integrity sha512-roGr54CsTmNPPzZoCP1AmDXuBoNao7tnSA83TXTwt+UK5QVyh1DIJnrgYRPWKCF2flqZQXwa7Yr8v7VmLzF0YQ== - dependencies: - core-js-pure "^3.0.0" - regenerator-runtime "^0.13.4" - -"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.2.0", "@babel/runtime@^7.4.5": - version "7.12.5" - resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.5.tgz" - integrity sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg== - dependencies: - regenerator-runtime "^0.13.4" - -"@babel/runtime@^7.10.5", "@babel/runtime@^7.4.2", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": - version "7.10.5" - resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.10.5.tgz" - integrity sha512-otddXKhdNn7d0ptoFRHtMLa8LqDxLYwTjB4nYgM1yy5N6gU/MUf8zqyyLltCH3yAVitBzmwK4us+DD0l/MauAg== - dependencies: - regenerator-runtime "^0.13.4" - -"@babel/runtime@^7.13.8", "@babel/runtime@^7.14.0", "@babel/runtime@^7.18.3": - version "7.22.10" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.10.tgz#ae3e9631fd947cb7e3610d3e9d8fef5f76696682" - integrity sha512-21t/fkKLMZI4pqP2wlmsQAWnYW1PDyKyyUV4vCi+B25ydmdaYTKXPwCj0BzSUnZf4seIiYvSA3jcZ3gdsMFkLQ== - dependencies: - regenerator-runtime "^0.14.0" - -"@babel/runtime@^7.21.0": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.0.tgz#5b55c9d394e5fcf304909a8b00c07dc217b56673" - integrity sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw== - dependencies: - regenerator-runtime "^0.13.11" - -"@babel/runtime@^7.7.2": - version "7.12.1" - resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.1.tgz" - integrity sha512-J5AIf3vPj3UwXaAzb5j1xM4WAQDX3EMgemF8rjCP3SoW09LfRKAXQKt6CoVYl230P6iWdRcBbnLDDdnqWxZSCA== - dependencies: - regenerator-runtime "^0.13.4" - -"@babel/template@7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.15.4.tgz#51898d35dcf3faa670c4ee6afcfd517ee139f194" - integrity sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg== - dependencies: - "@babel/code-frame" "^7.14.5" - "@babel/parser" "^7.15.4" - "@babel/types" "^7.15.4" - -"@babel/template@^7.10.4", "@babel/template@^7.3.3": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz" - integrity sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA== - dependencies: - "@babel/code-frame" "^7.10.4" - "@babel/parser" "^7.10.4" - "@babel/types" "^7.10.4" - -"@babel/template@^7.18.10", "@babel/template@^7.20.7": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.20.7.tgz#a15090c2839a83b02aa996c0b4994005841fd5a8" - integrity sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw== - dependencies: - "@babel/code-frame" "^7.18.6" - "@babel/parser" "^7.20.7" - "@babel/types" "^7.20.7" - -"@babel/template@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38" - integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w== - dependencies: - "@babel/code-frame" "^7.22.13" - "@babel/parser" "^7.22.15" - "@babel/types" "^7.22.15" - -"@babel/template@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.5.tgz#0c8c4d944509875849bd0344ff0050756eefc6ec" - integrity sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw== - dependencies: - "@babel/code-frame" "^7.22.5" - "@babel/parser" "^7.22.5" - "@babel/types" "^7.22.5" - -"@babel/template@^7.4.4": - version "7.18.10" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.10.tgz#6f9134835970d1dbf0835c0d100c9f38de0c5e71" - integrity sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA== - dependencies: - "@babel/code-frame" "^7.18.6" - "@babel/parser" "^7.18.10" - "@babel/types" "^7.18.10" - -"@babel/traverse@^7.1.0", "@babel/traverse@^7.10.4", "@babel/traverse@^7.10.5", "@babel/traverse@^7.20.5", "@babel/traverse@^7.20.7", "@babel/traverse@^7.21.0", "@babel/traverse@^7.21.2", "@babel/traverse@^7.22.10", "@babel/traverse@^7.4.5": - version "7.23.2" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.2.tgz#329c7a06735e144a506bdb2cad0268b7f46f4ad8" - integrity sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw== - dependencies: - "@babel/code-frame" "^7.22.13" - "@babel/generator" "^7.23.0" - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-function-name" "^7.23.0" - "@babel/helper-hoist-variables" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/parser" "^7.23.0" - "@babel/types" "^7.23.0" - debug "^4.1.0" - globals "^11.1.0" - -"@babel/types@^7.0.0", "@babel/types@^7.0.0-beta.49", "@babel/types@^7.10.4", "@babel/types@^7.10.5", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4": - version "7.10.5" - resolved "https://registry.npmjs.org/@babel/types/-/types-7.10.5.tgz" - integrity sha512-ixV66KWfCI6GKoA/2H9v6bQdbfXEwwpOdQ8cRvb4F+eyvhlaHxWFMQB4+3d9QFJXZsiiiqVrewNV0DFEQpyT4Q== - dependencies: - "@babel/helper-validator-identifier" "^7.10.4" - lodash "^4.17.19" - to-fast-properties "^2.0.0" - -"@babel/types@^7.12.1": - version "7.12.1" - resolved "https://registry.npmjs.org/@babel/types/-/types-7.12.1.tgz" - integrity sha512-BzSY3NJBKM4kyatSOWh3D/JJ2O3CVzBybHWxtgxnggaxEuaSTTDqeiSb/xk9lrkw2Tbqyivw5ZU4rT+EfznQsA== - dependencies: - "@babel/helper-validator-identifier" "^7.10.4" - lodash "^4.17.19" - to-fast-properties "^2.0.0" - -"@babel/types@^7.12.10": - version "7.12.11" - resolved "https://registry.npmjs.org/@babel/types/-/types-7.12.11.tgz" - integrity sha512-ukA9SQtKThINm++CX1CwmliMrE54J6nIYB5XTwL5f/CLFW9owfls+YSU8tVW15RQ2w+a3fSbPjC6HdQNtWZkiA== - dependencies: - "@babel/helper-validator-identifier" "^7.12.11" - lodash "^4.17.19" - to-fast-properties "^2.0.0" - -"@babel/types@^7.15.4": - version "7.23.6" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.6.tgz#be33fdb151e1f5a56877d704492c240fc71c7ccd" - integrity sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg== - dependencies: - "@babel/helper-string-parser" "^7.23.4" - "@babel/helper-validator-identifier" "^7.22.20" - to-fast-properties "^2.0.0" - -"@babel/types@^7.18.10": - version "7.20.2" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.20.2.tgz#67ac09266606190f496322dbaff360fdaa5e7842" - integrity sha512-FnnvsNWgZCr232sqtXggapvlkk/tuwR/qhGzcmxI0GXLCjmPYQPzio2FbdlWuY6y1sHFfQKk+rRbUZ9VStQMog== - dependencies: - "@babel/helper-string-parser" "^7.19.4" - "@babel/helper-validator-identifier" "^7.19.1" - to-fast-properties "^2.0.0" - -"@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.20.0", "@babel/types@^7.20.2", "@babel/types@^7.20.5", "@babel/types@^7.20.7", "@babel/types@^7.21.0", "@babel/types@^7.21.2": - version "7.21.2" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.21.2.tgz#92246f6e00f91755893c2876ad653db70c8310d1" - integrity sha512-3wRZSs7jiFaB8AjxiiD+VqN5DTG2iRvJGQ+qYFrs/654lg6kGTQWIOFjlBo5RaXuAZjBmP3+OQH4dmhqiiyYxw== - dependencies: - "@babel/helper-string-parser" "^7.19.4" - "@babel/helper-validator-identifier" "^7.19.1" - to-fast-properties "^2.0.0" - -"@babel/types@^7.22.10", "@babel/types@^7.22.5": - version "7.22.10" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.10.tgz#4a9e76446048f2c66982d1a989dd12b8a2d2dc03" - integrity sha512-obaoigiLrlDZ7TUQln/8m4mSqIW2QFeOrCQc9r+xsaHGNoplVNYlRVpsfE8Vj35GEm2ZH4ZhrNYogs/3fj85kg== - dependencies: - "@babel/helper-string-parser" "^7.22.5" - "@babel/helper-validator-identifier" "^7.22.5" - to-fast-properties "^2.0.0" - -"@babel/types@^7.22.15", "@babel/types@^7.23.0": - version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.0.tgz#8c1f020c9df0e737e4e247c0619f58c68458aaeb" - integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg== - dependencies: - "@babel/helper-string-parser" "^7.22.5" - "@babel/helper-validator-identifier" "^7.22.20" - to-fast-properties "^2.0.0" - -"@bcoe/v8-coverage@^0.2.3": - version "0.2.3" - resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz" - integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== - -"@cnakazawa/watch@^1.0.3": - version "1.0.4" - resolved "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz" - integrity sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ== - dependencies: - exec-sh "^0.3.2" - minimist "^1.2.0" - -"@discoveryjs/json-ext@0.5.7", "@discoveryjs/json-ext@^0.5.0": - version "0.5.7" - resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" - integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== - -"@ebay/nice-modal-react@^1.2.13": - version "1.2.13" - resolved "https://registry.yarnpkg.com/@ebay/nice-modal-react/-/nice-modal-react-1.2.13.tgz#7e8229fe3a48a11f27cd7f5e21190d82d6f609ce" - integrity sha512-jx8xIWe/Up4tpNuM02M+rbnLoxdngTGk3Y8LjJsLGXXcSoKd/+eZStZcAlIO/jwxyz/bhPZnpqPJZWAmhOofuA== - -"@emoji-mart/data@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@emoji-mart/data/-/data-1.1.2.tgz#777c976f8f143df47cbb23a7077c9ca9fe5fc513" - integrity sha512-1HP8BxD2azjqWJvxIaWAMyTySeZY0Osr83ukYjltPVkNXeJvTz7yDrPLBtnrD5uqJ3tg4CcLuuBW09wahqL/fg== - -"@emoji-mart/react@^1.1.1": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@emoji-mart/react/-/react-1.1.1.tgz#ddad52f93a25baf31c5383c3e7e4c6e05554312a" - integrity sha512-NMlFNeWgv1//uPsvLxvGQoIerPuVdXwK/EUek8OOkJ6wVOWPUizRBJU0hDqWZCOROVpfBgCemaC3m6jDOXi03g== - -"@emotion/babel-plugin@^11.11.0": - version "11.11.0" - resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz#c2d872b6a7767a9d176d007f5b31f7d504bb5d6c" - integrity sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ== - dependencies: - "@babel/helper-module-imports" "^7.16.7" - "@babel/runtime" "^7.18.3" - "@emotion/hash" "^0.9.1" - "@emotion/memoize" "^0.8.1" - "@emotion/serialize" "^1.1.2" - babel-plugin-macros "^3.1.0" - convert-source-map "^1.5.0" - escape-string-regexp "^4.0.0" - find-root "^1.1.0" - source-map "^0.5.7" - stylis "4.2.0" - -"@emotion/cache@^11.11.0", "@emotion/cache@^11.4.0": - version "11.11.0" - resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.11.0.tgz#809b33ee6b1cb1a625fef7a45bc568ccd9b8f3ff" - integrity sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ== - dependencies: - "@emotion/memoize" "^0.8.1" - "@emotion/sheet" "^1.2.2" - "@emotion/utils" "^1.2.1" - "@emotion/weak-memoize" "^0.3.1" - stylis "4.2.0" - -"@emotion/hash@^0.9.1": - version "0.9.1" - resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.1.tgz#4ffb0055f7ef676ebc3a5a91fb621393294e2f43" - integrity sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ== - -"@emotion/is-prop-valid@^0.8.8": - version "0.8.8" - resolved "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz" - integrity sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA== - dependencies: - "@emotion/memoize" "0.7.4" - -"@emotion/memoize@0.7.4": - version "0.7.4" - resolved "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz" - integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw== - -"@emotion/memoize@^0.8.1": - version "0.8.1" - resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.8.1.tgz#c1ddb040429c6d21d38cc945fe75c818cfb68e17" - integrity sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA== - -"@emotion/react@^11.8.1": - version "11.11.1" - resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.11.1.tgz#b2c36afac95b184f73b08da8c214fdf861fa4157" - integrity sha512-5mlW1DquU5HaxjLkfkGN1GA/fvVGdyHURRiX/0FHl2cfIfRxSOfmxEH5YS43edp0OldZrZ+dkBKbngxcNCdZvA== - dependencies: - "@babel/runtime" "^7.18.3" - "@emotion/babel-plugin" "^11.11.0" - "@emotion/cache" "^11.11.0" - "@emotion/serialize" "^1.1.2" - "@emotion/use-insertion-effect-with-fallbacks" "^1.0.1" - "@emotion/utils" "^1.2.1" - "@emotion/weak-memoize" "^0.3.1" - hoist-non-react-statics "^3.3.1" - -"@emotion/serialize@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.1.2.tgz#017a6e4c9b8a803bd576ff3d52a0ea6fa5a62b51" - integrity sha512-zR6a/fkFP4EAcCMQtLOhIgpprZOwNmCldtpaISpvz348+DP4Mz8ZoKaGGCQpbzepNIUWbq4w6hNZkwDyKoS+HA== - dependencies: - "@emotion/hash" "^0.9.1" - "@emotion/memoize" "^0.8.1" - "@emotion/unitless" "^0.8.1" - "@emotion/utils" "^1.2.1" - csstype "^3.0.2" - -"@emotion/sheet@^1.2.2": - version "1.2.2" - resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.2.2.tgz#d58e788ee27267a14342303e1abb3d508b6d0fec" - integrity sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA== - -"@emotion/stylis@^0.8.4": - version "0.8.5" - resolved "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz" - integrity sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ== - -"@emotion/unitless@^0.7.4": - version "0.7.5" - resolved "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz" - integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== - -"@emotion/unitless@^0.8.1": - version "0.8.1" - resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.8.1.tgz#182b5a4704ef8ad91bde93f7a860a88fd92c79a3" - integrity sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ== - -"@emotion/use-insertion-effect-with-fallbacks@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz#08de79f54eb3406f9daaf77c76e35313da963963" - integrity sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw== - -"@emotion/utils@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.2.1.tgz#bbab58465738d31ae4cb3dbb6fc00a5991f755e4" - integrity sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg== - -"@emotion/weak-memoize@^0.3.1": - version "0.3.1" - resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz#d0fce5d07b0620caa282b5131c297bb60f9d87e6" - integrity sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww== - -"@eslint/eslintrc@^0.2.1": - version "0.2.1" - resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.2.1.tgz" - integrity sha512-XRUeBZ5zBWLYgSANMpThFddrZZkEbGHgUdt5UJjZfnlN9BGCiUBrf+nvbRupSjMvqzwnQN0qwCmOxITt1cfywA== - dependencies: - ajv "^6.12.4" - debug "^4.1.1" - espree "^7.3.0" - globals "^12.1.0" - ignore "^4.0.6" - import-fresh "^3.2.1" - js-yaml "^3.13.1" - lodash "^4.17.19" - minimatch "^3.0.4" - strip-json-comments "^3.1.1" - -"@esri/arcgis-rest-auth@^2.14.1": - version "2.24.0" - resolved "https://registry.npmjs.org/@esri/arcgis-rest-auth/-/arcgis-rest-auth-2.24.0.tgz" - integrity sha512-ntq9zI3+RqY7MQwuzpj9mZ9mzx32LnjApUJWGUTUL6nlPEb8JNY6cchZxISt1KNOQ3j/ElE8xaMl8sX+MzM1+w== - dependencies: - "@esri/arcgis-rest-types" "^2.24.0" - tslib "^1.13.0" - -"@esri/arcgis-rest-portal@^2.14.1": - version "2.24.0" - resolved "https://registry.npmjs.org/@esri/arcgis-rest-portal/-/arcgis-rest-portal-2.24.0.tgz" - integrity sha512-06y3/FpG3GUCY7RyvvyXa+3/Ss6hRudTRGSzJUjQrjV+r7dkz6wxZplYBOqIW8ZibY3x7pUuvYVQV4hGZFxhPg== - dependencies: - "@esri/arcgis-rest-types" "^2.24.0" - tslib "^1.13.0" - -"@esri/arcgis-rest-request@^2.14.1": - version "2.24.0" - resolved "https://registry.npmjs.org/@esri/arcgis-rest-request/-/arcgis-rest-request-2.24.0.tgz" - integrity sha512-HXEG7z7yuqlP1tvagsuftwhKLtWKZXkkfUbUBFAaYFZSSz50yiKH3rk5ODc/dRCWoHPabUMpQBoGwY88lMANxA== - dependencies: - tslib "^1.10.0" - -"@esri/arcgis-rest-types@^2.24.0": - version "2.24.0" - resolved "https://registry.npmjs.org/@esri/arcgis-rest-types/-/arcgis-rest-types-2.24.0.tgz" - integrity sha512-Lfg+1EyQYqcCC8c2hyKHuJLTHdEEOvERC6VZco9h4sLZfDvUv2nwdrs9sxX/1xg0dJl/5ytpXKgFdNv6AXOGnw== - -"@esri/calcite-colors@^1.7.1": - version "1.7.1" - resolved "https://registry.npmjs.org/@esri/calcite-colors/-/calcite-colors-1.7.1.tgz" - integrity sha512-oZgYHKPLLfgo4teqDsnS9utYySL5ECYtqkGzXUMOu5J1vSS0Z/MlBEq6RMDm9+aHsDUnMZw6NuXDkaQzwfkzzQ== - -"@floating-ui/core@^1.4.1": - version "1.4.1" - resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.4.1.tgz#0d633f4b76052668afb932492ac452f7ebe97f17" - integrity sha512-jk3WqquEJRlcyu7997NtR5PibI+y5bi+LS3hPmguVClypenMsCY3CBa3LAQnozRCtCrYWSEtAdiskpamuJRFOQ== - dependencies: - "@floating-ui/utils" "^0.1.1" - -"@floating-ui/dom@^1.0.1": - version "1.5.1" - resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.5.1.tgz#88b70defd002fe851f17b4a25efb2d3c04d7a8d7" - integrity sha512-KwvVcPSXg6mQygvA1TjbN/gh///36kKtllIF8SUm0qpFj8+rvYrpvlYdL1JoA71SHpDqgSSdGOSoQ0Mp3uY5aw== - dependencies: - "@floating-ui/core" "^1.4.1" - "@floating-ui/utils" "^0.1.1" - -"@floating-ui/utils@^0.1.1": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.1.1.tgz#1a5b1959a528e374e8037c4396c3e825d6cf4a83" - integrity sha512-m0G6wlnhm/AX0H12IOWtK8gASEMffnX08RtKkCgTdHb9JpHKGloI7icFfLg9ZmQeavcvR0PKmzxClyuFPSjKWw== - -"@fortawesome/fontawesome-common-types@6.2.0": - version "6.2.0" - resolved "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.2.0.tgz" - integrity sha512-rBevIsj2nclStJ7AxTdfsa3ovHb1H+qApwrxcTVo+NNdeJiB9V75hsKfrkG5AwNcRUNxrPPiScGYCNmLMoh8pg== - -"@fortawesome/fontawesome-common-types@6.5.1": - version "6.5.1" - resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.5.1.tgz#fdb1ec4952b689f5f7aa0bffe46180bb35490032" - integrity sha512-GkWzv+L6d2bI5f/Vk6ikJ9xtl7dfXtoRu3YGE6nq0p/FFqA1ebMOAWg3XgRyb0I6LYyYkiAo+3/KrwuBp8xG7A== - -"@fortawesome/fontawesome-common-types@^0.2.32": - version "0.2.32" - resolved "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.32.tgz" - integrity sha512-ux2EDjKMpcdHBVLi/eWZynnPxs0BtFVXJkgHIxXRl+9ZFaHPvYamAfCzeeQFqHRjuJtX90wVnMRaMQAAlctz3w== - -"@fortawesome/fontawesome-free@^5.15.1": - version "5.15.1" - resolved "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-5.15.1.tgz" - integrity sha512-OEdH7SyC1suTdhBGW91/zBfR6qaIhThbcN8PUXtXilY4GYnSBbVqOntdHbC1vXwsDnX0Qix2m2+DSU1J51ybOQ== - -"@fortawesome/fontawesome-svg-core@^1.2.32": - version "1.2.32" - resolved "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.32.tgz" - integrity sha512-XjqyeLCsR/c/usUpdWcOdVtWFVjPbDFBTQkn2fQRrWhhUoxriQohO2RWDxLyUM8XpD+Zzg5xwJ8gqTYGDLeGaQ== - dependencies: - "@fortawesome/fontawesome-common-types" "^0.2.32" - -"@fortawesome/free-regular-svg-icons@^6.5.1": - version "6.5.1" - resolved "https://registry.yarnpkg.com/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.5.1.tgz#c98a91d2c9137ed54a7aa2362a916f46503e0627" - integrity sha512-m6ShXn+wvqEU69wSP84coxLbNl7sGVZb+Ca+XZq6k30SzuP3X4TfPqtycgUh9ASwlNh5OfQCd8pDIWxl+O+LlQ== - dependencies: - "@fortawesome/fontawesome-common-types" "6.5.1" - -"@fortawesome/free-solid-svg-icons@^6.2.0": - version "6.2.0" - resolved "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.2.0.tgz" - integrity sha512-UjCILHIQ4I8cN46EiQn0CZL/h8AwCGgR//1c4R96Q5viSRwuKVo0NdQEc4bm+69ZwC0dUvjbDqAHF1RR5FA3XA== - dependencies: - "@fortawesome/fontawesome-common-types" "6.2.0" - -"@fortawesome/react-fontawesome@^0.1.13": - version "0.1.13" - resolved "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.13.tgz" - integrity sha512-/HrLnIft5Ks2511Pz6TxHBIctC9QalVscAC64sufQ4sJH/sXaQlG3uR9LCu6VpEwkBemgcBLrz/QPNP/ddbjDg== - dependencies: - prop-types "^15.7.2" - -"@gilbarbara/deep-equal@^0.1.1": - version "0.1.2" - resolved "https://registry.yarnpkg.com/@gilbarbara/deep-equal/-/deep-equal-0.1.2.tgz#1a106721368dba5e7e9fb7e9a3a6f9efbd8df36d" - integrity sha512-jk+qzItoEb0D0xSSmrKDDzf9sheQj/BAPxlgNxgmOaA3mxpUa6ndJLYGZKsJnIVEQSD8zcTbyILz7I0HcnBCRA== - -"@inline-svg-unique-id/react@^1.2.3": - version "1.2.3" - resolved "https://registry.yarnpkg.com/@inline-svg-unique-id/react/-/react-1.2.3.tgz#7b682183d1d2a4cb9e1ace10569c1d4b45589604" - integrity sha512-Tf6u4pTdkeN4BLuh4aHNFDrKxUoiNbCglou3IDem7x0KRCt/rrhRgLljx85X2k5aAUdLvDhQcpeKVePFarF+8w== - -"@istanbuljs/load-nyc-config@^1.0.0": - version "1.1.0" - resolved "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz" - integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== - dependencies: - camelcase "^5.3.1" - find-up "^4.1.0" - get-package-type "^0.1.0" - js-yaml "^3.13.1" - resolve-from "^5.0.0" - -"@istanbuljs/schema@^0.1.2": - version "0.1.2" - resolved "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz" - integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw== - -"@jest/console@^26.6.2": - version "26.6.2" - resolved "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz" - integrity sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g== - dependencies: - "@jest/types" "^26.6.2" - "@types/node" "*" - chalk "^4.0.0" - jest-message-util "^26.6.2" - jest-util "^26.6.2" - slash "^3.0.0" - -"@jest/core@^26.6.3": - version "26.6.3" - resolved "https://registry.npmjs.org/@jest/core/-/core-26.6.3.tgz" - integrity sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw== - dependencies: - "@jest/console" "^26.6.2" - "@jest/reporters" "^26.6.2" - "@jest/test-result" "^26.6.2" - "@jest/transform" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/node" "*" - ansi-escapes "^4.2.1" - chalk "^4.0.0" - exit "^0.1.2" - graceful-fs "^4.2.4" - jest-changed-files "^26.6.2" - jest-config "^26.6.3" - jest-haste-map "^26.6.2" - jest-message-util "^26.6.2" - jest-regex-util "^26.0.0" - jest-resolve "^26.6.2" - jest-resolve-dependencies "^26.6.3" - jest-runner "^26.6.3" - jest-runtime "^26.6.3" - jest-snapshot "^26.6.2" - jest-util "^26.6.2" - jest-validate "^26.6.2" - jest-watcher "^26.6.2" - micromatch "^4.0.2" - p-each-series "^2.1.0" - rimraf "^3.0.0" - slash "^3.0.0" - strip-ansi "^6.0.0" - -"@jest/environment@^26.6.2": - version "26.6.2" - resolved "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz" - integrity sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA== - dependencies: - "@jest/fake-timers" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/node" "*" - jest-mock "^26.6.2" - -"@jest/fake-timers@^26.6.2": - version "26.6.2" - resolved "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz" - integrity sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA== - dependencies: - "@jest/types" "^26.6.2" - "@sinonjs/fake-timers" "^6.0.1" - "@types/node" "*" - jest-message-util "^26.6.2" - jest-mock "^26.6.2" - jest-util "^26.6.2" - -"@jest/globals@^26.6.2": - version "26.6.2" - resolved "https://registry.npmjs.org/@jest/globals/-/globals-26.6.2.tgz" - integrity sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA== - dependencies: - "@jest/environment" "^26.6.2" - "@jest/types" "^26.6.2" - expect "^26.6.2" - -"@jest/reporters@^26.6.2": - version "26.6.2" - resolved "https://registry.npmjs.org/@jest/reporters/-/reporters-26.6.2.tgz" - integrity sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw== - dependencies: - "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^26.6.2" - "@jest/test-result" "^26.6.2" - "@jest/transform" "^26.6.2" - "@jest/types" "^26.6.2" - chalk "^4.0.0" - collect-v8-coverage "^1.0.0" - exit "^0.1.2" - glob "^7.1.2" - graceful-fs "^4.2.4" - istanbul-lib-coverage "^3.0.0" - istanbul-lib-instrument "^4.0.3" - istanbul-lib-report "^3.0.0" - istanbul-lib-source-maps "^4.0.0" - istanbul-reports "^3.0.2" - jest-haste-map "^26.6.2" - jest-resolve "^26.6.2" - jest-util "^26.6.2" - jest-worker "^26.6.2" - slash "^3.0.0" - source-map "^0.6.0" - string-length "^4.0.1" - terminal-link "^2.0.0" - v8-to-istanbul "^7.0.0" - optionalDependencies: - node-notifier "^8.0.0" - -"@jest/schemas@^29.6.0": - version "29.6.0" - resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.0.tgz#0f4cb2c8e3dca80c135507ba5635a4fd755b0040" - integrity sha512-rxLjXyJBTL4LQeJW3aKo0M/+GkCOXsO+8i9Iu7eDb6KwtP65ayoDsitrdPBtujxQ88k4wI2FNYfa6TOGwSn6cQ== - dependencies: - "@sinclair/typebox" "^0.27.8" - -"@jest/source-map@^26.6.2": - version "26.6.2" - resolved "https://registry.npmjs.org/@jest/source-map/-/source-map-26.6.2.tgz" - integrity sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA== - dependencies: - callsites "^3.0.0" - graceful-fs "^4.2.4" - source-map "^0.6.0" - -"@jest/test-result@^26.6.2": - version "26.6.2" - resolved "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz" - integrity sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ== - dependencies: - "@jest/console" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/istanbul-lib-coverage" "^2.0.0" - collect-v8-coverage "^1.0.0" - -"@jest/test-sequencer@^26.6.3": - version "26.6.3" - resolved "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz" - integrity sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw== - dependencies: - "@jest/test-result" "^26.6.2" - graceful-fs "^4.2.4" - jest-haste-map "^26.6.2" - jest-runner "^26.6.3" - jest-runtime "^26.6.3" - -"@jest/transform@^26.6.2": - version "26.6.2" - resolved "https://registry.npmjs.org/@jest/transform/-/transform-26.6.2.tgz" - integrity sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA== - dependencies: - "@babel/core" "^7.1.0" - "@jest/types" "^26.6.2" - babel-plugin-istanbul "^6.0.0" - chalk "^4.0.0" - convert-source-map "^1.4.0" - fast-json-stable-stringify "^2.0.0" - graceful-fs "^4.2.4" - jest-haste-map "^26.6.2" - jest-regex-util "^26.0.0" - jest-util "^26.6.2" - micromatch "^4.0.2" - pirates "^4.0.1" - slash "^3.0.0" - source-map "^0.6.1" - write-file-atomic "^3.0.0" - -"@jest/transform@^29.6.2": - version "29.6.2" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.6.2.tgz#522901ebbb211af08835bc3bcdf765ab778094e3" - integrity sha512-ZqCqEISr58Ce3U+buNFJYUktLJZOggfyvR+bZMaiV1e8B1SIvJbwZMrYz3gx/KAPn9EXmOmN+uB08yLCjWkQQg== - dependencies: - "@babel/core" "^7.11.6" - "@jest/types" "^29.6.1" - "@jridgewell/trace-mapping" "^0.3.18" - babel-plugin-istanbul "^6.1.1" - chalk "^4.0.0" - convert-source-map "^2.0.0" - fast-json-stable-stringify "^2.1.0" - graceful-fs "^4.2.9" - jest-haste-map "^29.6.2" - jest-regex-util "^29.4.3" - jest-util "^29.6.2" - micromatch "^4.0.4" - pirates "^4.0.4" - slash "^3.0.0" - write-file-atomic "^4.0.2" - -"@jest/types@^25.5.0": - version "25.5.0" - resolved "https://registry.npmjs.org/@jest/types/-/types-25.5.0.tgz" - integrity sha512-OXD0RgQ86Tu3MazKo8bnrkDRaDXXMGUqd+kTtLtK1Zb7CRzQcaSRPPPV37SvYTdevXEBVxe0HXylEjs8ibkmCw== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^1.1.1" - "@types/yargs" "^15.0.0" - chalk "^3.0.0" - -"@jest/types@^26.6.2": - version "26.6.2" - resolved "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz" - integrity sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^3.0.0" - "@types/node" "*" - "@types/yargs" "^15.0.0" - chalk "^4.0.0" - -"@jest/types@^29.6.1": - version "29.6.1" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.1.tgz#ae79080278acff0a6af5eb49d063385aaa897bf2" - integrity sha512-tPKQNMPuXgvdOn2/Lg9HNfUvjYVGolt04Hp03f5hAk878uwOLikN+JzeLY0HcVgKgFl9Hs3EIqpu3WX27XNhnw== - dependencies: - "@jest/schemas" "^29.6.0" - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^3.0.0" - "@types/node" "*" - "@types/yargs" "^17.0.8" - chalk "^4.0.0" - -"@jridgewell/gen-mapping@^0.1.0": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996" - integrity sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w== - dependencies: - "@jridgewell/set-array" "^1.0.0" - "@jridgewell/sourcemap-codec" "^1.4.10" - -"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": - version "0.3.2" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" - integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== - dependencies: - "@jridgewell/set-array" "^1.0.1" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.9" - -"@jridgewell/resolve-uri@3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" - integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== - -"@jridgewell/resolve-uri@^3.1.0": - version "3.1.1" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" - integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== - -"@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" - integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== - -"@jridgewell/source-map@^0.3.3": - version "0.3.5" - resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.5.tgz#a3bb4d5c6825aab0d281268f47f6ad5853431e91" - integrity sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ== - dependencies: - "@jridgewell/gen-mapping" "^0.3.0" - "@jridgewell/trace-mapping" "^0.3.9" - -"@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10": - version "1.4.14" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" - integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== - -"@jridgewell/sourcemap-codec@^1.4.14": - version "1.4.15" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" - integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== - -"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": - version "0.3.17" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz#793041277af9073b0951a7fe0f0d8c4c98c36985" - integrity sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g== - dependencies: - "@jridgewell/resolve-uri" "3.1.0" - "@jridgewell/sourcemap-codec" "1.4.14" - -"@jridgewell/trace-mapping@^0.3.18": - version "0.3.19" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz#f8a3249862f91be48d3127c3cfe992f79b4b8811" - integrity sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw== - dependencies: - "@jridgewell/resolve-uri" "^3.1.0" - "@jridgewell/sourcemap-codec" "^1.4.14" - -"@jridgewell/trace-mapping@^0.3.20": - version "0.3.25" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" - integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== - dependencies: - "@jridgewell/resolve-uri" "^3.1.0" - "@jridgewell/sourcemap-codec" "^1.4.14" - -"@kurkle/color@^0.3.0": - version "0.3.2" - resolved "https://registry.yarnpkg.com/@kurkle/color/-/color-0.3.2.tgz#5acd38242e8bde4f9986e7913c8fdf49d3aa199f" - integrity sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw== - -"@leichtgewicht/ip-codec@^2.0.1": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz#b2ac626d6cb9c8718ab459166d4bb405b8ffa78b" - integrity sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A== - -"@monaco-editor/loader@^1.5.0": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@monaco-editor/loader/-/loader-1.5.0.tgz#dcdbc7fe7e905690fb449bed1c251769f325c55d" - integrity sha512-hKoGSM+7aAc7eRTRjpqAZucPmoNOC4UUbknb/VNoTkEIkCPhqV8LfbsgM1webRM7S/z21eHEx9Fkwx8Z/C/+Xw== - dependencies: - state-local "^1.0.6" - -"@monaco-editor/react@^4.6.0": - version "4.7.0" - resolved "https://registry.yarnpkg.com/@monaco-editor/react/-/react-4.7.0.tgz#35a1ec01bfe729f38bfc025df7b7bac145602a60" - integrity sha512-cyzXQCtO47ydzxpQtCGSQGOC8Gk3ZUeBXFAxD+CWXYFo5OqZyZUonFl0DwUlTyAfRHntBfw2p3w4s9R6oe1eCA== - dependencies: - "@monaco-editor/loader" "^1.5.0" - -"@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents.3": - version "2.1.8-no-fsevents.3" - resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz#323d72dd25103d0c4fbdce89dadf574a787b1f9b" - integrity sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ== - -"@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1": - version "5.1.1-v1" - resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz#dbf733a965ca47b1973177dc0bb6c889edcfb129" - integrity sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg== - dependencies: - eslint-scope "5.1.1" - -"@nodelib/fs.scandir@2.1.3": - version "2.1.3" - resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz" - integrity sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw== - dependencies: - "@nodelib/fs.stat" "2.0.3" - run-parallel "^1.1.9" - -"@nodelib/fs.stat@2.0.3", "@nodelib/fs.stat@^2.0.2": - version "2.0.3" - resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz" - integrity sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA== - -"@nodelib/fs.walk@^1.2.3": - version "1.2.4" - resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz" - integrity sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ== - dependencies: - "@nodelib/fs.scandir" "2.1.3" - fastq "^1.6.0" - -"@pmmmwh/react-refresh-webpack-plugin@^0.5.11": - version "0.5.11" - resolved "https://registry.yarnpkg.com/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.11.tgz#7c2268cedaa0644d677e8c4f377bc8fb304f714a" - integrity sha512-7j/6vdTym0+qZ6u4XbSAxrWBGYSdCfTzySkj7WAFgDLmSyWlOrWvpyzxlFh5jtw9dn0oL/jtW+06XfFiisN3JQ== - dependencies: - ansi-html-community "^0.0.8" - common-path-prefix "^3.0.0" - core-js-pure "^3.23.3" - error-stack-parser "^2.0.6" - find-up "^5.0.0" - html-entities "^2.1.0" - loader-utils "^2.0.4" - schema-utils "^3.0.0" - source-map "^0.7.3" - -"@polka/url@^1.0.0-next.20": - version "1.0.0-next.21" - resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1" - integrity sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g== - -"@popperjs/core@^2.11.6": - version "2.11.8" - resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f" - integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A== - -"@reduxjs/toolkit@^1.6.2": - version "1.6.2" - resolved "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.6.2.tgz" - integrity sha512-HbfI/hOVrAcMGAYsMWxw3UJyIoAS9JTdwddsjlr5w3S50tXhWb+EMyhIw+IAvCVCLETkzdjgH91RjDSYZekVBA== - dependencies: - immer "^9.0.6" - redux "^4.1.0" - redux-thunk "^2.3.0" - reselect "^4.0.0" - -"@restart/context@^2.1.4": - version "2.1.4" - resolved "https://registry.npmjs.org/@restart/context/-/context-2.1.4.tgz" - integrity sha512-INJYZQJP7g+IoDUh/475NlGiTeMfwTXUEr3tmRneckHIxNolGOW9CTq83S8cxq0CgJwwcMzMJFchxvlwe7Rk8Q== - -"@restart/hooks@^0.4.7": - version "0.4.11" - resolved "https://registry.yarnpkg.com/@restart/hooks/-/hooks-0.4.11.tgz#8876ccce1d4ad2a4b793a31689d63df36cf56088" - integrity sha512-Ft/ncTULZN6ldGHiF/k5qt72O8JyRMOeg0tApvCni8LkoiEahO+z3TNxfXIVGy890YtWVDvJAl662dVJSJXvMw== - dependencies: - dequal "^2.0.3" - -"@sentry-internal/browser-utils@8.4.0": - version "8.4.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/browser-utils/-/browser-utils-8.4.0.tgz#5b108878e93713757d75e7e8ae7780297d36ad17" - integrity sha512-Mfm3TK3KUlghhuKM3rjTeD4D5kAiB7iVNFoaDJIJBVKa67M9BvlNTnNJMDi7+9rV4RuLQYxXn0p5HEZJFYp3Zw== - dependencies: - "@sentry/core" "8.4.0" - "@sentry/types" "8.4.0" - "@sentry/utils" "8.4.0" - -"@sentry-internal/feedback@8.4.0": - version "8.4.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/feedback/-/feedback-8.4.0.tgz#81067dadda249b354b72f5adba20374dea43fdf4" - integrity sha512-1/WshI2X9seZAQXrOiv6/LU08fbSSvJU0b1ZWMhn+onb/FWPomsL/UN0WufCYA65S5JZGdaWC8fUcJxWC8PATQ== - dependencies: - "@sentry/core" "8.4.0" - "@sentry/types" "8.4.0" - "@sentry/utils" "8.4.0" - -"@sentry-internal/replay-canvas@8.4.0": - version "8.4.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/replay-canvas/-/replay-canvas-8.4.0.tgz#cf5e903d8935ba6b60a5027d0055902987353920" - integrity sha512-g+U4IPQdODCg7fQQVNvH6ix05Tl1mOQXXRexgtp+tXdys4sHQSBUYraJYZy+mY3OGnLRgKFqELM0fnffJSpuyQ== - dependencies: - "@sentry-internal/replay" "8.4.0" - "@sentry/core" "8.4.0" - "@sentry/types" "8.4.0" - "@sentry/utils" "8.4.0" - -"@sentry-internal/replay@8.4.0": - version "8.4.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/replay/-/replay-8.4.0.tgz#8fc4a6bf1d5f480fcde2d56cd75042953e44efda" - integrity sha512-RSzQwCF/QTi5/5XAuj0VJImAhu4MheeHYvAbr/PuMSF4o1j89gBA7e3boA4u8633IqUeu5w3S5sb6jVrKaVifg== - dependencies: - "@sentry-internal/browser-utils" "8.4.0" - "@sentry/core" "8.4.0" - "@sentry/types" "8.4.0" - "@sentry/utils" "8.4.0" - -"@sentry/browser@8.4.0": - version "8.4.0" - resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-8.4.0.tgz#f4aa381eab212432d71366884693a36c2e3a1675" - integrity sha512-hmXeIZBdN0A6yCuoMTcigGxLl42nbeb205fXtouwE7Maa0qM2HM+Ijq0sHzbhxR3zU0JXDtcJh1k6wtJOREJ3g== - dependencies: - "@sentry-internal/browser-utils" "8.4.0" - "@sentry-internal/feedback" "8.4.0" - "@sentry-internal/replay" "8.4.0" - "@sentry-internal/replay-canvas" "8.4.0" - "@sentry/core" "8.4.0" - "@sentry/types" "8.4.0" - "@sentry/utils" "8.4.0" - -"@sentry/core@8.4.0": - version "8.4.0" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-8.4.0.tgz#ab3f7202f3cae82daf4c3c408f50d2c6fb913620" - integrity sha512-0eACPlJvKloFIlcT1c/vjGnvqxLxpGyGuSsU7uonrkmBqIRwLYXWtR4PoHapysKtjPVoHAn9au50ut6ymC2V8Q== - dependencies: - "@sentry/types" "8.4.0" - "@sentry/utils" "8.4.0" - -"@sentry/react@^8.4.0": - version "8.4.0" - resolved "https://registry.yarnpkg.com/@sentry/react/-/react-8.4.0.tgz#95f4fed03709b231770a4f32d3c960c544b0dc3c" - integrity sha512-YnDN+szKFm1fQ9311nAulsRbboeMbqNmosMLA6PweBDEwD0HEJsovQT+ZJxXiOL220qsgWVJzk+aTPtf+oY4wA== - dependencies: - "@sentry/browser" "8.4.0" - "@sentry/core" "8.4.0" - "@sentry/types" "8.4.0" - "@sentry/utils" "8.4.0" - hoist-non-react-statics "^3.3.2" - -"@sentry/types@8.4.0": - version "8.4.0" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-8.4.0.tgz#42500005a198ff8c247490434ed55e0a9f975ad1" - integrity sha512-mHUaaYEQCNukzYsTLp4rP2NNO17vUf+oSGS6qmhrsGqmGNICKw2CIwJlPPGeAkq9Y4tiUOye2m5OT1xsOtxLIw== - -"@sentry/utils@8.4.0": - version "8.4.0" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-8.4.0.tgz#1b816e65d8dbf055c5e1554361aaf9a8a8a94102" - integrity sha512-oDF0RVWW0AyEnsP1x4McHUvQSAxJgx3G6wM9Sb4wc1F8rwsHnCtGHc+WRZ5Gd2AXC5EGkfbg5919+1ku/L4Dww== - dependencies: - "@sentry/types" "8.4.0" - -"@sinclair/typebox@^0.27.8": - version "0.27.8" - resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" - integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== - -"@sindresorhus/is@^0.7.0": - version "0.7.0" - resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz" - integrity sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow== - -"@sinonjs/commons@^1.7.0": - version "1.8.1" - resolved "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.1.tgz" - integrity sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw== - dependencies: - type-detect "4.0.8" - -"@sinonjs/fake-timers@^6.0.1": - version "6.0.1" - resolved "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz" - integrity sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA== - dependencies: - "@sinonjs/commons" "^1.7.0" - -"@testing-library/dom@^9.0.0": - version "9.3.1" - resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-9.3.1.tgz#8094f560e9389fb973fe957af41bf766937a9ee9" - integrity sha512-0DGPd9AR3+iDTjGoMpxIkAsUihHZ3Ai6CneU6bRRrffXMgzCdlNk43jTrD2/5LT6CBb3MWTP8v510JzYtahD2w== - dependencies: - "@babel/code-frame" "^7.10.4" - "@babel/runtime" "^7.12.5" - "@types/aria-query" "^5.0.1" - aria-query "5.1.3" - chalk "^4.1.0" - dom-accessibility-api "^0.5.9" - lz-string "^1.5.0" - pretty-format "^27.0.2" - -"@testing-library/jest-dom@^5.17.0": - version "5.17.0" - resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-5.17.0.tgz#5e97c8f9a15ccf4656da00fecab505728de81e0c" - integrity sha512-ynmNeT7asXyH3aSVv4vvX4Rb+0qjOhdNHnO/3vuZNqPmhDpV/+rCSGwQ7bLcmU2cJ4dvoheIO85LQj0IbJHEtg== - dependencies: - "@adobe/css-tools" "^4.0.1" - "@babel/runtime" "^7.9.2" - "@types/testing-library__jest-dom" "^5.9.1" - aria-query "^5.0.0" - chalk "^3.0.0" - css.escape "^1.5.1" - dom-accessibility-api "^0.5.6" - lodash "^4.17.15" - redent "^3.0.0" - -"@testing-library/react@^14.0.0": - version "14.0.0" - resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-14.0.0.tgz#59030392a6792450b9ab8e67aea5f3cc18d6347c" - integrity sha512-S04gSNJbYE30TlIMLTzv6QCTzt9AqIF5y6s6SzVFILNcNvbV/jU96GeiTPillGQo+Ny64M/5PV7klNYYgv5Dfg== - dependencies: - "@babel/runtime" "^7.12.5" - "@testing-library/dom" "^9.0.0" - "@types/react-dom" "^18.0.0" - -"@testing-library/user-event@^14.4.3": - version "14.4.3" - resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-14.4.3.tgz#af975e367743fa91989cd666666aec31a8f50591" - integrity sha512-kCUc5MEwaEMakkO5x7aoD+DLi02ehmEM2QCGWvNqAS1dV/fAvORWEjnjsEIvml59M7Y5kCkWN6fCCyPOe8OL6Q== - -"@tootallnate/once@1": - version "1.1.2" - resolved "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz" - integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== - -"@trysound/sax@0.2.0": - version "0.2.0" - resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" - integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== - -"@types/aria-query@^5.0.1": - version "5.0.1" - resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-5.0.1.tgz#3286741fb8f1e1580ac28784add4c7a1d49bdfbc" - integrity sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q== - -"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.7": - version "7.1.9" - resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.9.tgz" - integrity sha512-sY2RsIJ5rpER1u3/aQ8OFSI7qGIy8o1NEEbgb2UaJcvOtXOMpd39ko723NBpjQFg9SIX7TXtjejZVGeIMLhoOw== - dependencies: - "@babel/parser" "^7.1.0" - "@babel/types" "^7.0.0" - "@types/babel__generator" "*" - "@types/babel__template" "*" - "@types/babel__traverse" "*" - -"@types/babel__core@^7.1.14": - version "7.20.1" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.1.tgz#916ecea274b0c776fec721e333e55762d3a9614b" - integrity sha512-aACu/U/omhdk15O4Nfb+fHgH/z3QsfQzpnvRZhYhThms83ZnAOZz7zZAWO7mn2yyNQaA4xTO8GLK3uqFU4bYYw== - dependencies: - "@babel/parser" "^7.20.7" - "@babel/types" "^7.20.7" - "@types/babel__generator" "*" - "@types/babel__template" "*" - "@types/babel__traverse" "*" - -"@types/babel__generator@*": - version "7.6.1" - resolved "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.1.tgz" - integrity sha512-bBKm+2VPJcMRVwNhxKu8W+5/zT7pwNEqeokFOmbvVSqGzFneNxYcEBro9Ac7/N9tlsaPYnZLK8J1LWKkMsLAew== - dependencies: - "@babel/types" "^7.0.0" - -"@types/babel__template@*": - version "7.0.2" - resolved "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.0.2.tgz" - integrity sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg== - dependencies: - "@babel/parser" "^7.1.0" - "@babel/types" "^7.0.0" - -"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": - version "7.0.13" - resolved "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.13.tgz" - integrity sha512-i+zS7t6/s9cdQvbqKDARrcbrPvtJGlbYsMkazo03nTAK3RX9FNrLllXys22uiTGJapPOTZTQ35nHh4ISph4SLQ== - dependencies: - "@babel/types" "^7.3.0" - -"@types/babel__traverse@^7.0.4": - version "7.0.16" - resolved "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.16.tgz" - integrity sha512-S63Dt4CZOkuTmpLGGWtT/mQdVORJOpx6SZWGVaP56dda/0Nx5nEe82K7/LAm8zYr6SfMq+1N2OreIOrHAx656w== - dependencies: - "@babel/types" "^7.3.0" - -"@types/body-parser@*": - version "1.19.2" - resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0" - integrity sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g== - dependencies: - "@types/connect" "*" - "@types/node" "*" - -"@types/bonjour@^3.5.9": - version "3.5.10" - resolved "https://registry.yarnpkg.com/@types/bonjour/-/bonjour-3.5.10.tgz#0f6aadfe00ea414edc86f5d106357cda9701e275" - integrity sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw== - dependencies: - "@types/node" "*" - -"@types/connect-history-api-fallback@^1.3.5": - version "1.3.5" - resolved "https://registry.yarnpkg.com/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz#d1f7a8a09d0ed5a57aee5ae9c18ab9b803205dae" - integrity sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw== - dependencies: - "@types/express-serve-static-core" "*" - "@types/node" "*" - -"@types/connect@*": - version "3.4.35" - resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" - integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ== - dependencies: - "@types/node" "*" - -"@types/d3-color@^2": - version "2.0.3" - resolved "https://registry.npmjs.org/@types/d3-color/-/d3-color-2.0.3.tgz" - integrity sha512-+0EtEjBfKEDtH9Rk3u3kLOUXM5F+iZK+WvASPb0MhIZl8J8NUvGeZRwKCXl+P3HkYx5TdU4YtcibpqHkSR9n7w== - -"@types/d3-interpolate@^2.0.0": - version "2.0.2" - resolved "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-2.0.2.tgz" - integrity sha512-lElyqlUfIPyWG/cD475vl6msPL4aMU7eJvx1//Q177L8mdXoVPFl1djIESF2FKnc0NyaHvQlJpWwKJYwAhUoCw== - dependencies: - "@types/d3-color" "^2" - -"@types/d3-path@^2": - version "2.0.2" - resolved "https://registry.npmjs.org/@types/d3-path/-/d3-path-2.0.2.tgz" - integrity sha512-3YHpvDw9LzONaJzejXLOwZ3LqwwkoXb9LI2YN7Hbd6pkGo5nIlJ09ul4bQhBN4hQZJKmUpX8HkVqbzgUKY48cg== - -"@types/d3-scale@^3.0.0": - version "3.3.2" - resolved "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-3.3.2.tgz" - integrity sha512-gGqr7x1ost9px3FvIfUMi5XA/F/yAf4UkUDtdQhpH92XCT0Oa7zkkRzY61gPVJq+DxpHn/btouw5ohWkbBsCzQ== - dependencies: - "@types/d3-time" "^2" - -"@types/d3-shape@^2.0.0": - version "2.1.3" - resolved "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-2.1.3.tgz" - integrity sha512-HAhCel3wP93kh4/rq+7atLdybcESZ5bRHDEZUojClyZWsRuEMo3A52NGYJSh48SxfxEU6RZIVbZL2YFZ2OAlzQ== - dependencies: - "@types/d3-path" "^2" - -"@types/d3-time@^2": - version "2.1.1" - resolved "https://registry.npmjs.org/@types/d3-time/-/d3-time-2.1.1.tgz" - integrity sha512-9MVYlmIgmRR31C5b4FVSWtuMmBHh2mOWQYfl7XAYOa8dsnb7iEmUmRSWSFgXFtkjxO65d7hTUHQC+RhR/9IWFg== - -"@types/debug@^4.0.0": - version "4.1.12" - resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.12.tgz#a155f21690871953410df4b6b6f53187f0500917" - integrity sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ== - dependencies: - "@types/ms" "*" - -"@types/estree-jsx@^1.0.0": - version "1.0.5" - resolved "https://registry.yarnpkg.com/@types/estree-jsx/-/estree-jsx-1.0.5.tgz#858a88ea20f34fe65111f005a689fa1ebf70dc18" - integrity sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg== - dependencies: - "@types/estree" "*" - -"@types/estree@*", "@types/estree@^1.0.0", "@types/estree@^1.0.5": - version "1.0.5" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" - integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== - -"@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.33": - version "4.17.33" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz#de35d30a9d637dc1450ad18dd583d75d5733d543" - integrity sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA== - dependencies: - "@types/node" "*" - "@types/qs" "*" - "@types/range-parser" "*" - -"@types/express@*", "@types/express@^4.17.13": - version "4.17.17" - resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.17.tgz#01d5437f6ef9cfa8668e616e13c2f2ac9a491ae4" - integrity sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q== - dependencies: - "@types/body-parser" "*" - "@types/express-serve-static-core" "^4.17.33" - "@types/qs" "*" - "@types/serve-static" "*" - -"@types/glob@^7.1.1": - version "7.1.3" - resolved "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz" - integrity sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w== - dependencies: - "@types/minimatch" "*" - "@types/node" "*" - -"@types/graceful-fs@^4.1.2": - version "4.1.3" - resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.3.tgz" - integrity sha512-AiHRaEB50LQg0pZmm659vNBb9f4SJ0qrAnteuzhSeAUcJKxoYgEnprg/83kppCnc2zvtCKbdZry1a5pVY3lOTQ== - dependencies: - "@types/node" "*" - -"@types/graceful-fs@^4.1.3": - version "4.1.6" - resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.6.tgz#e14b2576a1c25026b7f02ede1de3b84c3a1efeae" - integrity sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw== - dependencies: - "@types/node" "*" - -"@types/hast@^3.0.0": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@types/hast/-/hast-3.0.4.tgz#1d6b39993b82cea6ad783945b0508c25903e15aa" - integrity sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ== - dependencies: - "@types/unist" "*" - -"@types/hoist-non-react-statics@^3.3.1": - version "3.3.1" - resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" - integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA== - dependencies: - "@types/react" "*" - hoist-non-react-statics "^3.3.0" - -"@types/http-proxy@^1.17.8": - version "1.17.10" - resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.10.tgz#e576c8e4a0cc5c6a138819025a88e167ebb38d6c" - integrity sha512-Qs5aULi+zV1bwKAg5z1PWnDXWmsn+LxIvUGv6E2+OOMYhclZMO+OXd9pYVf2gLykf2I7IV2u7oTHwChPNsvJ7g== - dependencies: - "@types/node" "*" - -"@types/invariant@^2.2.33": - version "2.2.33" - resolved "https://registry.npmjs.org/@types/invariant/-/invariant-2.2.33.tgz" - integrity sha512-/jUNmS8d4bCKdqslfxW6dg/9Gksfzxz67IYfqApHn+HvHlMVXwYv2zpTDnS/yaK9BB0i0GlBTaYci0EFE62Hmw== - -"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": - version "2.0.3" - resolved "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz" - integrity sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw== - -"@types/istanbul-lib-report@*": - version "3.0.0" - resolved "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz" - integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== - dependencies: - "@types/istanbul-lib-coverage" "*" - -"@types/istanbul-reports@^1.1.1": - version "1.1.2" - resolved "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz" - integrity sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw== - dependencies: - "@types/istanbul-lib-coverage" "*" - "@types/istanbul-lib-report" "*" - -"@types/istanbul-reports@^3.0.0": - version "3.0.0" - resolved "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz" - integrity sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA== - dependencies: - "@types/istanbul-lib-report" "*" - -"@types/jest@*": - version "26.0.4" - resolved "https://registry.npmjs.org/@types/jest/-/jest-26.0.4.tgz" - integrity sha512-4fQNItvelbNA9+sFgU+fhJo8ZFF+AS4Egk3GWwCW2jFtViukXbnztccafAdLhzE/0EiCogljtQQXP8aQ9J7sFg== - dependencies: - jest-diff "^25.2.1" - pretty-format "^25.2.1" - -"@types/json-schema@^7.0.3": - version "7.0.6" - resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz" - integrity sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw== - -"@types/json-schema@^7.0.5": - version "7.0.12" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb" - integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA== - -"@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": - version "7.0.11" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" - integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== - -"@types/json5@^0.0.29": - version "0.0.29" - resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz" - integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= - -"@types/katex@^0.16.0": - version "0.16.7" - resolved "https://registry.yarnpkg.com/@types/katex/-/katex-0.16.7.tgz#03ab680ab4fa4fbc6cb46ecf987ecad5d8019868" - integrity sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ== - -"@types/mdast@^4.0.0": - version "4.0.4" - resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-4.0.4.tgz#7ccf72edd2f1aa7dd3437e180c64373585804dd6" - integrity sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA== - dependencies: - "@types/unist" "*" - -"@types/mime@*": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.1.tgz#5f8f2bca0a5863cb69bc0b0acd88c96cb1d4ae10" - integrity sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA== - -"@types/minimatch@*": - version "3.0.3" - resolved "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz" - integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== - -"@types/ms@*": - version "0.7.34" - resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.34.tgz#10964ba0dee6ac4cd462e2795b6bebd407303433" - integrity sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g== - -"@types/node@*": - version "14.0.23" - resolved "https://registry.npmjs.org/@types/node/-/node-14.0.23.tgz" - integrity sha512-Z4U8yDAl5TFkmYsZdFPdjeMa57NOvnaf1tljHzhouaPEp7LCj2JKkejpI1ODviIAQuW4CcQmxkQ77rnLsOOoKw== - -"@types/normalize-package-data@^2.4.0": - version "2.4.0" - resolved "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz" - integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA== - -"@types/parse-json@^4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz" - integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== - -"@types/prettier@^2.0.0": - version "2.0.2" - resolved "https://registry.npmjs.org/@types/prettier/-/prettier-2.0.2.tgz" - integrity sha512-IkVfat549ggtkZUthUzEX49562eGikhSYeVGX97SkMFn+sTZrgRewXjQ4tPKFPCykZHkX1Zfd9OoELGqKU2jJA== - -"@types/prop-types@*": - version "15.7.13" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.13.tgz#2af91918ee12d9d32914feb13f5326658461b451" - integrity sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA== - -"@types/prop-types@^15.7.3": - version "15.7.3" - resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz" - integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw== - -"@types/qs@*": - version "6.9.7" - resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" - integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== - -"@types/range-parser@*": - version "1.2.4" - resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" - integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== - -"@types/react-dom@^18.0.0": - version "18.2.7" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.7.tgz#67222a08c0a6ae0a0da33c3532348277c70abb63" - integrity sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA== - dependencies: - "@types/react" "*" - -"@types/react-transition-group@^4.4.0": - version "4.4.0" - resolved "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.0.tgz" - integrity sha512-/QfLHGpu+2fQOqQaXh8MG9q03bFENooTb/it4jr5kKaZlDQfWvjqWZg48AwzPVMBHlRuTRAY7hRHCEOXz5kV6w== - dependencies: - "@types/react" "*" - -"@types/react-transition-group@^4.4.1": - version "4.4.6" - resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.6.tgz#18187bcda5281f8e10dfc48f0943e2fdf4f75e2e" - integrity sha512-VnCdSxfcm08KjsJVQcfBmhEQAPnLB8G08hAxn39azX1qYBQ/5RVQuoHuKIcfKOdncuaUvEpFKFzEvbtIMsfVew== - dependencies: - "@types/react" "*" - -"@types/react@*": - version "16.9.43" - resolved "https://registry.npmjs.org/@types/react/-/react-16.9.43.tgz" - integrity sha512-PxshAFcnJqIWYpJbLPriClH53Z2WlJcVZE+NP2etUtWQs2s7yIMj3/LDKZT/5CHJ/F62iyjVCDu2H3jHEXIxSg== - dependencies: - "@types/prop-types" "*" - csstype "^2.2.0" - -"@types/react@>=16.14.8", "@types/react@>=16.9.11": - version "18.2.20" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.20.tgz#1605557a83df5c8a2cc4eeb743b3dfc0eb6aaeb2" - integrity sha512-WKNtmsLWJM/3D5mG4U84cysVY31ivmyw85dE84fOCk5Hx78wezB/XEjVPWl2JTZ5FkEeaTJf+VgUAUn3PE7Isw== - dependencies: - "@types/prop-types" "*" - "@types/scheduler" "*" - csstype "^3.0.2" - -"@types/retry@0.12.0": - version "0.12.0" - resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d" - integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA== - -"@types/scheduler@*": - version "0.16.3" - resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.3.tgz#cef09e3ec9af1d63d2a6cc5b383a737e24e6dcf5" - integrity sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ== - -"@types/serve-index@^1.9.1": - version "1.9.1" - resolved "https://registry.yarnpkg.com/@types/serve-index/-/serve-index-1.9.1.tgz#1b5e85370a192c01ec6cec4735cf2917337a6278" - integrity sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg== - dependencies: - "@types/express" "*" - -"@types/serve-static@*", "@types/serve-static@^1.13.10": - version "1.15.1" - resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.1.tgz#86b1753f0be4f9a1bee68d459fcda5be4ea52b5d" - integrity sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ== - dependencies: - "@types/mime" "*" - "@types/node" "*" - -"@types/sockjs@^0.3.33": - version "0.3.33" - resolved "https://registry.yarnpkg.com/@types/sockjs/-/sockjs-0.3.33.tgz#570d3a0b99ac995360e3136fd6045113b1bd236f" - integrity sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw== - dependencies: - "@types/node" "*" - -"@types/stack-utils@^2.0.0": - version "2.0.0" - resolved "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz" - integrity sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw== - -"@types/testing-library__jest-dom@^5.9.1": - version "5.9.1" - resolved "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.9.1.tgz" - integrity sha512-yYn5EKHO3MPEMSOrcAb1dLWY+68CG29LiXKsWmmpVHqoP5+ZRiAVLyUHvPNrO2dABDdUGZvavMsaGpWNjM6N2g== - dependencies: - "@types/jest" "*" - -"@types/unist@*", "@types/unist@^3.0.0": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@types/unist/-/unist-3.0.2.tgz#6dd61e43ef60b34086287f83683a5c1b2dc53d20" - integrity sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ== - -"@types/unist@^2.0.0": - version "2.0.10" - resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.10.tgz#04ffa7f406ab628f7f7e97ca23e290cd8ab15efc" - integrity sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA== - -"@types/use-sync-external-store@^0.0.3": - version "0.0.3" - resolved "https://registry.yarnpkg.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz#b6725d5f4af24ace33b36fafd295136e75509f43" - integrity sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA== - -"@types/warning@^3.0.0": - version "3.0.0" - resolved "https://registry.npmjs.org/@types/warning/-/warning-3.0.0.tgz" - integrity sha1-DSUBJorY+ZYrdA04fEZU9fjiPlI= - -"@types/ws@^8.5.5": - version "8.5.5" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.5.tgz#af587964aa06682702ee6dcbc7be41a80e4b28eb" - integrity sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg== - dependencies: - "@types/node" "*" - -"@types/yargs-parser@*": - version "15.0.0" - resolved "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-15.0.0.tgz" - integrity sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw== - -"@types/yargs@^15.0.0": - version "15.0.10" - resolved "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.10.tgz" - integrity sha512-z8PNtlhrj7eJNLmrAivM7rjBESG6JwC5xP3RVk12i/8HVP7Xnx/sEmERnRImyEuUaJfO942X0qMOYsoupaJbZQ== - dependencies: - "@types/yargs-parser" "*" - -"@types/yargs@^17.0.8": - version "17.0.22" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.22.tgz#7dd37697691b5f17d020f3c63e7a45971ff71e9a" - integrity sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g== - dependencies: - "@types/yargs-parser" "*" - -"@typescript-eslint/experimental-utils@^2.5.0": - version "2.34.0" - resolved "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.34.0.tgz" - integrity sha512-eS6FTkq+wuMJ+sgtuNTtcqavWXqsflWcfBnlYhg/nS4aZ1leewkXGbvBhaapn1q6qf4M71bsR1tez5JTRMuqwA== - dependencies: - "@types/json-schema" "^7.0.3" - "@typescript-eslint/typescript-estree" "2.34.0" - eslint-scope "^5.0.0" - eslint-utils "^2.0.0" - -"@typescript-eslint/typescript-estree@2.34.0": - version "2.34.0" - resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz" - integrity sha512-OMAr+nJWKdlVM9LOqCqh3pQQPwxHAN7Du8DR6dmwCrAmxtiXQnhHJ6tBNtf+cggqfo51SG/FCwnKhXCIM7hnVg== - dependencies: - debug "^4.1.1" - eslint-visitor-keys "^1.1.0" - glob "^7.1.6" - is-glob "^4.0.1" - lodash "^4.17.15" - semver "^7.3.2" - tsutils "^3.17.1" - -"@ungap/structured-clone@^1.0.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" - integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== - -"@webassemblyjs/ast@1.12.1", "@webassemblyjs/ast@^1.12.1": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.12.1.tgz#bb16a0e8b1914f979f45864c23819cc3e3f0d4bb" - integrity sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg== - dependencies: - "@webassemblyjs/helper-numbers" "1.11.6" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - -"@webassemblyjs/floating-point-hex-parser@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz#dacbcb95aff135c8260f77fa3b4c5fea600a6431" - integrity sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw== - -"@webassemblyjs/helper-api-error@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz#6132f68c4acd59dcd141c44b18cbebbd9f2fa768" - integrity sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q== - -"@webassemblyjs/helper-buffer@1.12.1": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz#6df20d272ea5439bf20ab3492b7fb70e9bfcb3f6" - integrity sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw== - -"@webassemblyjs/helper-numbers@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz#cbce5e7e0c1bd32cf4905ae444ef64cea919f1b5" - integrity sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g== - dependencies: - "@webassemblyjs/floating-point-hex-parser" "1.11.6" - "@webassemblyjs/helper-api-error" "1.11.6" - "@xtuc/long" "4.2.2" - -"@webassemblyjs/helper-wasm-bytecode@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz#bb2ebdb3b83aa26d9baad4c46d4315283acd51e9" - integrity sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA== - -"@webassemblyjs/helper-wasm-section@1.12.1": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz#3da623233ae1a60409b509a52ade9bc22a37f7bf" - integrity sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g== - dependencies: - "@webassemblyjs/ast" "1.12.1" - "@webassemblyjs/helper-buffer" "1.12.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/wasm-gen" "1.12.1" - -"@webassemblyjs/ieee754@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz#bb665c91d0b14fffceb0e38298c329af043c6e3a" - integrity sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg== - dependencies: - "@xtuc/ieee754" "^1.2.0" - -"@webassemblyjs/leb128@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.6.tgz#70e60e5e82f9ac81118bc25381a0b283893240d7" - integrity sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ== - dependencies: - "@xtuc/long" "4.2.2" - -"@webassemblyjs/utf8@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.6.tgz#90f8bc34c561595fe156603be7253cdbcd0fab5a" - integrity sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA== - -"@webassemblyjs/wasm-edit@^1.12.1": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz#9f9f3ff52a14c980939be0ef9d5df9ebc678ae3b" - integrity sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g== - dependencies: - "@webassemblyjs/ast" "1.12.1" - "@webassemblyjs/helper-buffer" "1.12.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/helper-wasm-section" "1.12.1" - "@webassemblyjs/wasm-gen" "1.12.1" - "@webassemblyjs/wasm-opt" "1.12.1" - "@webassemblyjs/wasm-parser" "1.12.1" - "@webassemblyjs/wast-printer" "1.12.1" - -"@webassemblyjs/wasm-gen@1.12.1": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz#a6520601da1b5700448273666a71ad0a45d78547" - integrity sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w== - dependencies: - "@webassemblyjs/ast" "1.12.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/ieee754" "1.11.6" - "@webassemblyjs/leb128" "1.11.6" - "@webassemblyjs/utf8" "1.11.6" - -"@webassemblyjs/wasm-opt@1.12.1": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz#9e6e81475dfcfb62dab574ac2dda38226c232bc5" - integrity sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg== - dependencies: - "@webassemblyjs/ast" "1.12.1" - "@webassemblyjs/helper-buffer" "1.12.1" - "@webassemblyjs/wasm-gen" "1.12.1" - "@webassemblyjs/wasm-parser" "1.12.1" - -"@webassemblyjs/wasm-parser@1.12.1", "@webassemblyjs/wasm-parser@^1.12.1": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz#c47acb90e6f083391e3fa61d113650eea1e95937" - integrity sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ== - dependencies: - "@webassemblyjs/ast" "1.12.1" - "@webassemblyjs/helper-api-error" "1.11.6" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/ieee754" "1.11.6" - "@webassemblyjs/leb128" "1.11.6" - "@webassemblyjs/utf8" "1.11.6" - -"@webassemblyjs/wast-printer@1.12.1": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz#bcecf661d7d1abdaf989d8341a4833e33e2b31ac" - integrity sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA== - dependencies: - "@webassemblyjs/ast" "1.12.1" - "@xtuc/long" "4.2.2" - -"@webpack-cli/configtest@^2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-2.1.1.tgz#3b2f852e91dac6e3b85fb2a314fb8bef46d94646" - integrity sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw== - -"@webpack-cli/info@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-2.0.2.tgz#cc3fbf22efeb88ff62310cf885c5b09f44ae0fdd" - integrity sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A== - -"@webpack-cli/serve@^2.0.5": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-2.0.5.tgz#325db42395cd49fe6c14057f9a900e427df8810e" - integrity sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ== - -"@xstate/graph@^2.0.0-alpha.1": - version "2.0.0-alpha.2" - resolved "https://registry.yarnpkg.com/@xstate/graph/-/graph-2.0.0-alpha.2.tgz#3b04aa3d36dc5de181145d31d04801a8a3a93d6e" - integrity sha512-7jqRqt5Sh+vR4olCq9JpGij5vWUKaN+EBEYvECg8fLnLYC9ULbXw7HjPpVk6Rq3aR6RWkBfc5JUDt8ib1x/rUA== - -"@xstate/inspect@^0.8.0": - version "0.8.0" - resolved "https://registry.yarnpkg.com/@xstate/inspect/-/inspect-0.8.0.tgz#f99d3706cd823d4922c47ce4f4376eecac502cc7" - integrity sha512-wSkFeOnp+7dhn+zTThO0M4D2FEqZN9lGIWowJu5JLa2ojjtlzRwK8SkjcHZ4rLX8VnMev7kGjgQLrGs8kxy+hw== - dependencies: - fast-safe-stringify "^2.1.1" - -"@xstate/react@^3.2.2": - version "3.2.2" - resolved "https://registry.yarnpkg.com/@xstate/react/-/react-3.2.2.tgz#ddf0f9d75e2c19375b1e1b7335e72cb99762aed8" - integrity sha512-feghXWLedyq8JeL13yda3XnHPZKwYDN5HPBLykpLeuNpr9178tQd2/3d0NrH6gSd0sG5mLuLeuD+ck830fgzLQ== - dependencies: - use-isomorphic-layout-effect "^1.1.2" - use-sync-external-store "^1.0.0" - -"@xstate/test@^1.0.0-alpha.1": - version "1.0.0-alpha.1" - resolved "https://registry.yarnpkg.com/@xstate/test/-/test-1.0.0-alpha.1.tgz#46ce7730fa8710590dc917dd348359d4c1202d20" - integrity sha512-U2SyXHzlQk3Aa5aAFCEcuhc7U/3sr5I2eWbc7EO3fv8BtRROeh8Xk/40FAna5t4lv8T66RAgB7XqIUOKt3tKig== - dependencies: - "@xstate/graph" "^2.0.0-alpha.1" - -"@xtuc/ieee754@^1.2.0": - version "1.2.0" - resolved "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz" - integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== - -"@xtuc/long@4.2.2": - version "4.2.2" - resolved "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz" - integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== - -abab@^2.0.3, abab@^2.0.5: - version "2.0.6" - resolved "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz" - integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== - -accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8: - version "1.3.8" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" - integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== - dependencies: - mime-types "~2.1.34" - negotiator "0.6.3" - -acorn-globals@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz" - integrity sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg== - dependencies: - acorn "^7.1.1" - acorn-walk "^7.1.1" - -acorn-import-attributes@^1.9.5: - version "1.9.5" - resolved "https://registry.yarnpkg.com/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz#7eb1557b1ba05ef18b5ed0ec67591bfab04688ef" - integrity sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ== - -acorn-jsx@^5.2.0: - version "5.2.0" - resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz" - integrity sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ== - -acorn-walk@^7.1.1: - version "7.2.0" - resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz" - integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== - -acorn-walk@^8.0.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" - integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== - -acorn@^7.1.1, acorn@^7.4.0: - version "7.4.1" - resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz" - integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== - -acorn@^8.0.4, acorn@^8.2.4, acorn@^8.7.1, acorn@^8.8.2: - version "8.10.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" - integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== - -adjust-sourcemap-loader@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz#fc4a0fd080f7d10471f30a7320f25560ade28c99" - integrity sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A== - dependencies: - loader-utils "^2.0.0" - regex-parser "^2.2.11" - -agent-base@6: - version "6.0.2" - resolved "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz" - integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== - dependencies: - debug "4" - -airbnb-prop-types@^2.10.0, airbnb-prop-types@^2.14.0, airbnb-prop-types@^2.15.0: - version "2.16.0" - resolved "https://registry.npmjs.org/airbnb-prop-types/-/airbnb-prop-types-2.16.0.tgz" - integrity sha512-7WHOFolP/6cS96PhKNrslCLMYAI8yB1Pp6u6XmxozQOiZbsI5ycglZr5cHhBFfuRcQQjzCMith5ZPZdYiJCxUg== - dependencies: - array.prototype.find "^2.1.1" - function.prototype.name "^1.1.2" - is-regex "^1.1.0" - object-is "^1.1.2" - object.assign "^4.1.0" - object.entries "^1.1.2" - prop-types "^15.7.2" - prop-types-exact "^1.2.0" - react-is "^16.13.1" - -ajv-formats@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" - integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA== - dependencies: - ajv "^8.0.0" - -ajv-keywords@^3.5.2: - version "3.5.2" - resolved "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz" - integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== - -ajv-keywords@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz#69d4d385a4733cdbeab44964a1170a88f87f0e16" - integrity sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw== - dependencies: - fast-deep-equal "^3.1.3" - -ajv@^6.10.0: - version "6.12.3" - resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz" - integrity sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA== - 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" - -ajv@^6.10.2, ajv@^6.12.4, ajv@^6.12.5: - version "6.12.6" - resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -ajv@^8.0.0, ajv@^8.9.0: - version "8.12.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" - integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== - dependencies: - fast-deep-equal "^3.1.1" - json-schema-traverse "^1.0.0" - require-from-string "^2.0.2" - uri-js "^4.2.2" - -ansi-colors@^4.1.1: - version "4.1.1" - resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz" - integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== - -ansi-escapes@^4.2.1: - version "4.3.1" - resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz" - integrity sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA== - dependencies: - type-fest "^0.11.0" - -ansi-html-community@^0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/ansi-html-community/-/ansi-html-community-0.0.8.tgz#69fbc4d6ccbe383f9736934ae34c3f8290f1bf41" - integrity sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw== - -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz" - integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= - -ansi-regex@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz" - integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== - -ansi-regex@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz" - integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== - -ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz" - integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= - -ansi-styles@^3.2.0, ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -ansi-styles@^4.0.0, ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -ansi-styles@^5.0.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" - integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== - -anymatch@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz" - integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== - dependencies: - micromatch "^3.1.4" - normalize-path "^2.1.1" - -anymatch@^3.0.3, anymatch@~3.1.1: - version "3.1.1" - resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz" - integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg== - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - -anymatch@~3.1.2: - version "3.1.2" - resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz" - integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - -arch@^2.1.0: - version "2.1.2" - resolved "https://registry.npmjs.org/arch/-/arch-2.1.2.tgz" - integrity sha512-NTBIIbAfkJeIletyABbVtdPgeKfDafR+1mZV/AyyfC1UkVkp9iUjV+wwmqtUgphHYajbI86jejBJp5e+jkGTiQ== - -archive-type@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/archive-type/-/archive-type-4.0.0.tgz" - integrity sha1-+S5yIzBW38aWlHJ0nCZ72wRrHXA= - dependencies: - file-type "^4.2.0" - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - -argparse@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" - integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== - -aria-query@5.1.3: - version "5.1.3" - resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.1.3.tgz#19db27cd101152773631396f7a95a3b58c22c35e" - integrity sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ== - dependencies: - deep-equal "^2.0.5" - -aria-query@^4.2.2: - version "4.2.2" - resolved "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz" - integrity sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA== - dependencies: - "@babel/runtime" "^7.10.2" - "@babel/runtime-corejs3" "^7.10.2" - -aria-query@^5.0.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.3.0.tgz#650c569e41ad90b51b3d7df5e5eed1c7549c103e" - integrity sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A== - dependencies: - dequal "^2.0.3" - -arr-diff@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz" - integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= - -arr-flatten@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz" - integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== - -arr-union@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz" - integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= - -array-buffer-byte-length@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead" - integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A== - dependencies: - call-bind "^1.0.2" - is-array-buffer "^3.0.1" - -array-flatten@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" - integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== - -array-flatten@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099" - integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== - -array-includes@^3.1.1: - version "3.1.1" - resolved "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz" - integrity sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.0" - is-string "^1.0.5" - -array-union@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz" - integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== - -array-unique@^0.3.2: - version "0.3.2" - resolved "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz" - integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= - -array.prototype.find@^2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/array.prototype.find/-/array.prototype.find-2.1.1.tgz" - integrity sha512-mi+MYNJYLTx2eNYy+Yh6raoQacCsNeeMUaspFPh9Y141lFSsWxxB8V9mM2ye+eqiRs917J6/pJ4M9ZPzenWckA== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.4" - -array.prototype.flat@^1.2.1, array.prototype.flat@^1.2.3: - version "1.2.4" - resolved "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz" - integrity sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - es-abstract "^1.18.0-next.1" - -array.prototype.flatmap@^1.2.3: - version "1.2.3" - resolved "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.3.tgz" - integrity sha512-OOEk+lkePcg+ODXIpvuU9PAryCikCJyo7GlDG1upleEpQRx6mzL9puEBkozQ5iAx20KV0l3DbyQwqciJtqe5Pg== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" - function-bind "^1.1.1" - -assign-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz" - integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= - -ast-types-flow@^0.0.7: - version "0.0.7" - resolved "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz" - integrity sha1-9wtzXGvKGlycItmCw+Oef+ujva0= - -astral-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz" - integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== - -async@~1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/async/-/async-1.2.1.tgz" - integrity sha1-pIFqF81f9RbfosdpikUzabl5DeA= - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" - integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== - -atob@^2.1.2: - version "2.1.2" - resolved "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz" - integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== - -autobind-decorator@^2.4.0: - version "2.4.0" - resolved "https://registry.npmjs.org/autobind-decorator/-/autobind-decorator-2.4.0.tgz" - integrity sha512-OGYhWUO72V6DafbF8PM8rm3EPbfuyMZcJhtm5/n26IDwO18pohE4eNazLoCGhPiXOCD0gEGmrbU3849QvM8bbw== - -available-typed-arrays@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" - integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== - -axe-core@^4.0.2: - version "4.1.1" - resolved "https://registry.npmjs.org/axe-core/-/axe-core-4.1.1.tgz" - integrity sha512-5Kgy8Cz6LPC9DJcNb3yjAXTu3XihQgEdnIg50c//zOC/MyLP0Clg+Y8Sh9ZjjnvBrDZU4DgXS9C3T9r4/scGZQ== - -axios@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.0.tgz#f1e5292f26b2fd5c2e66876adc5b06cdbd7d2102" - integrity sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg== - dependencies: - follow-redirects "^1.15.0" - form-data "^4.0.0" - proxy-from-env "^1.1.0" - -axobject-query@^2.2.0: - version "2.2.0" - resolved "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz" - integrity sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA== - -babel-jest@^26.6.3: - version "26.6.3" - resolved "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz" - integrity sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA== - dependencies: - "@jest/transform" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/babel__core" "^7.1.7" - babel-plugin-istanbul "^6.0.0" - babel-preset-jest "^26.6.2" - chalk "^4.0.0" - graceful-fs "^4.2.4" - slash "^3.0.0" - -babel-jest@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.6.2.tgz#cada0a59e07f5acaeb11cbae7e3ba92aec9c1126" - integrity sha512-BYCzImLos6J3BH/+HvUCHG1dTf2MzmAB4jaVxHV+29RZLjR29XuYTmsf2sdDwkrb+FczkGo3kOhE7ga6sI0P4A== - dependencies: - "@jest/transform" "^29.6.2" - "@types/babel__core" "^7.1.14" - babel-plugin-istanbul "^6.1.1" - babel-preset-jest "^29.5.0" - chalk "^4.0.0" - graceful-fs "^4.2.9" - slash "^3.0.0" - -babel-loader@^9.1.3: - version "9.1.3" - resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-9.1.3.tgz#3d0e01b4e69760cc694ee306fe16d358aa1c6f9a" - integrity sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw== - dependencies: - find-cache-dir "^4.0.0" - schema-utils "^4.0.0" - -babel-plugin-istanbul@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz" - integrity sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@istanbuljs/load-nyc-config" "^1.0.0" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-instrument "^4.0.0" - test-exclude "^6.0.0" - -babel-plugin-istanbul@^6.1.1: - version "6.1.1" - resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" - integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@istanbuljs/load-nyc-config" "^1.0.0" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-instrument "^5.0.4" - test-exclude "^6.0.0" - -babel-plugin-jest-hoist@^26.6.2: - version "26.6.2" - resolved "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz" - integrity sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw== - dependencies: - "@babel/template" "^7.3.3" - "@babel/types" "^7.3.3" - "@types/babel__core" "^7.0.0" - "@types/babel__traverse" "^7.0.6" - -babel-plugin-jest-hoist@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz#a97db437936f441ec196990c9738d4b88538618a" - integrity sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w== - dependencies: - "@babel/template" "^7.3.3" - "@babel/types" "^7.3.3" - "@types/babel__core" "^7.1.14" - "@types/babel__traverse" "^7.0.6" - -babel-plugin-lodash@^3.3.4: - version "3.3.4" - resolved "https://registry.npmjs.org/babel-plugin-lodash/-/babel-plugin-lodash-3.3.4.tgz" - integrity sha512-yDZLjK7TCkWl1gpBeBGmuaDIFhZKmkoL+Cu2MUUjv5VxUZx/z7tBGBCBcQs5RI1Bkz5LLmNdjx7paOyQtMovyg== - dependencies: - "@babel/helper-module-imports" "^7.0.0-beta.49" - "@babel/types" "^7.0.0-beta.49" - glob "^7.1.1" - lodash "^4.17.10" - require-package-name "^2.0.1" - -babel-plugin-macros@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz#9ef6dc74deb934b4db344dc973ee851d148c50c1" - integrity sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg== - dependencies: - "@babel/runtime" "^7.12.5" - cosmiconfig "^7.0.0" - resolve "^1.19.0" - -babel-plugin-polyfill-corejs2@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz#5d1bd3836d0a19e1b84bbf2d9640ccb6f951c122" - integrity sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q== - dependencies: - "@babel/compat-data" "^7.17.7" - "@babel/helper-define-polyfill-provider" "^0.3.3" - semver "^6.1.1" - -babel-plugin-polyfill-corejs3@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz#56ad88237137eade485a71b52f72dbed57c6230a" - integrity sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA== - dependencies: - "@babel/helper-define-polyfill-provider" "^0.3.3" - core-js-compat "^3.25.1" - -babel-plugin-polyfill-regenerator@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz#390f91c38d90473592ed43351e801a9d3e0fd747" - integrity sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw== - dependencies: - "@babel/helper-define-polyfill-provider" "^0.3.3" - -babel-plugin-react-inline-svg-unique-id@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/babel-plugin-react-inline-svg-unique-id/-/babel-plugin-react-inline-svg-unique-id-1.4.0.tgz#da7ec9338826c6a77cc0dd0bafa25f0ed43912aa" - integrity sha512-8pps5AVafDvFpwgyFpkWkt1gutOL10Gq2Y/pDq+6C+IAEVRA8hx+qzHTW1m+wGxDrqyPO+B5etSrvvYo5l8hlA== - dependencies: - "@babel/plugin-syntax-jsx" "7.14.5" - "@babel/template" "7.15.4" - -"babel-plugin-styled-components@>= 1": - version "1.12.0" - resolved "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-1.12.0.tgz" - integrity sha512-FEiD7l5ZABdJPpLssKXjBUJMYqzbcNzBowfXDCdJhOpbhWiewapUaY+LZGT8R4Jg2TwOjGjG4RKeyrO5p9sBkA== - dependencies: - "@babel/helper-annotate-as-pure" "^7.0.0" - "@babel/helper-module-imports" "^7.0.0" - babel-plugin-syntax-jsx "^6.18.0" - lodash "^4.17.11" - -babel-plugin-syntax-jsx@^6.18.0: - version "6.18.0" - resolved "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz" - integrity sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY= - -babel-plugin-transform-import-meta@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-import-meta/-/babel-plugin-transform-import-meta-2.2.1.tgz#eb5b79019ff0a9157b94d8280955121189a2964b" - integrity sha512-AxNh27Pcg8Kt112RGa3Vod2QS2YXKKJ6+nSvRtv7qQTJAdx0MZa4UHZ4lnxHUWA2MNbLuZQv5FVab4P1CoLOWw== - dependencies: - "@babel/template" "^7.4.4" - tslib "^2.4.0" - -babel-preset-current-node-syntax@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.0.tgz#cf5feef29551253471cfa82fc8e0f5063df07a77" - integrity sha512-mGkvkpocWJes1CmMKtgGUwCeeq0pOhALyymozzDWYomHTbDLwueDYG6p4TK1YOeYHCzBzYPsWkgTto10JubI1Q== - dependencies: - "@babel/plugin-syntax-async-generators" "^7.8.4" - "@babel/plugin-syntax-bigint" "^7.8.3" - "@babel/plugin-syntax-class-properties" "^7.8.3" - "@babel/plugin-syntax-import-meta" "^7.8.3" - "@babel/plugin-syntax-json-strings" "^7.8.3" - "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-syntax-numeric-separator" "^7.8.3" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - "@babel/plugin-syntax-top-level-await" "^7.8.3" - -babel-preset-jest@^26.6.2: - version "26.6.2" - resolved "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz" - integrity sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ== - dependencies: - babel-plugin-jest-hoist "^26.6.2" - babel-preset-current-node-syntax "^1.0.0" - -babel-preset-jest@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz#57bc8cc88097af7ff6a5ab59d1cd29d52a5916e2" - integrity sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg== - dependencies: - babel-plugin-jest-hoist "^29.5.0" - babel-preset-current-node-syntax "^1.0.0" - -bad-words-next@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/bad-words-next/-/bad-words-next-3.1.1.tgz#342ffbf9f78ff78f12881e9e093d8710049e9c52" - integrity sha512-u0PSwEJijXlcz9X4bEXdR4rbOLZQVqMgY7QgJkpFa/VLrVrr+N7poT7pAHy2LcwOYNSBEF9Jnvk5G2sig5SYlg== - dependencies: - confusables "^1.1.1" - moize "^6.1.6" - -bail@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/bail/-/bail-2.0.2.tgz#d26f5cd8fe5d6f832a31517b9f7c356040ba6d5d" - integrity sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw== - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - -base64-js@^1.0.2: - version "1.5.1" - resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" - integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== - -base@^0.11.1: - version "0.11.2" - resolved "https://registry.npmjs.org/base/-/base-0.11.2.tgz" - integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== - dependencies: - cache-base "^1.0.1" - class-utils "^0.3.5" - component-emitter "^1.2.1" - define-property "^1.0.0" - isobject "^3.0.1" - mixin-deep "^1.2.0" - pascalcase "^0.1.1" - -batch@0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" - integrity sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw== - -big.js@^5.2.2: - version "5.2.2" - resolved "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz" - integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== - -bin-build@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/bin-build/-/bin-build-3.0.0.tgz" - integrity sha512-jcUOof71/TNAI2uM5uoUaDq2ePcVBQ3R/qhxAz1rX7UfvduAL/RXD3jXzvn8cVcDJdGVkiR1shal3OH0ImpuhA== - dependencies: - decompress "^4.0.0" - download "^6.2.2" - execa "^0.7.0" - p-map-series "^1.0.0" - tempfile "^2.0.0" - -bin-check@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/bin-check/-/bin-check-4.1.0.tgz" - integrity sha512-b6weQyEUKsDGFlACWSIOfveEnImkJyK/FGW6FAG42loyoquvjdtOIqO6yBFzHyqyVVhNgNkQxxx09SFLK28YnA== - dependencies: - execa "^0.7.0" - executable "^4.1.0" - -bin-version-check@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/bin-version-check/-/bin-version-check-4.0.0.tgz" - integrity sha512-sR631OrhC+1f8Cvs8WyVWOA33Y8tgwjETNPyyD/myRBXLkfS/vl74FmH/lFcRl9KY3zwGh7jFhvyk9vV3/3ilQ== - dependencies: - bin-version "^3.0.0" - semver "^5.6.0" - semver-truncate "^1.1.2" - -bin-version@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/bin-version/-/bin-version-3.1.0.tgz" - integrity sha512-Mkfm4iE1VFt4xd4vH+gx+0/71esbfus2LsnCGe8Pi4mndSPyT+NGES/Eg99jx8/lUGWfu3z2yuB/bt5UB+iVbQ== - dependencies: - execa "^1.0.0" - find-versions "^3.0.0" - -bin-wrapper@^4.0.0, bin-wrapper@^4.0.1: - version "4.1.0" - resolved "https://registry.npmjs.org/bin-wrapper/-/bin-wrapper-4.1.0.tgz" - integrity sha512-hfRmo7hWIXPkbpi0ZltboCMVrU+0ClXR/JgbCKKjlDjQf6igXa7OwdqNcFWQZPZTgiY7ZpzE3+LjjkLiTN2T7Q== - dependencies: - bin-check "^4.1.0" - bin-version-check "^4.0.0" - download "^7.1.0" - import-lazy "^3.1.0" - os-filter-obj "^2.0.0" - pify "^4.0.1" - -binary-extensions@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz" - integrity sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ== - -bl@^1.0.0: - version "1.2.2" - resolved "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz" - integrity sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA== - dependencies: - readable-stream "^2.3.5" - safe-buffer "^5.1.1" - -block-stream@*: - version "0.0.9" - resolved "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz" - integrity sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo= - dependencies: - inherits "~2.0.0" - -bluebird@^3.4.1: - version "3.7.2" - resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz" - integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== - -body-parser@1.20.3: - version "1.20.3" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6" - integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g== - dependencies: - bytes "3.1.2" - content-type "~1.0.5" - debug "2.6.9" - depd "2.0.0" - destroy "1.2.0" - http-errors "2.0.0" - iconv-lite "0.4.24" - on-finished "2.4.1" - qs "6.13.0" - raw-body "2.5.2" - type-is "~1.6.18" - unpipe "1.0.0" - -bonjour-service@^1.0.11: - version "1.1.0" - resolved "https://registry.yarnpkg.com/bonjour-service/-/bonjour-service-1.1.0.tgz#424170268d68af26ff83a5c640b95def01803a13" - integrity sha512-LVRinRB3k1/K0XzZ2p58COnWvkQknIY6sf0zF2rpErvcJXpMBttEPQSxK+HEXSS9VmpZlDoDnQWv8ftJT20B0Q== - dependencies: - array-flatten "^2.1.2" - dns-equal "^1.0.0" - fast-deep-equal "^3.1.3" - multicast-dns "^7.2.5" - -boolbase@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz" - integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= - -bootstrap@^4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.6.2.tgz#8e0cd61611728a5bf65a3a2b8d6ff6c77d5d7479" - integrity sha512-51Bbp/Uxr9aTuy6ca/8FbFloBUJZLHwnhTcnjIeRn2suQWsWzcuJhGjKDB5eppVte/8oCdOL3VuwxvZDUggwGQ== - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -braces@^2.3.1: - version "2.3.2" - resolved "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz" - integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== - dependencies: - arr-flatten "^1.1.0" - array-unique "^0.3.2" - extend-shallow "^2.0.1" - fill-range "^4.0.0" - isobject "^3.0.1" - repeat-element "^1.1.2" - snapdragon "^0.8.1" - snapdragon-node "^2.0.1" - split-string "^3.0.2" - to-regex "^3.0.1" - -braces@^3.0.1, braces@^3.0.2, braces@~3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== - dependencies: - fill-range "^7.0.1" - -brcast@^2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/brcast/-/brcast-2.0.2.tgz" - integrity sha512-Tfn5JSE7hrUlFcOoaLzVvkbgIemIorMIyoMr3TgvszWW7jFt2C9PdeMLtysYD9RU0MmU17b69+XJG1eRY2OBRg== - -browser-process-hrtime@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz" - integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== - -browserslist@^4.0.0, browserslist@^4.21.10, browserslist@^4.21.3, browserslist@^4.21.4, browserslist@^4.21.5, browserslist@^4.21.9: - version "4.23.3" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.3.tgz#debb029d3c93ebc97ffbc8d9cbb03403e227c800" - integrity sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA== - dependencies: - caniuse-lite "^1.0.30001646" - electron-to-chromium "^1.5.4" - node-releases "^2.0.18" - update-browserslist-db "^1.1.0" - -bser@2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz" - integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== - dependencies: - node-int64 "^0.4.0" - -buffer-alloc-unsafe@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz" - integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== - -buffer-alloc@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz" - integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== - dependencies: - buffer-alloc-unsafe "^1.1.0" - buffer-fill "^1.0.0" - -buffer-crc32@~0.2.3: - version "0.2.13" - resolved "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz" - integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= - -buffer-fill@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz" - integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= - -buffer-from@^1.0.0: - version "1.1.2" - resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz" - integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== - -buffer@^5.2.1: - version "5.6.0" - resolved "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz" - integrity sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw== - dependencies: - base64-js "^1.0.2" - ieee754 "^1.1.4" - -bytes@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" - integrity sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw== - -bytes@3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" - integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== - -cache-base@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz" - integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== - dependencies: - collection-visit "^1.0.0" - component-emitter "^1.2.1" - get-value "^2.0.6" - has-value "^1.0.0" - isobject "^3.0.1" - set-value "^2.0.0" - to-object-path "^0.3.0" - union-value "^1.0.0" - unset-value "^1.0.0" - -cacheable-request@^2.1.1: - version "2.1.4" - resolved "https://registry.npmjs.org/cacheable-request/-/cacheable-request-2.1.4.tgz" - integrity sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0= - dependencies: - clone-response "1.0.2" - get-stream "3.0.0" - http-cache-semantics "3.8.1" - keyv "3.0.0" - lowercase-keys "1.0.0" - normalize-url "2.0.1" - responselike "1.0.2" - -calcite-react@^0.56.2: - version "0.56.2" - resolved "https://registry.npmjs.org/calcite-react/-/calcite-react-0.56.2.tgz" - integrity sha512-Q7xoQKl6EDtlyfgdDUVf0KnTbcZzP5rdemlGf7D0eB2JXwHuEZ1Qwz3wRrn8ufZn8vTY2+g71lzEIiVBCZiqdA== - dependencies: - "@esri/arcgis-rest-auth" "^2.14.1" - "@esri/arcgis-rest-portal" "^2.14.1" - "@esri/arcgis-rest-request" "^2.14.1" - "@esri/calcite-colors" "^1.7.1" - calcite-ui-icons-react "^0.11.0" - downshift "^3.4.1" - match-sorter "^2.3.0" - memoize-one "^4.0.2" - outy "^0.1.2" - polished "^2.3.0" - react-dates "^21.8.0" - react-is "^16.8.6" - react-modal "^3.11.1" - react-popper "^1.3.6" - react-resize-aware "^3.0.0-beta.5" - react-toastify "^5.5.0" - react-transition-group "^4.3.0" - react-virtualized "^9.20.1" - styled-components "^5.0.0-beta.8" - uniqid "^5.0.3" - -calcite-ui-icons-react@^0.11.0: - version "0.11.0" - resolved "https://registry.npmjs.org/calcite-ui-icons-react/-/calcite-ui-icons-react-0.11.0.tgz" - integrity sha512-o+sNCWBP0aCeJLxklum+mHBCdxF5ItH1hhzorY0qjVACRV80yx3XNtFtepZQEt8tMaEOFpPRcg9gepGzmZTo0w== - -call-bind@^1.0.0, call-bind@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" - integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== - dependencies: - function-bind "^1.1.1" - get-intrinsic "^1.0.2" - -call-bind@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" - integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== - dependencies: - es-define-property "^1.0.0" - es-errors "^1.3.0" - function-bind "^1.1.2" - get-intrinsic "^1.2.4" - set-function-length "^1.2.1" - -callsites@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" - integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== - -camelcase@^5.0.0, camelcase@^5.3.1: - version "5.3.1" - resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz" - integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== - -camelcase@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.0.0.tgz" - integrity sha512-8KMDF1Vz2gzOq54ONPJS65IvTUaB1cHJ2DMM7MbPmLZljDH1qpzzLsWdiN9pHh6qvkRVDTi/07+eNGch/oLU4w== - -camelize@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz" - integrity sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs= - -caniuse-api@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz" - integrity sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw== - dependencies: - browserslist "^4.0.0" - caniuse-lite "^1.0.0" - lodash.memoize "^4.1.2" - lodash.uniq "^4.5.0" - -caniuse-lite@^1.0.0: - version "1.0.30001617" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001617.tgz" - integrity sha512-mLyjzNI9I+Pix8zwcrpxEbGlfqOkF9kM3ptzmKNw5tizSyYwMe+nGLTqMK9cO+0E+Bh6TsBxNAaHWEM8xwSsmA== - -caniuse-lite@^1.0.30001646: - version "1.0.30001655" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001655.tgz#0ce881f5a19a2dcfda2ecd927df4d5c1684b982f" - integrity sha512-jRGVy3iSGO5Uutn2owlb5gR6qsGngTw9ZTb4ali9f3glshcNmJ2noam4Mo9zia5P9Dk3jNNydy7vQjuE5dQmfg== - -capture-exit@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz" - integrity sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g== - dependencies: - rsvp "^4.8.4" - -caw@^2.0.0, caw@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/caw/-/caw-2.0.1.tgz" - integrity sha512-Cg8/ZSBEa8ZVY9HspcGUYaK63d/bN7rqS3CYCzEGUxuYv6UlmcjzDUz2fCFFHyTvUW5Pk0I+3hkA3iXlIj6guA== - dependencies: - get-proxy "^2.0.0" - isurl "^1.0.0-alpha5" - tunnel-agent "^0.6.0" - url-to-options "^1.0.1" - -ccount@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/ccount/-/ccount-2.0.1.tgz#17a3bf82302e0870d6da43a01311a8bc02a3ecf5" - integrity sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg== - -chalk@^1.1.3: - version "1.1.3" - resolved "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz" - integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - -chalk@^2.0.0, chalk@^2.4.2: - version "2.4.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz" - integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -chalk@^4.0.0, chalk@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz" - integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -char-regex@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz" - integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== - -character-entities-html4@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/character-entities-html4/-/character-entities-html4-2.1.0.tgz#1f1adb940c971a4b22ba39ddca6b618dc6e56b2b" - integrity sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA== - -character-entities-legacy@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz#76bc83a90738901d7bc223a9e93759fdd560125b" - integrity sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ== - -character-entities@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-2.0.2.tgz#2d09c2e72cd9523076ccb21157dff66ad43fcc22" - integrity sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ== - -character-reference-invalid@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz#85c66b041e43b47210faf401278abf808ac45cb9" - integrity sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw== - -chart.js@^4.4.3: - version "4.4.3" - resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-4.4.3.tgz#3b2e11e7010fefa99b07d0349236f5098e5226ad" - integrity sha512-qK1gkGSRYcJzqrrzdR6a+I0vQ4/R+SoODXyAjscQ/4mzuNzySaMCd+hyVxitSY1+L2fjPD1Gbn+ibNqRmwQeLw== - dependencies: - "@kurkle/color" "^0.3.0" - -"chokidar@>=3.0.0 <4.0.0": - version "3.5.2" - resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz" - integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ== - dependencies: - anymatch "~3.1.2" - braces "~3.0.2" - glob-parent "~5.1.2" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.6.0" - optionalDependencies: - fsevents "~2.3.2" - -chokidar@^3.4.0: - version "3.4.3" - resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz" - integrity sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ== - dependencies: - anymatch "~3.1.1" - braces "~3.0.2" - glob-parent "~5.1.0" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.5.0" - optionalDependencies: - fsevents "~2.1.2" - -chokidar@^3.5.3: - version "3.5.3" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" - integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== - dependencies: - anymatch "~3.1.2" - braces "~3.0.2" - glob-parent "~5.1.2" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.6.0" - optionalDependencies: - fsevents "~2.3.2" - -chrome-trace-event@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz" - integrity sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ== - dependencies: - tslib "^1.9.0" - -ci-info@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz" - integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== - -ci-info@^3.2.0: - version "3.8.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.8.0.tgz#81408265a5380c929f0bc665d62256628ce9ef91" - integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw== - -cjs-module-lexer@^0.6.0: - version "0.6.0" - resolved "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz" - integrity sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw== - -class-utils@^0.3.5: - version "0.3.6" - resolved "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz" - integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== - dependencies: - arr-union "^3.1.0" - define-property "^0.2.5" - isobject "^3.0.0" - static-extend "^0.1.1" - -classnames@^2.2.5, classnames@^2.2.6: - version "2.2.6" - resolved "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz" - integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q== - -classnames@^2.3.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.2.tgz#351d813bf0137fcc6a76a16b88208d2560a0d924" - integrity sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw== - -cliui@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz" - integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^6.2.0" - -clone-deep@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz" - integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== - dependencies: - is-plain-object "^2.0.4" - kind-of "^6.0.2" - shallow-clone "^3.0.0" - -clone-response@1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz" - integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= - dependencies: - mimic-response "^1.0.0" - -clsx@^1.0.4, clsx@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz" - integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA== - -clsx@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12" - integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== - -co@^4.6.0: - version "4.6.0" - resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz" - integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= - -collect-v8-coverage@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz" - integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== - -collection-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz" - integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= - dependencies: - map-visit "^1.0.0" - object-visit "^1.0.0" - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -colord@^2.9.1: - version "2.9.3" - resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.3.tgz#4f8ce919de456f1d5c1c368c307fe20f3e59fb43" - integrity sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw== - -colorette@^2.0.10, colorette@^2.0.14: - version "2.0.19" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798" - integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ== - -combined-stream@^1.0.8: - version "1.0.8" - resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" - -comma-separated-tokens@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz#4e89c9458acb61bc8fef19f4529973b2392839ee" - integrity sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg== - -commander@^10.0.1: - version "10.0.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" - integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== - -commander@^2.20.0, commander@^2.9.0: - version "2.20.3" - resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - -commander@^4.0.1: - version "4.1.1" - resolved "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz" - integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== - -commander@^7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" - integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== - -commander@^8.3.0: - version "8.3.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" - integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== - -commander@~2.8.1: - version "2.8.1" - resolved "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz" - integrity sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ= - dependencies: - graceful-readlink ">= 1.0.0" - -common-path-prefix@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/common-path-prefix/-/common-path-prefix-3.0.0.tgz#7d007a7e07c58c4b4d5f433131a19141b29f11e0" - integrity sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w== - -component-emitter@^1.2.1: - version "1.3.0" - resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz" - integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== - -compressible@~2.0.16: - version "2.0.18" - resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" - integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== - dependencies: - mime-db ">= 1.43.0 < 2" - -compression@^1.7.4: - version "1.7.4" - resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" - integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== - dependencies: - accepts "~1.3.5" - bytes "3.0.0" - compressible "~2.0.16" - debug "2.6.9" - on-headers "~1.0.2" - safe-buffer "5.1.2" - vary "~1.1.2" - -compute-scroll-into-view@^1.0.9: - version "1.0.16" - resolved "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.16.tgz" - integrity sha512-a85LHKY81oQnikatZYA90pufpZ6sQx++BoCxOEMsjpZx+ZnaKGQnCyCehTRr/1p9GBIAHTjcU9k71kSYWloLiQ== - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== - -config-chain@^1.1.11: - version "1.1.12" - resolved "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz" - integrity sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA== - dependencies: - ini "^1.3.4" - proto-list "~1.2.1" - -confusables@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/confusables/-/confusables-1.1.1.tgz#d3aafa1666d13a3a2fa9483bf556f641588d9a02" - integrity sha512-BzFtzUrufackm00Wb2zvrZV0ItRqPdWaUprU5FXHeZiJRrOWxGmXmQl/muGTF9EQl+MdBXz+Irk99meskGZmXw== - -confusing-browser-globals@^1.0.10: - version "1.0.10" - resolved "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.10.tgz" - integrity sha512-gNld/3lySHwuhaVluJUKLePYirM3QNCKzVxqAdhJII9/WXKVX5PURzMVJspS1jTslSqjeuG4KMVTSouit5YPHA== - -connect-history-api-fallback@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz#647264845251a0daf25b97ce87834cace0f5f1c8" - integrity sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA== - -console-polyfill@0.3.0: - version "0.3.0" - resolved "https://registry.npmjs.org/console-polyfill/-/console-polyfill-0.3.0.tgz" - integrity sha512-w+JSDZS7XML43Xnwo2x5O5vxB0ID7T5BdqDtyqT6uiCAX2kZAgcWxNaGqT97tZfSHzfOcvrfsDAodKcJ3UvnXQ== - -"consolidated-events@^1.1.1 || ^2.0.0": - version "2.0.2" - resolved "https://registry.npmjs.org/consolidated-events/-/consolidated-events-2.0.2.tgz" - integrity sha512-2/uRVMdRypf5z/TW/ncD/66l75P5hH2vM/GR8Jf8HLc2xnfJtmina6F6du8+v4Z2vTrMo7jC+W1tmEEuuELgkQ== - -contains-path@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz" - integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo= - -content-disposition@0.5.4, content-disposition@^0.5.2: - version "0.5.4" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" - integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== - dependencies: - safe-buffer "5.2.1" - -content-type@~1.0.4, content-type@~1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" - integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== - -convert-source-map@^1.1.0, convert-source-map@^1.4.0, convert-source-map@^1.5.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: - version "1.7.0" - resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz" - integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== - dependencies: - safe-buffer "~5.1.1" - -convert-source-map@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" - integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== - -cookie-signature@1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" - integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== - -cookie@0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051" - integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== - -copy-descriptor@^0.1.0: - version "0.1.1" - resolved "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz" - integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= - -copy-to-clipboard@^3.3.1: - version "3.3.1" - resolved "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz" - integrity sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw== - dependencies: - toggle-selection "^1.0.6" - -copy-webpack-plugin@^11.0.0: - version "11.0.0" - resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz#96d4dbdb5f73d02dd72d0528d1958721ab72e04a" - integrity sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ== - dependencies: - fast-glob "^3.2.11" - glob-parent "^6.0.1" - globby "^13.1.1" - normalize-path "^3.0.0" - schema-utils "^4.0.0" - serialize-javascript "^6.0.0" - -core-js-compat@^3.25.1: - version "3.29.0" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.29.0.tgz#1b8d9eb4191ab112022e7f6364b99b65ea52f528" - integrity sha512-ScMn3uZNAFhK2DGoEfErguoiAHhV2Ju+oJo/jK08p7B3f3UhocUrCCkTvnZaiS+edl5nlIoiBXKcwMc6elv4KQ== - dependencies: - browserslist "^4.21.5" - -core-js-pure@^3.0.0: - version "3.8.0" - resolved "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.8.0.tgz" - integrity sha512-fRjhg3NeouotRoIV0L1FdchA6CK7ZD+lyINyMoz19SyV+ROpC4noS1xItWHFtwZdlqfMfVPJEyEGdfri2bD1pA== - -core-js-pure@^3.23.3: - version "3.33.2" - resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.33.2.tgz#644830db2507ef84d068a70980ccd99c275f5fa6" - integrity sha512-a8zeCdyVk7uF2elKIGz67AjcXOxjRbwOLz8SbklEso1V+2DoW4OkAMZN9S9GBgvZIaqQi/OemFX4OiSoQEmg1Q== - -core-js@3.29.0: - version "3.29.0" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.29.0.tgz#0273e142b67761058bcde5615c503c7406b572d6" - integrity sha512-VG23vuEisJNkGl6XQmFJd3rEG/so/CNatqeE+7uZAwTSwFeB/qaO0be8xZYUNWprJ/GIwL8aMt9cj1kvbpTZhg== - -core-util-is@~1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= - -cosmiconfig@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6" - integrity sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA== - dependencies: - "@types/parse-json" "^4.0.0" - import-fresh "^3.2.1" - parse-json "^5.0.0" - path-type "^4.0.0" - yaml "^1.10.0" - -cosmiconfig@^8.2.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.2.0.tgz#f7d17c56a590856cd1e7cee98734dca272b0d8fd" - integrity sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ== - dependencies: - import-fresh "^3.2.1" - js-yaml "^4.1.0" - parse-json "^5.0.0" - path-type "^4.0.0" - -create-react-context@^0.3.0: - version "0.3.0" - resolved "https://registry.npmjs.org/create-react-context/-/create-react-context-0.3.0.tgz" - integrity sha512-dNldIoSuNSvlTJ7slIKC/ZFGKexBMBrrcc+TTe1NdmROnaASuLPvqpwj9v4XS4uXZ8+YPu0sNmShX2rXI5LNsw== - dependencies: - gud "^1.0.0" - warning "^4.0.3" - -cross-spawn@^5.0.1: - version "5.1.0" - resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz" - integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= - dependencies: - lru-cache "^4.0.1" - shebang-command "^1.2.0" - which "^1.2.9" - -cross-spawn@^6.0.0: - version "6.0.5" - resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== - dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" - -cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: - version "7.0.3" - resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -css-color-keywords@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz" - integrity sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU= - -css-declaration-sorter@^6.3.1: - version "6.3.1" - resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.3.1.tgz#be5e1d71b7a992433fb1c542c7a1b835e45682ec" - integrity sha512-fBffmak0bPAnyqc/HO8C3n2sHrp9wcqQz6ES9koRF2/mLOVAx9zIQ3Y7R29sYCteTPqMCwns4WYQoCX91Xl3+w== - -css-loader@^6.8.1: - version "6.8.1" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.8.1.tgz#0f8f52699f60f5e679eab4ec0fcd68b8e8a50a88" - integrity sha512-xDAXtEVGlD0gJ07iclwWVkLoZOpEvAWaSyf6W18S2pOC//K8+qUDIx8IIT3D+HjnmkJPQeesOPv5aiUaJsCM2g== - dependencies: - icss-utils "^5.1.0" - postcss "^8.4.21" - postcss-modules-extract-imports "^3.0.0" - postcss-modules-local-by-default "^4.0.3" - postcss-modules-scope "^3.0.0" - postcss-modules-values "^4.0.0" - postcss-value-parser "^4.2.0" - semver "^7.3.8" - -css-minimizer-webpack-plugin@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-5.0.1.tgz#33effe662edb1a0bf08ad633c32fa75d0f7ec565" - integrity sha512-3caImjKFQkS+ws1TGcFn0V1HyDJFq1Euy589JlD6/3rV2kj+w7r5G9WDMgSHvpvXHNZ2calVypZWuEDQd9wfLg== - dependencies: - "@jridgewell/trace-mapping" "^0.3.18" - cssnano "^6.0.1" - jest-worker "^29.4.3" - postcss "^8.4.24" - schema-utils "^4.0.1" - serialize-javascript "^6.0.1" - -css-select@^4.1.3: - version "4.3.0" - resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.3.0.tgz#db7129b2846662fd8628cfc496abb2b59e41529b" - integrity sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ== - dependencies: - boolbase "^1.0.0" - css-what "^6.0.1" - domhandler "^4.3.1" - domutils "^2.8.0" - nth-check "^2.0.1" - -css-select@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/css-select/-/css-select-5.1.0.tgz#b8ebd6554c3637ccc76688804ad3f6a6fdaea8a6" - integrity sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg== - dependencies: - boolbase "^1.0.0" - css-what "^6.1.0" - domhandler "^5.0.2" - domutils "^3.0.1" - nth-check "^2.0.1" - -css-to-react-native@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.0.0.tgz" - integrity sha512-Ro1yETZA813eoyUp2GDBhG2j+YggidUmzO1/v9eYBKR2EHVEniE2MI/NqpTQ954BMpTPZFsGNPm46qFB9dpaPQ== - dependencies: - camelize "^1.0.0" - css-color-keywords "^1.0.0" - postcss-value-parser "^4.0.2" - -css-tree@^1.1.2, css-tree@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d" - integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q== - dependencies: - mdn-data "2.0.14" - source-map "^0.6.1" - -css-tree@^2.2.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-2.3.1.tgz#10264ce1e5442e8572fc82fbe490644ff54b5c20" - integrity sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw== - dependencies: - mdn-data "2.0.30" - source-map-js "^1.0.1" - -css-tree@~2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-2.2.1.tgz#36115d382d60afd271e377f9c5f67d02bd48c032" - integrity sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA== - dependencies: - mdn-data "2.0.28" - source-map-js "^1.0.1" - -css-unit-converter@^1.1.1: - version "1.1.2" - resolved "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz" - integrity sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA== - -css-what@^6.0.1, css-what@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4" - integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw== - -css.escape@^1.5.1: - version "1.5.1" - resolved "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz" - integrity sha1-QuJ9T6BK4y+TGktNQZH6nN3ul8s= - -cssesc@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz" - integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== - -cssnano-preset-default@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-6.0.1.tgz#2a93247140d214ddb9f46bc6a3562fa9177fe301" - integrity sha512-7VzyFZ5zEB1+l1nToKyrRkuaJIx0zi/1npjvZfbBwbtNTzhLtlvYraK/7/uqmX2Wb2aQtd983uuGw79jAjLSuQ== - dependencies: - css-declaration-sorter "^6.3.1" - cssnano-utils "^4.0.0" - postcss-calc "^9.0.0" - postcss-colormin "^6.0.0" - postcss-convert-values "^6.0.0" - postcss-discard-comments "^6.0.0" - postcss-discard-duplicates "^6.0.0" - postcss-discard-empty "^6.0.0" - postcss-discard-overridden "^6.0.0" - postcss-merge-longhand "^6.0.0" - postcss-merge-rules "^6.0.1" - postcss-minify-font-values "^6.0.0" - postcss-minify-gradients "^6.0.0" - postcss-minify-params "^6.0.0" - postcss-minify-selectors "^6.0.0" - postcss-normalize-charset "^6.0.0" - postcss-normalize-display-values "^6.0.0" - postcss-normalize-positions "^6.0.0" - postcss-normalize-repeat-style "^6.0.0" - postcss-normalize-string "^6.0.0" - postcss-normalize-timing-functions "^6.0.0" - postcss-normalize-unicode "^6.0.0" - postcss-normalize-url "^6.0.0" - postcss-normalize-whitespace "^6.0.0" - postcss-ordered-values "^6.0.0" - postcss-reduce-initial "^6.0.0" - postcss-reduce-transforms "^6.0.0" - postcss-svgo "^6.0.0" - postcss-unique-selectors "^6.0.0" - -cssnano-utils@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/cssnano-utils/-/cssnano-utils-4.0.0.tgz#d1da885ec04003ab19505ff0e62e029708d36b08" - integrity sha512-Z39TLP+1E0KUcd7LGyF4qMfu8ZufI0rDzhdyAMsa/8UyNUU8wpS0fhdBxbQbv32r64ea00h4878gommRVg2BHw== - -cssnano@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-6.0.1.tgz#87c38c4cd47049c735ab756d7e77ac3ca855c008" - integrity sha512-fVO1JdJ0LSdIGJq68eIxOqFpIJrZqXUsBt8fkrBcztCQqAjQD51OhZp7tc0ImcbwXD4k7ny84QTV90nZhmqbkg== - dependencies: - cssnano-preset-default "^6.0.1" - lilconfig "^2.1.0" - -csso@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529" - integrity sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA== - dependencies: - css-tree "^1.1.2" - -csso@^5.0.5: - version "5.0.5" - resolved "https://registry.yarnpkg.com/csso/-/csso-5.0.5.tgz#f9b7fe6cc6ac0b7d90781bb16d5e9874303e2ca6" - integrity sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ== - dependencies: - css-tree "~2.2.0" - -cssom@^0.4.4: - version "0.4.4" - resolved "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz" - integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== - -cssom@~0.3.6: - version "0.3.8" - resolved "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz" - integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== - -cssstyle@^2.3.0: - version "2.3.0" - resolved "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz" - integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== - dependencies: - cssom "~0.3.6" - -csstype@^2.2.0: - version "2.6.21" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.21.tgz#2efb85b7cc55c80017c66a5ad7cbd931fda3a90e" - integrity sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w== - -csstype@^2.6.7: - version "2.6.11" - resolved "https://registry.npmjs.org/csstype/-/csstype-2.6.11.tgz" - integrity sha512-l8YyEC9NBkSm783PFTvh0FmJy7s5pFKrDp49ZL7zBGX3fWkO+N4EEyan1qqp8cwPLDcD0OSdyY6hAMoxp34JFw== - -csstype@^3.0.2: - version "3.0.5" - resolved "https://registry.npmjs.org/csstype/-/csstype-3.0.5.tgz" - integrity sha512-uVDi8LpBUKQj6sdxNaTetL6FpeCqTjOvAQuQUa/qAqq8oOd4ivkbhgnqayl0dnPal8Tb/yB1tF+gOvCBiicaiQ== - -cwebp-bin@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/cwebp-bin/-/cwebp-bin-7.0.1.tgz#cb1303bf43f645ba5b2ece342773c4a93574d4f4" - integrity sha512-Ko5ADY74/dbfd8xG0+f+MUP9UKjCe1TG4ehpW0E5y4YlPdwDJlGrSzSR4/Yonxpm9QmZE1RratkIxFlKeyo3FA== - dependencies: - bin-build "^3.0.0" - bin-wrapper "^4.0.1" - -d3-array@2, d3-array@^2.3.0: - version "2.12.1" - resolved "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz" - integrity sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ== - dependencies: - internmap "^1.0.0" - -"d3-color@1 - 2": - version "2.0.0" - resolved "https://registry.npmjs.org/d3-color/-/d3-color-2.0.0.tgz" - integrity sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ== - -"d3-format@1 - 2": - version "2.0.0" - resolved "https://registry.npmjs.org/d3-format/-/d3-format-2.0.0.tgz" - integrity sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA== - -"d3-interpolate@1.2.0 - 2", d3-interpolate@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-2.0.1.tgz" - integrity sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ== - dependencies: - d3-color "1 - 2" - -"d3-path@1 - 2": - version "2.0.0" - resolved "https://registry.npmjs.org/d3-path/-/d3-path-2.0.0.tgz" - integrity sha512-ZwZQxKhBnv9yHaiWd6ZU4x5BtCQ7pXszEV9CU6kRgwIQVQGLMv1oiL4M+MK/n79sYzsj+gcgpPQSctJUsLN7fA== - -d3-scale@^3.0.0: - version "3.3.0" - resolved "https://registry.npmjs.org/d3-scale/-/d3-scale-3.3.0.tgz" - integrity sha512-1JGp44NQCt5d1g+Yy+GeOnZP7xHo0ii8zsQp6PGzd+C1/dl0KGsp9A7Mxwp+1D1o4unbTTxVdU/ZOIEBoeZPbQ== - dependencies: - d3-array "^2.3.0" - d3-format "1 - 2" - d3-interpolate "1.2.0 - 2" - d3-time "^2.1.1" - d3-time-format "2 - 3" - -d3-shape@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/d3-shape/-/d3-shape-2.1.0.tgz" - integrity sha512-PnjUqfM2PpskbSLTJvAzp2Wv4CZsnAgTfcVRTwW03QR3MkXF8Uo7B1y/lWkAsmbKwuecto++4NlsYcvYpXpTHA== - dependencies: - d3-path "1 - 2" - -"d3-time-format@2 - 3": - version "3.0.0" - resolved "https://registry.npmjs.org/d3-time-format/-/d3-time-format-3.0.0.tgz" - integrity sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag== - dependencies: - d3-time "1 - 2" - -"d3-time@1 - 2", d3-time@^2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/d3-time/-/d3-time-2.1.1.tgz" - integrity sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ== - dependencies: - d3-array "2" - -damerau-levenshtein@^1.0.6: - version "1.0.6" - resolved "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.6.tgz" - integrity sha512-JVrozIeElnj3QzfUIt8tB8YMluBJom4Vw9qTPpjGYQ9fYlB3D/rb6OordUxf3xeFB35LKWs0xqcO5U6ySvBtug== - -data-urls@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz" - integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ== - dependencies: - abab "^2.0.3" - whatwg-mimetype "^2.3.0" - whatwg-url "^8.0.0" - -debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: - version "2.6.9" - resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: - version "4.3.4" - resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - -debug@^4.0.0: - version "4.3.5" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.5.tgz#e83444eceb9fedd4a1da56d671ae2446a01a6e1e" - integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== - dependencies: - ms "2.1.2" - -decache@^3.0.5: - version "3.1.0" - resolved "https://registry.npmjs.org/decache/-/decache-3.1.0.tgz" - integrity sha1-T1A2+9ZYH8yXI3rDlUokS5U2wto= - dependencies: - find "^0.2.4" - -decamelize@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz" - integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= - -decimal.js-light@^2.4.1: - version "2.5.1" - resolved "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz" - integrity sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg== - -decimal.js@^10.2.1: - version "10.3.1" - resolved "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz" - integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ== - -decode-named-character-reference@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz#daabac9690874c394c81e4162a0304b35d824f0e" - integrity sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg== - dependencies: - character-entities "^2.0.0" - -decode-uri-component@^0.2.0: - version "0.2.2" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" - integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ== - -decompress-response@^3.2.0, decompress-response@^3.3.0: - version "3.3.0" - resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz" - integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= - dependencies: - mimic-response "^1.0.0" - -decompress-tar@^4.0.0, decompress-tar@^4.1.0, decompress-tar@^4.1.1: - version "4.1.1" - resolved "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz" - integrity sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ== - dependencies: - file-type "^5.2.0" - is-stream "^1.1.0" - tar-stream "^1.5.2" - -decompress-tarbz2@^4.0.0: - version "4.1.1" - resolved "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz" - integrity sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A== - dependencies: - decompress-tar "^4.1.0" - file-type "^6.1.0" - is-stream "^1.1.0" - seek-bzip "^1.0.5" - unbzip2-stream "^1.0.9" - -decompress-targz@^4.0.0: - version "4.1.1" - resolved "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz" - integrity sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w== - dependencies: - decompress-tar "^4.1.1" - file-type "^5.2.0" - is-stream "^1.1.0" - -decompress-unzip@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz" - integrity sha1-3qrM39FK6vhVePczroIQ+bSEj2k= - dependencies: - file-type "^3.8.0" - get-stream "^2.2.0" - pify "^2.3.0" - yauzl "^2.4.2" - -decompress@^4.0.0, decompress@^4.2.0: - version "4.2.1" - resolved "https://registry.npmjs.org/decompress/-/decompress-4.2.1.tgz" - integrity sha512-e48kc2IjU+2Zw8cTb6VZcJQ3lgVbS4uuB1TfCHbiZIP/haNXm+SVyhu+87jts5/3ROpd82GSVCoNs/z8l4ZOaQ== - dependencies: - decompress-tar "^4.0.0" - decompress-tarbz2 "^4.0.0" - decompress-targz "^4.0.0" - decompress-unzip "^4.0.1" - graceful-fs "^4.1.10" - make-dir "^1.0.0" - pify "^2.3.0" - strip-dirs "^2.0.0" - -deep-equal@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz" - integrity sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g== - dependencies: - is-arguments "^1.0.4" - is-date-object "^1.0.1" - is-regex "^1.0.4" - object-is "^1.0.1" - object-keys "^1.1.1" - regexp.prototype.flags "^1.2.0" - -deep-equal@^2.0.5: - version "2.2.2" - resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-2.2.2.tgz#9b2635da569a13ba8e1cc159c2f744071b115daa" - integrity sha512-xjVyBf0w5vH0I42jdAZzOKVldmPgSulmiyPRywoyq7HXC9qdgo17kxJE+rdnif5Tz6+pIrpJI8dCpMNLIGkUiA== - dependencies: - array-buffer-byte-length "^1.0.0" - call-bind "^1.0.2" - es-get-iterator "^1.1.3" - get-intrinsic "^1.2.1" - is-arguments "^1.1.1" - is-array-buffer "^3.0.2" - is-date-object "^1.0.5" - is-regex "^1.1.4" - is-shared-array-buffer "^1.0.2" - isarray "^2.0.5" - object-is "^1.1.5" - object-keys "^1.1.1" - object.assign "^4.1.4" - regexp.prototype.flags "^1.5.0" - side-channel "^1.0.4" - which-boxed-primitive "^1.0.2" - which-collection "^1.0.1" - which-typed-array "^1.1.9" - -deep-is@^0.1.3: - version "0.1.3" - resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz" - integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= - -deep-is@~0.1.3: - 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== - -deepmerge@^1.5.2: - version "1.5.2" - resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-1.5.2.tgz" - integrity sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ== - -deepmerge@^2.1.1: - version "2.2.1" - resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-2.2.1.tgz" - integrity sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA== - -deepmerge@^3.2.0: - version "3.3.0" - resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-3.3.0.tgz" - integrity sha512-GRQOafGHwMHpjPx9iCvTgpu9NojZ49q794EEL94JVEw6VaeA8XTUyBKvAkOOjBX9oJNiV6G3P+T+tihFjo2TqA== - -deepmerge@^4.2.2: - version "4.2.2" - resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz" - integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== - -deepmerge@^4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" - integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== - -default-gateway@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-6.0.3.tgz#819494c888053bdb743edbf343d6cdf7f2943a71" - integrity sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg== - dependencies: - execa "^5.0.0" - -define-data-property@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" - integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== - dependencies: - es-define-property "^1.0.0" - es-errors "^1.3.0" - gopd "^1.0.1" - -define-lazy-prop@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" - integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== - -define-properties@^1.1.2, define-properties@^1.1.3: - version "1.1.3" - resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz" - integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== - dependencies: - object-keys "^1.0.12" - -define-properties@^1.1.4, define-properties@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.0.tgz#52988570670c9eacedd8064f4a990f2405849bd5" - integrity sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA== - dependencies: - has-property-descriptors "^1.0.0" - object-keys "^1.1.1" - -define-property@^0.2.5: - version "0.2.5" - resolved "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz" - integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= - dependencies: - is-descriptor "^0.1.0" - -define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz" - integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= - dependencies: - is-descriptor "^1.0.0" - -define-property@^2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz" - integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== - dependencies: - is-descriptor "^1.0.2" - isobject "^3.0.1" - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" - integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== - -depd@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" - integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== - -depd@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" - integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== - -dequal@^2.0.0, dequal@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" - integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== - -destroy@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" - integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== - -detect-newline@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz" - integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== - -detect-node@^2.0.4: - version "2.1.0" - resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" - integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== - -devlop@^1.0.0, devlop@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/devlop/-/devlop-1.1.0.tgz#4db7c2ca4dc6e0e834c30be70c94bbc976dc7018" - integrity sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA== - dependencies: - dequal "^2.0.0" - -diacritic@0.0.2: - version "0.0.2" - resolved "https://registry.npmjs.org/diacritic/-/diacritic-0.0.2.tgz" - integrity sha1-/CqIe1pbwKCoVPthTHwvIJBh7gQ= - -diff-sequences@^25.2.6: - version "25.2.6" - resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-25.2.6.tgz" - integrity sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg== - -diff-sequences@^26.6.2: - version "26.6.2" - resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz" - integrity sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q== - -dir-glob@^3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz" - integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== - dependencies: - path-type "^4.0.0" - -direction@^1.0.2: - version "1.0.4" - resolved "https://registry.npmjs.org/direction/-/direction-1.0.4.tgz" - integrity sha512-GYqKi1aH7PJXxdhTeZBFrg8vUBeKXi+cNprXsC1kpJcbcVnV9wBsrOu1cQEdG0WeQwlfHiy3XvnKfIrJ2R0NzQ== - -dns-equal@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" - integrity sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg== - -dns-packet@^5.2.2: - version "5.4.0" - resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-5.4.0.tgz#1f88477cf9f27e78a213fb6d118ae38e759a879b" - integrity sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g== - dependencies: - "@leichtgewicht/ip-codec" "^2.0.1" - -doctrine@1.5.0: - version "1.5.0" - resolved "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz" - integrity sha1-N53Ocw9hZvds76TmcHoVmwLFpvo= - dependencies: - esutils "^2.0.2" - isarray "^1.0.0" - -doctrine@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz" - integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== - dependencies: - esutils "^2.0.2" - -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - -document.contains@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/document.contains/-/document.contains-1.0.2.tgz" - integrity sha512-YcvYFs15mX8m3AO1QNQy3BlIpSMfNRj3Ujk2BEJxsZG+HZf7/hZ6jr7mDpXrF8q+ff95Vef5yjhiZxm8CGJr6Q== - dependencies: - define-properties "^1.1.3" - -dom-accessibility-api@^0.5.6, dom-accessibility-api@^0.5.9: - version "0.5.16" - resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz#5a7429e6066eb3664d911e33fb0e45de8eb08453" - integrity sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg== - -dom-helpers@^3.4.0: - version "3.4.0" - resolved "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz" - integrity sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA== - dependencies: - "@babel/runtime" "^7.1.2" - -dom-helpers@^5.0.1: - version "5.1.4" - resolved "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.1.4.tgz" - integrity sha512-TjMyeVUvNEnOnhzs6uAn9Ya47GmMo3qq7m+Lr/3ON0Rs5kHvb8I+SQYjLUSYn7qhEm0QjW0yrBkvz9yOrwwz1A== - dependencies: - "@babel/runtime" "^7.8.7" - csstype "^2.6.7" - -dom-helpers@^5.1.3, dom-helpers@^5.2.0: - version "5.2.0" - resolved "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.0.tgz" - integrity sha512-Ru5o9+V8CpunKnz5LGgWXkmrH/20cGKwcHwS4m73zIvs54CN9epEmT/HLqFJW3kXpakAFkEdzgy1hzlJe3E4OQ== - dependencies: - "@babel/runtime" "^7.8.7" - csstype "^3.0.2" - -dom-helpers@^5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902" - integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA== - dependencies: - "@babel/runtime" "^7.8.7" - csstype "^3.0.2" - -dom-serializer@^1.0.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.4.1.tgz#de5d41b1aea290215dc45a6dae8adcf1d32e2d30" - integrity sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag== - dependencies: - domelementtype "^2.0.1" - domhandler "^4.2.0" - entities "^2.0.0" - -dom-serializer@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-2.0.0.tgz#e41b802e1eedf9f6cae183ce5e622d789d7d8e53" - integrity sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg== - dependencies: - domelementtype "^2.3.0" - domhandler "^5.0.2" - entities "^4.2.0" - -domelementtype@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz" - integrity sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ== - -domelementtype@^2.2.0, domelementtype@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d" - integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== - -domexception@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz" - integrity sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg== - dependencies: - webidl-conversions "^5.0.0" - -domhandler@^4.2.0, domhandler@^4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c" - integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ== - dependencies: - domelementtype "^2.2.0" - -domhandler@^5.0.2, domhandler@^5.0.3: - version "5.0.3" - resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-5.0.3.tgz#cc385f7f751f1d1fc650c21374804254538c7d31" - integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w== - dependencies: - domelementtype "^2.3.0" - -domutils@^2.8.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" - integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A== - dependencies: - dom-serializer "^1.0.1" - domelementtype "^2.2.0" - domhandler "^4.2.0" - -domutils@^3.0.1: - version "3.1.0" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.1.0.tgz#c47f551278d3dc4b0b1ab8cbb42d751a6f0d824e" - integrity sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA== - dependencies: - dom-serializer "^2.0.0" - domelementtype "^2.3.0" - domhandler "^5.0.3" - -download@^6.2.2: - version "6.2.5" - resolved "https://registry.npmjs.org/download/-/download-6.2.5.tgz" - integrity sha512-DpO9K1sXAST8Cpzb7kmEhogJxymyVUd5qz/vCOSyvwtp2Klj2XcDt5YUuasgxka44SxF0q5RriKIwJmQHG2AuA== - dependencies: - caw "^2.0.0" - content-disposition "^0.5.2" - decompress "^4.0.0" - ext-name "^5.0.0" - file-type "5.2.0" - filenamify "^2.0.0" - get-stream "^3.0.0" - got "^7.0.0" - make-dir "^1.0.0" - p-event "^1.0.0" - pify "^3.0.0" - -download@^7.1.0: - version "7.1.0" - resolved "https://registry.npmjs.org/download/-/download-7.1.0.tgz" - integrity sha512-xqnBTVd/E+GxJVrX5/eUJiLYjCGPwMpdL+jGhGU57BvtcA7wwhtHVbXBeUk51kOpW3S7Jn3BQbN9Q1R1Km2qDQ== - dependencies: - archive-type "^4.0.0" - caw "^2.0.1" - content-disposition "^0.5.2" - decompress "^4.2.0" - ext-name "^5.0.0" - file-type "^8.1.0" - filenamify "^2.0.0" - get-stream "^3.0.0" - got "^8.3.1" - make-dir "^1.2.0" - p-event "^2.1.0" - pify "^3.0.0" - -downshift@^3.4.1: - version "3.4.8" - resolved "https://registry.npmjs.org/downshift/-/downshift-3.4.8.tgz" - integrity sha512-dZL3iNL/LbpHNzUQAaVq/eTD1ocnGKKjbAl/848Q0KEp6t81LJbS37w3f93oD6gqqAnjdgM7Use36qZSipHXBw== - dependencies: - "@babel/runtime" "^7.4.5" - compute-scroll-into-view "^1.0.9" - prop-types "^15.7.2" - react-is "^16.9.0" - -duplexer3@^0.1.4: - version "0.1.4" - resolved "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz" - integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= - -duplexer@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" - integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== - -ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== - -electron-to-chromium@^1.5.4: - version "1.5.13" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz#1abf0410c5344b2b829b7247e031f02810d442e6" - integrity sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q== - -emittery@^0.7.1: - version "0.7.2" - resolved "https://registry.npmjs.org/emittery/-/emittery-0.7.2.tgz" - integrity sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ== - -emoji-mart@^5.5.2: - version "5.5.2" - resolved "https://registry.yarnpkg.com/emoji-mart/-/emoji-mart-5.5.2.tgz#3ddbaf053139cf4aa217650078bc1c50ca8381af" - integrity sha512-Sqc/nso4cjxhOwWJsp9xkVm8OF5c+mJLZJFoFfzRuKO+yWiN7K8c96xmtughYb0d/fZ8UC6cLIQ/p4BR6Pv3/A== - -emoji-regex@^7.0.1: - version "7.0.3" - resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz" - integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -emoji-regex@^9.0.0: - version "9.0.0" - resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.0.0.tgz" - integrity sha512-6p1NII1Vm62wni/VR/cUMauVQoxmLVb9csqQlvLz+hO2gk8U2UYDfXHQSUYIBKmZwAKz867IDqG7B+u0mj+M6w== - -emojis-list@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz" - integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== - -encodeurl@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" - integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== - -encodeurl@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" - integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== - -encoding@^0.1.12: - version "0.1.13" - resolved "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz" - integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== - dependencies: - iconv-lite "^0.6.2" - -end-of-stream@^1.0.0, end-of-stream@^1.1.0: - version "1.4.4" - resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz" - integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== - dependencies: - once "^1.4.0" - -enhanced-resolve@^5.17.1: - version "5.17.1" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz#67bfbbcc2f81d511be77d686a90267ef7f898a15" - integrity sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg== - dependencies: - graceful-fs "^4.2.4" - tapable "^2.2.0" - -enquirer@^2.3.5: - version "2.3.6" - resolved "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz" - integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== - dependencies: - ansi-colors "^4.1.1" - -entities@^2.0.0: - version "2.0.3" - resolved "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz" - integrity sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ== - -entities@^4.2.0, entities@^4.4.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" - integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== - -envinfo@^7.7.3: - version "7.8.1" - resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.8.1.tgz#06377e3e5f4d379fea7ac592d5ad8927e0c4d475" - integrity sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw== - -enzyme-shallow-equal@^1.0.0: - version "1.0.4" - resolved "https://registry.npmjs.org/enzyme-shallow-equal/-/enzyme-shallow-equal-1.0.4.tgz" - integrity sha512-MttIwB8kKxypwHvRynuC3ahyNc+cFbR8mjVIltnmzQ0uKGqmsfO4bfBuLxb0beLNPhjblUEYvEbsg+VSygvF1Q== - dependencies: - has "^1.0.3" - object-is "^1.1.2" - -error-ex@^1.2.0, error-ex@^1.3.1: - version "1.3.2" - resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz" - integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== - dependencies: - is-arrayish "^0.2.1" - -error-stack-parser@^2.0.4: - version "2.0.6" - resolved "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.0.6.tgz" - integrity sha512-d51brTeqC+BHlwF0BhPtcYgF5nlzf9ZZ0ZIUQNZpc9ZB9qw5IJ2diTrBY9jlCJkTLITYPjmiX6OWCwH+fuyNgQ== - dependencies: - stackframe "^1.1.1" - -error-stack-parser@^2.0.6: - version "2.1.4" - resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.1.4.tgz#229cb01cdbfa84440bfa91876285b94680188286" - integrity sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ== - dependencies: - stackframe "^1.3.4" - -es-abstract@^1.17.0, es-abstract@^1.17.0-next.1, es-abstract@^1.17.5: - version "1.17.6" - resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz" - integrity sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw== - dependencies: - es-to-primitive "^1.2.1" - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" - is-callable "^1.2.0" - is-regex "^1.1.0" - object-inspect "^1.7.0" - object-keys "^1.1.1" - object.assign "^4.1.0" - string.prototype.trimend "^1.0.1" - string.prototype.trimstart "^1.0.1" - -es-abstract@^1.17.4: - version "1.17.7" - resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz" - integrity sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g== - dependencies: - es-to-primitive "^1.2.1" - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" - is-callable "^1.2.2" - is-regex "^1.1.1" - object-inspect "^1.8.0" - object-keys "^1.1.1" - object.assign "^4.1.1" - string.prototype.trimend "^1.0.1" - string.prototype.trimstart "^1.0.1" - -es-abstract@^1.18.0-next.1: - version "1.18.0-next.1" - resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz" - integrity sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA== - dependencies: - es-to-primitive "^1.2.1" - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" - is-callable "^1.2.2" - is-negative-zero "^2.0.0" - is-regex "^1.1.1" - object-inspect "^1.8.0" - object-keys "^1.1.1" - object.assign "^4.1.1" - string.prototype.trimend "^1.0.1" - string.prototype.trimstart "^1.0.1" - -es-define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" - integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== - dependencies: - get-intrinsic "^1.2.4" - -es-errors@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" - integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== - -es-get-iterator@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.3.tgz#3ef87523c5d464d41084b2c3c9c214f1199763d6" - integrity sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.3" - has-symbols "^1.0.3" - is-arguments "^1.1.1" - is-map "^2.0.2" - is-set "^2.0.2" - is-string "^1.0.7" - isarray "^2.0.5" - stop-iteration-iterator "^1.0.0" - -es-module-lexer@^1.2.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.3.0.tgz#6be9c9e0b4543a60cd166ff6f8b4e9dae0b0c16f" - integrity sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA== - -es-to-primitive@^1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz" - integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - -escalade@^3.1.2: - version "3.2.0" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" - integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== - -escape-html@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== - -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= - -escape-string-regexp@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz" - integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== - -escape-string-regexp@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" - integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== - -escodegen@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz" - integrity sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw== - dependencies: - esprima "^4.0.1" - estraverse "^5.2.0" - esutils "^2.0.2" - optionator "^0.8.1" - optionalDependencies: - source-map "~0.6.1" - -eslint-config-airbnb-base@^14.2.1: - version "14.2.1" - resolved "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.1.tgz" - integrity sha512-GOrQyDtVEc1Xy20U7vsB2yAoB4nBlfH5HZJeatRXHleO+OS5Ot+MWij4Dpltw4/DyIkqUfqz1epfhVR5XWWQPA== - dependencies: - confusing-browser-globals "^1.0.10" - object.assign "^4.1.2" - object.entries "^1.1.2" - -eslint-config-airbnb@^18.2.1: - version "18.2.1" - resolved "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-18.2.1.tgz" - integrity sha512-glZNDEZ36VdlZWoxn/bUR1r/sdFKPd1mHPbqUtkctgNG4yT2DLLtJ3D+yCV+jzZCc2V1nBVkmdknOJBZ5Hc0fg== - dependencies: - eslint-config-airbnb-base "^14.2.1" - object.assign "^4.1.2" - object.entries "^1.1.2" - -eslint-import-resolver-node@^0.3.4: - version "0.3.4" - resolved "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz" - integrity sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA== - dependencies: - debug "^2.6.9" - resolve "^1.13.1" - -eslint-module-utils@^2.6.0: - version "2.6.0" - resolved "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz" - integrity sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA== - dependencies: - debug "^2.6.9" - pkg-dir "^2.0.0" - -eslint-plugin-import@2.22.1: - version "2.22.1" - resolved "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.1.tgz" - integrity sha512-8K7JjINHOpH64ozkAhpT3sd+FswIZTfMZTjdx052pnWrgRCVfp8op9tbjpAk3DdUeI/Ba4C8OjdC0r90erHEOw== - dependencies: - array-includes "^3.1.1" - array.prototype.flat "^1.2.3" - contains-path "^0.1.0" - debug "^2.6.9" - doctrine "1.5.0" - eslint-import-resolver-node "^0.3.4" - eslint-module-utils "^2.6.0" - has "^1.0.3" - minimatch "^3.0.4" - object.values "^1.1.1" - read-pkg-up "^2.0.0" - resolve "^1.17.0" - tsconfig-paths "^3.9.0" - -eslint-plugin-jest@^23.13.2: - version "23.20.0" - resolved "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-23.20.0.tgz" - integrity sha512-+6BGQt85OREevBDWCvhqj1yYA4+BFK4XnRZSGJionuEYmcglMZYLNNBBemwzbqUAckURaHdJSBcjHPyrtypZOw== - dependencies: - "@typescript-eslint/experimental-utils" "^2.5.0" - -eslint-plugin-jsx-a11y@^6.4.1: - version "6.4.1" - resolved "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.4.1.tgz" - integrity sha512-0rGPJBbwHoGNPU73/QCLP/vveMlM1b1Z9PponxO87jfr6tuH5ligXbDT6nHSSzBC8ovX2Z+BQu7Bk5D/Xgq9zg== - dependencies: - "@babel/runtime" "^7.11.2" - aria-query "^4.2.2" - array-includes "^3.1.1" - ast-types-flow "^0.0.7" - axe-core "^4.0.2" - axobject-query "^2.2.0" - damerau-levenshtein "^1.0.6" - emoji-regex "^9.0.0" - has "^1.0.3" - jsx-ast-utils "^3.1.0" - language-tags "^1.0.5" - -eslint-plugin-jsx@0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/eslint-plugin-jsx/-/eslint-plugin-jsx-0.1.0.tgz" - integrity sha512-278HIClJgb3Gp1b89wbva7AGS7cxQzBNgKFysy6aEB44Acso2M8ARdoaLUnN7VTWf0vnSvtwugCmc/B8MSzY5g== - dependencies: - eslint-plugin-react "3.4.2" - html-tags "1" - svg-tags "1" - -eslint-plugin-react-hooks@^4.2.0: - version "4.2.0" - resolved "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz" - integrity sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ== - -eslint-plugin-react@3.4.2: - version "3.4.2" - resolved "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-3.4.2.tgz" - integrity sha1-nm74qAVPisO4e5cjbnuEnlg13Gw= - -eslint-plugin-react@^7.21.5: - version "7.21.5" - resolved "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.21.5.tgz" - integrity sha512-8MaEggC2et0wSF6bUeywF7qQ46ER81irOdWS4QWxnnlAEsnzeBevk1sWh7fhpCghPpXb+8Ks7hvaft6L/xsR6g== - dependencies: - array-includes "^3.1.1" - array.prototype.flatmap "^1.2.3" - doctrine "^2.1.0" - has "^1.0.3" - jsx-ast-utils "^2.4.1 || ^3.0.0" - object.entries "^1.1.2" - object.fromentries "^2.0.2" - object.values "^1.1.1" - prop-types "^15.7.2" - resolve "^1.18.1" - string.prototype.matchall "^4.0.2" - -eslint-scope@5.1.1, eslint-scope@^5.0.0, eslint-scope@^5.1.1: - version "5.1.1" - resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== - dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" - -eslint-utils@^2.0.0, eslint-utils@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz" - integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== - dependencies: - eslint-visitor-keys "^1.1.0" - -eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz" - integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== - -eslint-visitor-keys@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz" - integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ== - -eslint-visitor-keys@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" - integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== - -eslint@^7.14.0: - version "7.14.0" - resolved "https://registry.npmjs.org/eslint/-/eslint-7.14.0.tgz" - integrity sha512-5YubdnPXrlrYAFCKybPuHIAH++PINe1pmKNc5wQRB9HSbqIK1ywAnntE3Wwua4giKu0bjligf1gLF6qxMGOYRA== - dependencies: - "@babel/code-frame" "^7.0.0" - "@eslint/eslintrc" "^0.2.1" - ajv "^6.10.0" - chalk "^4.0.0" - cross-spawn "^7.0.2" - debug "^4.0.1" - doctrine "^3.0.0" - enquirer "^2.3.5" - eslint-scope "^5.1.1" - eslint-utils "^2.1.0" - eslint-visitor-keys "^2.0.0" - espree "^7.3.0" - esquery "^1.2.0" - esutils "^2.0.2" - file-entry-cache "^5.0.1" - functional-red-black-tree "^1.0.1" - glob-parent "^5.0.0" - globals "^12.1.0" - ignore "^4.0.6" - import-fresh "^3.0.0" - imurmurhash "^0.1.4" - is-glob "^4.0.0" - js-yaml "^3.13.1" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" - lodash "^4.17.19" - minimatch "^3.0.4" - natural-compare "^1.4.0" - optionator "^0.9.1" - progress "^2.0.0" - regexpp "^3.1.0" - semver "^7.2.1" - strip-ansi "^6.0.0" - strip-json-comments "^3.1.0" - table "^5.2.3" - text-table "^0.2.0" - v8-compile-cache "^2.0.3" - -espree@^7.3.0: - version "7.3.0" - resolved "https://registry.npmjs.org/espree/-/espree-7.3.0.tgz" - integrity sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw== - dependencies: - acorn "^7.4.0" - acorn-jsx "^5.2.0" - eslint-visitor-keys "^1.3.0" - -esprima@^4.0.0, esprima@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -esquery@^1.2.0: - version "1.3.1" - resolved "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz" - integrity sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ== - dependencies: - estraverse "^5.1.0" - -esrecurse@^4.3.0: - version "4.3.0" - resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz" - integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== - dependencies: - estraverse "^5.2.0" - -estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - -estraverse@^5.1.0: - version "5.1.0" - resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.1.0.tgz" - integrity sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw== - -estraverse@^5.2.0: - version "5.3.0" - resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" - integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== - -estree-util-is-identifier-name@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz#0b5ef4c4ff13508b34dcd01ecfa945f61fce5dbd" - integrity sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg== - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - -etag@~1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" - integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== - -eventemitter3@^4.0.0: - version "4.0.7" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" - integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== - -eventemitter3@^4.0.1: - version "4.0.4" - resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz" - integrity sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ== - -events@^3.2.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" - integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== - -exec-buffer@^3.0.0, exec-buffer@^3.2.0: - version "3.2.0" - resolved "https://registry.npmjs.org/exec-buffer/-/exec-buffer-3.2.0.tgz" - integrity sha512-wsiD+2Tp6BWHoVv3B+5Dcx6E7u5zky+hUwOHjuH2hKSLR3dvRmX8fk8UD8uqQixHs4Wk6eDmiegVrMPjKj7wpA== - dependencies: - execa "^0.7.0" - p-finally "^1.0.0" - pify "^3.0.0" - rimraf "^2.5.4" - tempfile "^2.0.0" - -exec-sh@^0.3.2: - version "0.3.4" - resolved "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.4.tgz" - integrity sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A== - -execa@^0.7.0: - version "0.7.0" - resolved "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz" - integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c= - dependencies: - cross-spawn "^5.0.1" - get-stream "^3.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - -execa@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz" - integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== - dependencies: - cross-spawn "^6.0.0" - get-stream "^4.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - -execa@^4.0.0: - version "4.0.3" - resolved "https://registry.npmjs.org/execa/-/execa-4.0.3.tgz" - integrity sha512-WFDXGHckXPWZX19t1kCsXzOpqX9LWYNqn4C+HqZlk/V0imTkzJZqf87ZBhvpHaftERYknpk0fjSylnXVlVgI0A== - dependencies: - cross-spawn "^7.0.0" - get-stream "^5.0.0" - human-signals "^1.1.1" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^4.0.0" - onetime "^5.1.0" - signal-exit "^3.0.2" - strip-final-newline "^2.0.0" - -execa@^5.0.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" - integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== - dependencies: - cross-spawn "^7.0.3" - get-stream "^6.0.0" - human-signals "^2.1.0" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^4.0.1" - onetime "^5.1.2" - signal-exit "^3.0.3" - strip-final-newline "^2.0.0" - -executable@^4.1.0: - version "4.1.1" - resolved "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz" - integrity sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg== - dependencies: - pify "^2.2.0" - -exenv@^1.2.0, exenv@^1.2.2: - version "1.2.2" - resolved "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz" - integrity sha1-KueOhdmJQVhnCwPUe+wfA72Ru50= - -exit@^0.1.2: - version "0.1.2" - resolved "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz" - integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= - -expand-brackets@^2.1.4: - version "2.1.4" - resolved "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz" - integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= - dependencies: - debug "^2.3.3" - define-property "^0.2.5" - extend-shallow "^2.0.1" - posix-character-classes "^0.1.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -expect@^26.6.2: - version "26.6.2" - resolved "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz" - integrity sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA== - dependencies: - "@jest/types" "^26.6.2" - ansi-styles "^4.0.0" - jest-get-type "^26.3.0" - jest-matcher-utils "^26.6.2" - jest-message-util "^26.6.2" - jest-regex-util "^26.0.0" - -exports-loader@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/exports-loader/-/exports-loader-4.0.0.tgz#af34fe80a18f12fb0f42f435edd7df0fe9db49bb" - integrity sha512-4iqFFIAnlVAbkAUMHhWceyxK6N6dMDWpQFbSHLmiayGEPMXl2bgWD4D11GYi1VNuEQwJaHGdATcPYTnXpwzSmw== - dependencies: - source-map "^0.6.1" - -express@^4.17.3: - version "4.21.0" - resolved "https://registry.yarnpkg.com/express/-/express-4.21.0.tgz#d57cb706d49623d4ac27833f1cbc466b668eb915" - integrity sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng== - dependencies: - accepts "~1.3.8" - array-flatten "1.1.1" - body-parser "1.20.3" - content-disposition "0.5.4" - content-type "~1.0.4" - cookie "0.6.0" - cookie-signature "1.0.6" - debug "2.6.9" - depd "2.0.0" - encodeurl "~2.0.0" - escape-html "~1.0.3" - etag "~1.8.1" - finalhandler "1.3.1" - fresh "0.5.2" - http-errors "2.0.0" - merge-descriptors "1.0.3" - methods "~1.1.2" - on-finished "2.4.1" - parseurl "~1.3.3" - path-to-regexp "0.1.10" - proxy-addr "~2.0.7" - qs "6.13.0" - range-parser "~1.2.1" - safe-buffer "5.2.1" - send "0.19.0" - serve-static "1.16.2" - setprototypeof "1.2.0" - statuses "2.0.1" - type-is "~1.6.18" - utils-merge "1.0.1" - vary "~1.1.2" - -ext-list@^2.0.0: - version "2.2.2" - resolved "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz" - integrity sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA== - dependencies: - mime-db "^1.28.0" - -ext-name@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz" - integrity sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ== - dependencies: - ext-list "^2.0.0" - sort-keys-length "^1.0.0" - -extend-shallow@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz" - integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= - dependencies: - is-extendable "^0.1.0" - -extend-shallow@^3.0.0, extend-shallow@^3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz" - integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= - dependencies: - assign-symbols "^1.0.0" - is-extendable "^1.0.1" - -extend@^3.0.0: - version "3.0.2" - resolved "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - -extglob@^2.0.4: - version "2.0.4" - resolved "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz" - integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== - dependencies: - array-unique "^0.3.2" - define-property "^1.0.0" - expand-brackets "^2.1.4" - extend-shallow "^2.0.1" - fragment-cache "^0.2.1" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== - -fast-diff@1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz" - integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== - -fast-equals@^2.0.0: - version "2.0.4" - resolved "https://registry.npmjs.org/fast-equals/-/fast-equals-2.0.4.tgz" - integrity sha512-caj/ZmjHljPrZtbzJ3kfH5ia/k4mTJe/qSiXAGzxZWRZgsgDV0cvNaQULqUX8t0/JVlzzEdYOwCN5DmzTxoD4w== - -fast-equals@^3.0.1: - version "3.0.3" - resolved "https://registry.yarnpkg.com/fast-equals/-/fast-equals-3.0.3.tgz#8e6cb4e51ca1018d87dd41982ef92758b3e4197f" - integrity sha512-NCe8qxnZFARSHGztGMZOO/PC1qa5MIFB5Hp66WdzbCRAz8U8US3bx1UTgLS49efBQPcUtO9gf5oVEY8o7y/7Kg== - -fast-glob@^3.0.3: - version "3.2.4" - resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz" - integrity sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.0" - merge2 "^1.3.0" - micromatch "^4.0.2" - picomatch "^2.2.1" - -fast-glob@^3.2.11, fast-glob@^3.3.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" - integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.2" - merge2 "^1.3.0" - micromatch "^4.0.4" - -fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== - -fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: - version "2.0.6" - resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= - -fast-plist@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/fast-plist/-/fast-plist-0.1.3.tgz#328cd9335e93a2479ac90814a1302437574ea925" - integrity sha512-d9cEfo/WcOezgPLAC/8t8wGb6YOD6JTCPMw2QcG2nAdFmyY+9rTUizCTaGjIZAloWENTEUMAPpkUAIJJJ0i96A== - -fast-safe-stringify@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884" - integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA== - -fast-xml-parser@^4.1.3: - version "4.4.1" - resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz#86dbf3f18edf8739326447bcaac31b4ae7f6514f" - integrity sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw== - dependencies: - strnum "^1.0.5" - -fastest-levenshtein@^1.0.12: - version "1.0.16" - resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5" - integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg== - -fastq@^1.6.0: - version "1.8.0" - resolved "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz" - integrity sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q== - dependencies: - reusify "^1.0.4" - -faye-websocket@^0.11.3: - version "0.11.4" - resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.4.tgz#7f0d9275cfdd86a1c963dc8b65fcc451edcbb1da" - integrity sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g== - dependencies: - websocket-driver ">=0.5.1" - -fb-watchman@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz" - integrity sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg== - dependencies: - bser "2.1.1" - -fd-slicer@~1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz" - integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4= - dependencies: - pend "~1.2.0" - -file-entry-cache@^5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz" - integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== - dependencies: - flat-cache "^2.0.1" - -file-loader@^6.2.0: - version "6.2.0" - resolved "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz" - integrity sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw== - dependencies: - loader-utils "^2.0.0" - schema-utils "^3.0.0" - -file-type@5.2.0, file-type@^5.2.0: - version "5.2.0" - resolved "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz" - integrity sha1-LdvqfHP/42No365J3DOMBYwritY= - -file-type@^10.4.0, file-type@^10.5.0: - version "10.11.0" - resolved "https://registry.npmjs.org/file-type/-/file-type-10.11.0.tgz" - integrity sha512-uzk64HRpUZyTGZtVuvrjP0FYxzQrBf4rojot6J65YMEbwBLB0CWm0CLojVpwpmFmxcE/lkvYICgfcGozbBq6rw== - -file-type@^12.0.0: - version "12.4.2" - resolved "https://registry.npmjs.org/file-type/-/file-type-12.4.2.tgz" - integrity sha512-UssQP5ZgIOKelfsaB5CuGAL+Y+q7EmONuiwF3N5HAH0t27rvrttgi6Ra9k/+DVaY9UF6+ybxu5pOXLUdA8N7Vg== - -file-type@^3.8.0: - version "3.9.0" - resolved "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz" - integrity sha1-JXoHg4TR24CHvESdEH1SpSZyuek= - -file-type@^4.2.0: - version "4.4.0" - resolved "https://registry.npmjs.org/file-type/-/file-type-4.4.0.tgz" - integrity sha1-G2AOX8ofvcboDApwxxyNul95BsU= - -file-type@^6.1.0: - version "6.2.0" - resolved "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz" - integrity sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg== - -file-type@^8.1.0: - version "8.1.0" - resolved "https://registry.npmjs.org/file-type/-/file-type-8.1.0.tgz" - integrity sha512-qyQ0pzAy78gVoJsmYeNgl8uH8yKhr1lVhW7JbzJmnlRi0I4R2eEDEJZVKG8agpDnLpacwNbDhLNG/LMdxHD2YQ== - -filename-reserved-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz" - integrity sha1-q/c9+rc10EVECr/qLZHzieu/oik= - -filenamify@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/filenamify/-/filenamify-2.1.0.tgz" - integrity sha512-ICw7NTT6RsDp2rnYKVd8Fu4cr6ITzGy3+u4vUujPkabyaz+03F24NWEX7fs5fp+kBonlaqPH8fAO2NM+SXt/JA== - dependencies: - filename-reserved-regex "^2.0.0" - strip-outer "^1.0.0" - trim-repeated "^1.0.0" - -fill-range@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz" - integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= - dependencies: - extend-shallow "^2.0.1" - is-number "^3.0.0" - repeat-string "^1.6.1" - to-regex-range "^2.1.0" - -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== - dependencies: - to-regex-range "^5.0.1" - -finalhandler@1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.3.1.tgz#0c575f1d1d324ddd1da35ad7ece3df7d19088019" - integrity sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ== - dependencies: - debug "2.6.9" - encodeurl "~2.0.0" - escape-html "~1.0.3" - on-finished "2.4.1" - parseurl "~1.3.3" - statuses "2.0.1" - unpipe "~1.0.0" - -find-cache-dir@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-4.0.0.tgz#a30ee0448f81a3990708f6453633c733e2f6eec2" - integrity sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg== - dependencies: - common-path-prefix "^3.0.0" - pkg-dir "^7.0.0" - -find-root@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz" - integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== - -find-up@^2.0.0, find-up@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz" - integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= - dependencies: - locate-path "^2.0.0" - -find-up@^4.0.0, find-up@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz" - integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== - dependencies: - locate-path "^5.0.0" - path-exists "^4.0.0" - -find-up@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" - integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== - dependencies: - locate-path "^6.0.0" - path-exists "^4.0.0" - -find-up@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-6.3.0.tgz#2abab3d3280b2dc7ac10199ef324c4e002c8c790" - integrity sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw== - dependencies: - locate-path "^7.1.0" - path-exists "^5.0.0" - -find-versions@^3.0.0: - version "3.2.0" - resolved "https://registry.npmjs.org/find-versions/-/find-versions-3.2.0.tgz" - integrity sha512-P8WRou2S+oe222TOCHitLy8zj+SIsVJh52VP4lvXkaFVnOFFdoWv1H1Jjvel1aI6NCFOAaeAVm8qrI0odiLcww== - dependencies: - semver-regex "^2.0.0" - -find@^0.2.4: - version "0.2.9" - resolved "https://registry.npmjs.org/find/-/find-0.2.9.tgz" - integrity sha1-S3Px/55WrZG3bnFkB/5f/mVUu4w= - dependencies: - traverse-chain "~0.1.0" - -flat-cache@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz" - integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== - dependencies: - flatted "^2.0.0" - rimraf "2.6.3" - write "1.0.3" - -flatted@^2.0.0: - version "2.0.2" - resolved "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz" - integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== - -fn-name@~3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/fn-name/-/fn-name-3.0.0.tgz" - integrity sha512-eNMNr5exLoavuAMhIUVsOKF79SWd/zG104ef6sxBTSw+cZc6BXdQXDvYcGvp0VbxVVSp1XDUNoz7mg1xMtSznA== - -follow-redirects@^1.0.0, follow-redirects@^1.15.0: - version "1.15.6" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" - integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== - -for-each@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" - integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== - dependencies: - is-callable "^1.1.3" - -for-in@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz" - integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= - -form-data@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz" - integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" - -form-data@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" - integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" - -formik@^2.2.5: - version "2.2.5" - resolved "https://registry.npmjs.org/formik/-/formik-2.2.5.tgz" - integrity sha512-KkOsyYmh5xsow+wlbdL9QSkqvbiHSb1RIToBKiooCFW4lyypn+ZlHGjTuuOqUWBqZaI5nCEupeI275Mo6tFBzg== - dependencies: - deepmerge "^2.1.1" - hoist-non-react-statics "^3.3.0" - lodash "^4.17.14" - lodash-es "^4.17.14" - react-fast-compare "^2.0.1" - tiny-warning "^1.0.2" - tslib "^1.10.0" - -forwarded@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" - integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== - -fragment-cache@^0.2.1: - version "0.2.1" - resolved "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz" - integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= - dependencies: - map-cache "^0.2.2" - -fresh@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" - integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== - -from2@^2.1.1: - version "2.3.0" - resolved "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz" - integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= - dependencies: - inherits "^2.0.1" - readable-stream "^2.0.0" - -fs-constants@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz" - integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== - -fs-monkey@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.3.tgz#ae3ac92d53bb328efe0e9a1d9541f6ad8d48e2d3" - integrity sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q== - -fs-readdir-recursive@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz" - integrity sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA== - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - -fsevents@^2.1.2, fsevents@^2.3.2, fsevents@~2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== - -fsevents@~2.1.2: - version "2.1.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e" - integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ== - -fstream@1.0.12, fstream@^1.0.12: - version "1.0.12" - resolved "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz" - integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg== - dependencies: - graceful-fs "^4.1.2" - inherits "~2.0.0" - mkdirp ">=0.5 0" - rimraf "2" - -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - -function-bind@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" - integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== - -function.prototype.name@^1.1.2: - version "1.1.3" - resolved "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.3.tgz" - integrity sha512-H51qkbNSp8mtkJt+nyW1gyStBiKZxfRqySNUR99ylq6BPXHKI4SEvIlTKp4odLfjRKJV04DFWMU3G/YRlQOsag== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - es-abstract "^1.18.0-next.1" - functions-have-names "^1.2.1" - -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= - -functions-have-names@^1.2.1: - version "1.2.2" - resolved "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.2.tgz" - integrity sha512-bLgc3asbWdwPbx2mNk2S49kmJCuQeu0nfmaOgbs8WIyzzkw3r4htszdIi9Q9EMezDPTYuJx2wvjZ/EwgAthpnA== - -functions-have-names@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" - integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== - -gensync@^1.0.0-beta.1: - version "1.0.0-beta.1" - resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz" - integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== - -gensync@^1.0.0-beta.2: - version "1.0.0-beta.2" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" - integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== - -get-caller-file@^2.0.1: - version "2.0.5" - resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" - integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== - -get-intrinsic@^1.0.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.3.tgz#063c84329ad93e83893c7f4f243ef63ffa351385" - integrity sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A== - dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.3" - -get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0, get-intrinsic@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz#d295644fed4505fc9cde952c37ee12b477a83d82" - integrity sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw== - dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-proto "^1.0.1" - has-symbols "^1.0.3" - -get-intrinsic@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" - integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== - dependencies: - es-errors "^1.3.0" - function-bind "^1.1.2" - has-proto "^1.0.1" - has-symbols "^1.0.3" - hasown "^2.0.0" - -get-package-type@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz" - integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== - -get-proxy@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/get-proxy/-/get-proxy-2.1.0.tgz" - integrity sha512-zmZIaQTWnNQb4R4fJUEp/FC51eZsc6EkErspy3xtIYStaq8EB/hDIWipxsal+E8rz0qD7f2sL/NA9Xee4RInJw== - dependencies: - npm-conf "^1.1.0" - -get-stream@3.0.0, get-stream@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz" - integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= - -get-stream@^2.2.0: - version "2.3.1" - resolved "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz" - integrity sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4= - dependencies: - object-assign "^4.0.1" - pinkie-promise "^2.0.0" - -get-stream@^4.0.0: - version "4.1.0" - resolved "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz" - integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== - dependencies: - pump "^3.0.0" - -get-stream@^5.0.0: - version "5.1.0" - resolved "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz" - integrity sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw== - dependencies: - pump "^3.0.0" - -get-stream@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" - integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== - -get-value@^2.0.3, get-value@^2.0.6: - version "2.0.6" - resolved "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz" - integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= - -gettext-parser@^1.1.2, gettext-parser@^1.2.0: - version "1.4.0" - resolved "https://registry.npmjs.org/gettext-parser/-/gettext-parser-1.4.0.tgz" - integrity sha512-sedZYLHlHeBop/gZ1jdg59hlUEcpcZJofLq2JFwJT1zTqAU3l2wFv6IsuwFHGqbiT9DWzMUW4/em2+hspnmMMA== - dependencies: - encoding "^0.1.12" - safe-buffer "^5.1.1" - -gifsicle@^5.0.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/gifsicle/-/gifsicle-5.3.0.tgz#499713c6f1e89ebbc3630da3a74fdb4697913b4e" - integrity sha512-FJTpgdj1Ow/FITB7SVza5HlzXa+/lqEY0tHQazAJbuAdvyJtkH4wIdsR2K414oaTwRXHFLLF+tYbipj+OpYg+Q== - dependencies: - bin-build "^3.0.0" - bin-wrapper "^4.0.0" - execa "^5.0.0" - -glob-parent@^5.0.0, glob-parent@^5.1.0, glob-parent@^5.1.2, glob-parent@~5.1.0, glob-parent@~5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - -glob-parent@^6.0.1: - version "6.0.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" - integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== - dependencies: - is-glob "^4.0.3" - -glob-to-regexp@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" - integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== - -glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: - version "7.1.6" - resolved "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz" - integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== - 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" - -glob@^7.2.0: - version "7.2.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" - integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.1.1" - once "^1.3.0" - path-is-absolute "^1.0.0" - -global-cache@^1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/global-cache/-/global-cache-1.2.1.tgz" - integrity sha512-EOeUaup5DgWKlCMhA9YFqNRIlZwoxt731jCh47WBV9fQqHgXhr3Fa55hfgIUqilIcPsfdNKN7LHjrNY+Km40KA== - dependencies: - define-properties "^1.1.2" - is-symbol "^1.0.1" - -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - -globals@^12.1.0: - version "12.4.0" - resolved "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz" - integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== - dependencies: - type-fest "^0.8.1" - -globby@^10.0.0: - version "10.0.2" - resolved "https://registry.npmjs.org/globby/-/globby-10.0.2.tgz" - integrity sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg== - dependencies: - "@types/glob" "^7.1.1" - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.0.3" - glob "^7.1.3" - ignore "^5.1.1" - merge2 "^1.2.3" - slash "^3.0.0" - -globby@^13.1.1: - version "13.2.2" - resolved "https://registry.yarnpkg.com/globby/-/globby-13.2.2.tgz#63b90b1bf68619c2135475cbd4e71e66aa090592" - integrity sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w== - dependencies: - dir-glob "^3.0.1" - fast-glob "^3.3.0" - ignore "^5.2.4" - merge2 "^1.4.1" - slash "^4.0.0" - -gopd@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" - integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== - dependencies: - get-intrinsic "^1.1.3" - -got@^7.0.0: - version "7.1.0" - resolved "https://registry.npmjs.org/got/-/got-7.1.0.tgz" - integrity sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw== - dependencies: - decompress-response "^3.2.0" - duplexer3 "^0.1.4" - get-stream "^3.0.0" - is-plain-obj "^1.1.0" - is-retry-allowed "^1.0.0" - is-stream "^1.0.0" - isurl "^1.0.0-alpha5" - lowercase-keys "^1.0.0" - p-cancelable "^0.3.0" - p-timeout "^1.1.1" - safe-buffer "^5.0.1" - timed-out "^4.0.0" - url-parse-lax "^1.0.0" - url-to-options "^1.0.1" - -got@^8.3.1: - version "8.3.2" - resolved "https://registry.npmjs.org/got/-/got-8.3.2.tgz" - integrity sha512-qjUJ5U/hawxosMryILofZCkm3C84PLJS/0grRIpjAwu+Lkxxj5cxeCU25BG0/3mDSpXKTyZr8oh8wIgLaH0QCw== - dependencies: - "@sindresorhus/is" "^0.7.0" - cacheable-request "^2.1.1" - decompress-response "^3.3.0" - duplexer3 "^0.1.4" - get-stream "^3.0.0" - into-stream "^3.1.0" - is-retry-allowed "^1.1.0" - isurl "^1.0.0-alpha5" - lowercase-keys "^1.0.0" - mimic-response "^1.0.0" - p-cancelable "^0.4.0" - p-timeout "^2.0.1" - pify "^3.0.0" - safe-buffer "^5.1.1" - timed-out "^4.0.1" - url-parse-lax "^3.0.0" - url-to-options "^1.0.1" - -graceful-fs@^4.1.10, graceful-fs@^4.1.2, graceful-fs@^4.2.11, graceful-fs@^4.2.2, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: - version "4.2.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" - integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== - -"graceful-readlink@>= 1.0.0": - version "1.0.1" - resolved "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz" - integrity sha1-TK+tdrxi8C+gObL5Tpo906ORpyU= - -growly@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz" - integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= - -gud@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/gud/-/gud-1.0.0.tgz" - integrity sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw== - -gzip-size@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-6.0.0.tgz#065367fd50c239c0671cbcbad5be3e2eeb10e462" - integrity sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q== - dependencies: - duplexer "^0.1.2" - -handle-thing@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.1.tgz#857f79ce359580c340d43081cc648970d0bb234e" - integrity sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg== - -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz" - integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= - dependencies: - ansi-regex "^2.0.0" - -has-bigints@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" - integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -has-property-descriptors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861" - integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== - dependencies: - get-intrinsic "^1.1.1" - -has-property-descriptors@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" - integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== - dependencies: - es-define-property "^1.0.0" - -has-proto@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" - integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== - -has-symbol-support-x@^1.4.1: - version "1.4.2" - resolved "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz" - integrity sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw== - -has-symbols@^1.0.0, has-symbols@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz" - integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== - -has-symbols@^1.0.2, has-symbols@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" - integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== - -has-to-string-tag-x@^1.2.0: - version "1.4.1" - resolved "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz" - integrity sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw== - dependencies: - has-symbol-support-x "^1.4.1" - -has-tostringtag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" - integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== - dependencies: - has-symbols "^1.0.2" - -has-value@^0.3.1: - version "0.3.1" - resolved "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz" - integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= - dependencies: - get-value "^2.0.3" - has-values "^0.1.4" - isobject "^2.0.0" - -has-value@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz" - integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= - dependencies: - get-value "^2.0.6" - has-values "^1.0.0" - isobject "^3.0.0" - -has-values@^0.1.4: - version "0.1.4" - resolved "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz" - integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= - -has-values@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz" - integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= - dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" - -has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" - -hasown@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" - integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== - dependencies: - function-bind "^1.1.2" - -hast-util-from-dom@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/hast-util-from-dom/-/hast-util-from-dom-5.0.0.tgz#d32edd25bf28f4b178b5ae318f8d05762e67bd16" - integrity sha512-d6235voAp/XR3Hh5uy7aGLbM3S4KamdW0WEgOaU1YoewnuYw4HXb5eRtv9g65m/RFGEfUY1Mw4UqCc5Y8L4Stg== - dependencies: - "@types/hast" "^3.0.0" - hastscript "^8.0.0" - web-namespaces "^2.0.0" - -hast-util-from-html-isomorphic@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/hast-util-from-html-isomorphic/-/hast-util-from-html-isomorphic-2.0.0.tgz#b31baee386a899a2472326a3c5692f29f86d1d3c" - integrity sha512-zJfpXq44yff2hmE0XmwEOzdWin5xwH+QIhMLOScpX91e/NSGPsAzNCvLQDIEPyO2TXi+lBmU6hjLIhV8MwP2kw== - dependencies: - "@types/hast" "^3.0.0" - hast-util-from-dom "^5.0.0" - hast-util-from-html "^2.0.0" - unist-util-remove-position "^5.0.0" - -hast-util-from-html@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/hast-util-from-html/-/hast-util-from-html-2.0.1.tgz#9cd38ee81bf40b2607368b92a04b0905fa987488" - integrity sha512-RXQBLMl9kjKVNkJTIO6bZyb2n+cUH8LFaSSzo82jiLT6Tfc+Pt7VQCS+/h3YwG4jaNE2TA2sdJisGWR+aJrp0g== - dependencies: - "@types/hast" "^3.0.0" - devlop "^1.1.0" - hast-util-from-parse5 "^8.0.0" - parse5 "^7.0.0" - vfile "^6.0.0" - vfile-message "^4.0.0" - -hast-util-from-parse5@^8.0.0: - version "8.0.1" - resolved "https://registry.yarnpkg.com/hast-util-from-parse5/-/hast-util-from-parse5-8.0.1.tgz#654a5676a41211e14ee80d1b1758c399a0327651" - integrity sha512-Er/Iixbc7IEa7r/XLtuG52zoqn/b3Xng/w6aZQ0xGVxzhw5xUFxcRqdPzP6yFi/4HBYRaifaI5fQ1RH8n0ZeOQ== - dependencies: - "@types/hast" "^3.0.0" - "@types/unist" "^3.0.0" - devlop "^1.0.0" - hastscript "^8.0.0" - property-information "^6.0.0" - vfile "^6.0.0" - vfile-location "^5.0.0" - web-namespaces "^2.0.0" - -hast-util-is-element@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz#6e31a6532c217e5b533848c7e52c9d9369ca0932" - integrity sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g== - dependencies: - "@types/hast" "^3.0.0" - -hast-util-parse-selector@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz#352879fa86e25616036037dd8931fb5f34cb4a27" - integrity sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A== - dependencies: - "@types/hast" "^3.0.0" - -hast-util-to-jsx-runtime@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.0.tgz#3ed27caf8dc175080117706bf7269404a0aa4f7c" - integrity sha512-H/y0+IWPdsLLS738P8tDnrQ8Z+dj12zQQ6WC11TIM21C8WFVoIxcqWXf2H3hiTVZjF1AWqoimGwrTWecWrnmRQ== - dependencies: - "@types/estree" "^1.0.0" - "@types/hast" "^3.0.0" - "@types/unist" "^3.0.0" - comma-separated-tokens "^2.0.0" - devlop "^1.0.0" - estree-util-is-identifier-name "^3.0.0" - hast-util-whitespace "^3.0.0" - mdast-util-mdx-expression "^2.0.0" - mdast-util-mdx-jsx "^3.0.0" - mdast-util-mdxjs-esm "^2.0.0" - property-information "^6.0.0" - space-separated-tokens "^2.0.0" - style-to-object "^1.0.0" - unist-util-position "^5.0.0" - vfile-message "^4.0.0" - -hast-util-to-text@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/hast-util-to-text/-/hast-util-to-text-4.0.2.tgz#57b676931e71bf9cb852453678495b3080bfae3e" - integrity sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A== - dependencies: - "@types/hast" "^3.0.0" - "@types/unist" "^3.0.0" - hast-util-is-element "^3.0.0" - unist-util-find-after "^5.0.0" - -hast-util-whitespace@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz#7778ed9d3c92dd9e8c5c8f648a49c21fc51cb621" - integrity sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw== - dependencies: - "@types/hast" "^3.0.0" - -hastscript@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-8.0.0.tgz#4ef795ec8dee867101b9f23cc830d4baf4fd781a" - integrity sha512-dMOtzCEd3ABUeSIISmrETiKuyydk1w0pa+gE/uormcTpSYuaNJPbX1NU3JLyscSLjwAQM8bWMhhIlnCqnRvDTw== - dependencies: - "@types/hast" "^3.0.0" - comma-separated-tokens "^2.0.0" - hast-util-parse-selector "^4.0.0" - property-information "^6.0.0" - space-separated-tokens "^2.0.0" - -hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.2.1, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2: - version "3.3.2" - resolved "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz" - integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== - dependencies: - react-is "^16.7.0" - -hosted-git-info@^2.1.4: - version "2.8.8" - resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz" - integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== - -howler@^2.2.1: - version "2.2.1" - resolved "https://registry.npmjs.org/howler/-/howler-2.2.1.tgz" - integrity sha512-0iIXvuBO/81CcrQ/HSSweYmbT50fT2mIc9XMFb+kxIfk2pW/iKzDbX1n3fZmDXMEIpYvyyfrB+gXwPYSDqUxIQ== - -hpack.js@^2.1.6: - version "2.1.6" - resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" - integrity sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ== - dependencies: - inherits "^2.0.1" - obuf "^1.0.0" - readable-stream "^2.0.1" - wbuf "^1.1.0" - -html-encoding-sniffer@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz" - integrity sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ== - dependencies: - whatwg-encoding "^1.0.5" - -html-entities@^2.1.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.4.0.tgz#edd0cee70402584c8c76cc2c0556db09d1f45061" - integrity sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ== - -html-entities@^2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.3.3.tgz#117d7626bece327fc8baace8868fa6f5ef856e46" - integrity sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA== - -html-escaper@^2.0.0: - version "2.0.2" - resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz" - integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== - -html-tags@1: - version "1.2.0" - resolved "https://registry.npmjs.org/html-tags/-/html-tags-1.2.0.tgz" - integrity sha1-x43mW1Zjqll5id0rerSSANfk25g= - -html-url-attributes@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/html-url-attributes/-/html-url-attributes-3.0.0.tgz#fc4abf0c3fb437e2329c678b80abb3c62cff6f08" - integrity sha512-/sXbVCWayk6GDVg3ctOX6nxaVj7So40FcFAnWlWGNAB1LpYKcV5Cd10APjPjW80O7zYW2MsjBV4zZ7IZO5fVow== - -http-cache-semantics@3.8.1: - version "3.8.1" - resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz" - integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== - -http-deceiver@^1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" - integrity sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw== - -http-errors@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" - integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== - dependencies: - depd "2.0.0" - inherits "2.0.4" - setprototypeof "1.2.0" - statuses "2.0.1" - toidentifier "1.0.1" - -http-errors@~1.6.2: - version "1.6.3" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" - integrity sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A== - dependencies: - depd "~1.1.2" - inherits "2.0.3" - setprototypeof "1.1.0" - statuses ">= 1.4.0 < 2" - -http-parser-js@>=0.5.1: - version "0.5.8" - resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.8.tgz#af23090d9ac4e24573de6f6aecc9d84a48bf20e3" - integrity sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q== - -http-proxy-agent@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz" - integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== - dependencies: - "@tootallnate/once" "1" - agent-base "6" - debug "4" - -http-proxy-middleware@^2.0.3: - version "2.0.7" - resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz#915f236d92ae98ef48278a95dedf17e991936ec6" - integrity sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA== - dependencies: - "@types/http-proxy" "^1.17.8" - http-proxy "^1.18.1" - is-glob "^4.0.1" - is-plain-obj "^3.0.0" - micromatch "^4.0.2" - -http-proxy@^1.18.1: - version "1.18.1" - resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" - integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== - dependencies: - eventemitter3 "^4.0.0" - follow-redirects "^1.0.0" - requires-port "^1.0.0" - -https-proxy-agent@^5.0.0: - version "5.0.1" - resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz" - integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== - dependencies: - agent-base "6" - debug "4" - -human-signals@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz" - integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== - -human-signals@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" - integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== - -humps@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/humps/-/humps-2.0.1.tgz" - integrity sha1-3QLqYIG9BWjcXQcxhEY5V7qe+ao= - -i18next-conv@^3.0.1: - version "3.0.3" - resolved "https://registry.npmjs.org/i18next-conv/-/i18next-conv-3.0.3.tgz" - integrity sha1-yOZgaS3H3WgvWdkO6czcV61meW4= - dependencies: - bluebird "^3.4.1" - chalk "^1.1.3" - commander "^2.9.0" - gettext-parser "^1.2.0" - mkdirp "^0.5.1" - node-gettext "^1.1.0" - object-assign "^4.1.0" - pkginfo "^0.4.0" - -i18next-po-loader@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/i18next-po-loader/-/i18next-po-loader-1.0.1.tgz" - integrity sha512-+DNnVY1jMyn60msU6UvX4aEOyQd5f+KwnCsR39Qh8dkI6Ybl1aXO1hXLnXGcAzvkVHQm5EDpot6RE0B/NfZOPg== - dependencies: - i18next-conv "^3.0.1" - -i18next@^19.8.4: - version "19.8.4" - resolved "https://registry.npmjs.org/i18next/-/i18next-19.8.4.tgz" - integrity sha512-FfVPNWv+felJObeZ6DSXZkj9QM1Ivvh7NcFCgA8XPtJWHz0iXVa9BUy+QY8EPrCLE+vWgDfV/sc96BgXVo6HAA== - dependencies: - "@babel/runtime" "^7.12.0" - -iconv-lite@0.4.24: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - -iconv-lite@^0.6.2: - version "0.6.2" - resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz" - integrity sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ== - dependencies: - safer-buffer ">= 2.1.2 < 3.0.0" - -icss-utils@^5.0.0, icss-utils@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" - integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA== - -ieee754@^1.1.4: - version "1.2.1" - resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz" - integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== - -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - -ignore@^5.1.1: - version "5.1.8" - resolved "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz" - integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== - -ignore@^5.2.4: - version "5.2.4" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" - integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== - -image-webpack-loader@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/image-webpack-loader/-/image-webpack-loader-8.1.0.tgz#cd97172e1e7304ef5eb898344fc25bbb650fc7d7" - integrity sha512-bxzMIBNu42KGo6Bc9YMB0QEUt+XuVTl2ZSX3oGAlbsqYOkxkT4TEWvVsnwUkCRCYISJrMCEc/s0y8OYrmEfUOg== - dependencies: - imagemin "^7.0.1" - loader-utils "^2.0.0" - object-assign "^4.1.1" - schema-utils "^2.7.1" - optionalDependencies: - imagemin-gifsicle "^7.0.0" - imagemin-mozjpeg "^9.0.0" - imagemin-optipng "^8.0.0" - imagemin-pngquant "^9.0.2" - imagemin-svgo "^9.0.0" - imagemin-webp "^7.0.0" - -imagemin-gifsicle@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/imagemin-gifsicle/-/imagemin-gifsicle-7.0.0.tgz#1a7ab136a144c4678657ba3b6c412f80805d26b0" - integrity sha512-LaP38xhxAwS3W8PFh4y5iQ6feoTSF+dTAXFRUEYQWYst6Xd+9L/iPk34QGgK/VO/objmIlmq9TStGfVY2IcHIA== - dependencies: - execa "^1.0.0" - gifsicle "^5.0.0" - is-gif "^3.0.0" - -imagemin-mozjpeg@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/imagemin-mozjpeg/-/imagemin-mozjpeg-9.0.0.tgz#d1af26d0b43d75a41c211051c1910da59d9d2324" - integrity sha512-TwOjTzYqCFRgROTWpVSt5UTT0JeCuzF1jswPLKALDd89+PmrJ2PdMMYeDLYZ1fs9cTovI9GJd68mRSnuVt691w== - dependencies: - execa "^4.0.0" - is-jpg "^2.0.0" - mozjpeg "^7.0.0" - -imagemin-optipng@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/imagemin-optipng/-/imagemin-optipng-8.0.0.tgz#b88e5cf6da25cc8479e07cdf38c3ae0479df7ef2" - integrity sha512-CUGfhfwqlPjAC0rm8Fy+R2DJDBGjzy2SkfyT09L8rasnF9jSoHFqJ1xxSZWK6HVPZBMhGPMxCTL70OgTHlLF5A== - dependencies: - exec-buffer "^3.0.0" - is-png "^2.0.0" - optipng-bin "^7.0.0" - -imagemin-pngquant@^9.0.2: - version "9.0.2" - resolved "https://registry.yarnpkg.com/imagemin-pngquant/-/imagemin-pngquant-9.0.2.tgz#38155702b0cc4f60f671ba7c2b086ea3805d9567" - integrity sha512-cj//bKo8+Frd/DM8l6Pg9pws1pnDUjgb7ae++sUX1kUVdv2nrngPykhiUOgFeE0LGY/LmUbCf4egCHC4YUcZSg== - dependencies: - execa "^4.0.0" - is-png "^2.0.0" - is-stream "^2.0.0" - ow "^0.17.0" - pngquant-bin "^6.0.0" - -imagemin-svgo@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/imagemin-svgo/-/imagemin-svgo-9.0.0.tgz#749370804608917a67d4ff590f07a87756aec006" - integrity sha512-uNgXpKHd99C0WODkrJ8OO/3zW3qjgS4pW7hcuII0RcHN3tnKxDjJWcitdVC/TZyfIqSricU8WfrHn26bdSW62g== - dependencies: - is-svg "^4.2.1" - svgo "^2.1.0" - -imagemin-webp@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/imagemin-webp/-/imagemin-webp-7.0.0.tgz#df000ec927855d74d4cfafec8558ac418c88d2a9" - integrity sha512-JoYjvHNgBLgrQAkeCO7T5iNc8XVpiBmMPZmiXMhalC7K6gwY/3DCEUfNxVPOmNJ+NIJlJFvzcMR9RBxIE74Xxw== - dependencies: - cwebp-bin "^7.0.1" - exec-buffer "^3.2.0" - is-cwebp-readable "^3.0.0" - -imagemin@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/imagemin/-/imagemin-7.0.1.tgz#f6441ca647197632e23db7d971fffbd530c87dbf" - integrity sha512-33AmZ+xjZhg2JMCe+vDf6a9mzWukE7l+wAtesjE7KyteqqKjzxv7aVQeWnul1Ve26mWvEQqyPwl0OctNBfSR9w== - dependencies: - file-type "^12.0.0" - globby "^10.0.0" - graceful-fs "^4.2.2" - junk "^3.1.0" - make-dir "^3.0.0" - p-pipe "^3.0.0" - replace-ext "^1.0.0" - -immer@^9.0.6: - version "9.0.6" - resolved "https://registry.npmjs.org/immer/-/immer-9.0.6.tgz" - integrity sha512-G95ivKpy+EvVAnAab4fVa4YGYn24J1SpEktnJX7JJ45Bd7xqME/SCplFzYFmTbrkwZbQ4xJK1xMTUYBkN6pWsQ== - -immutable@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/immutable/-/immutable-4.0.0.tgz" - integrity sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw== - -import-fresh@^3.0.0: - version "3.2.1" - resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz" - integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - -import-fresh@^3.2.1: - version "3.2.2" - resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.2.tgz" - integrity sha512-cTPNrlvJT6twpYy+YmKUKrTSjWFs3bjYjAhCwm+z4EOCubZxAuO+hHpRN64TqjEaYSHs7tJAE0w1CKMGmsG/lw== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - -import-lazy@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/import-lazy/-/import-lazy-3.1.0.tgz" - integrity sha512-8/gvXvX2JMn0F+CDlSC4l6kOmVaLOO3XLkksI7CI3Ud95KDYJuYur2b9P/PUt/i/pDAMd/DulQsNbbbmRRsDIQ== - -import-local@^3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz" - integrity sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA== - dependencies: - pkg-dir "^4.2.0" - resolve-cwd "^3.0.0" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= - -indent-string@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz" - integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== - -indexes-of@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz" - integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc= - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.3: - version "2.0.4" - resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -inherits@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== - -ini@^1.3.4: - version "1.3.5" - resolved "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz" - integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== - -inline-style-parser@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.2.3.tgz#e35c5fb45f3a83ed7849fe487336eb7efa25971c" - integrity sha512-qlD8YNDqyTKTyuITrDOffsl6Tdhv+UC4hcdAVuQsK4IMQ99nSgd1MIA/Q+jQYoh9r3hVUXhYh7urSRmXPkW04g== - -internal-slot@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.2.tgz" - integrity sha512-2cQNfwhAfJIkU4KZPkDI+Gj5yNNnbqi40W9Gge6dfnk4TocEVm00B3bdiL+JINrbGJil2TeHvM4rETGzk/f/0g== - dependencies: - es-abstract "^1.17.0-next.1" - has "^1.0.3" - side-channel "^1.0.2" - -internal-slot@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.5.tgz#f2a2ee21f668f8627a4667f309dc0f4fb6674986" - integrity sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ== - dependencies: - get-intrinsic "^1.2.0" - has "^1.0.3" - side-channel "^1.0.4" - -internmap@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz" - integrity sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw== - -interpret@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-3.1.1.tgz#5be0ceed67ca79c6c4bc5cf0d7ee843dcea110c4" - integrity sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ== - -into-stream@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz" - integrity sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY= - dependencies: - from2 "^2.1.1" - p-is-promise "^1.1.0" - -invariant@^2.2.4: - version "2.2.4" - resolved "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz" - integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== - dependencies: - loose-envify "^1.0.0" - -ipaddr.js@1.9.1: - version "1.9.1" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" - integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== - -ipaddr.js@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.0.1.tgz#eca256a7a877e917aeb368b0a7497ddf42ef81c0" - integrity sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng== - -is-accessor-descriptor@^0.1.6: - version "0.1.6" - resolved "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz" - integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= - dependencies: - kind-of "^3.0.2" - -is-accessor-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz" - integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== - dependencies: - kind-of "^6.0.0" - -is-alphabetical@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-2.0.1.tgz#01072053ea7c1036df3c7d19a6daaec7f19e789b" - integrity sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ== - -is-alphanumerical@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz#7c03fbe96e3e931113e57f964b0a368cc2dfd875" - integrity sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw== - dependencies: - is-alphabetical "^2.0.0" - is-decimal "^2.0.0" - -is-arguments@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz" - integrity sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA== - -is-arguments@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" - integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" - integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.2.0" - is-typed-array "^1.1.10" - -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" - integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= - -is-bigint@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" - integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== - dependencies: - has-bigints "^1.0.1" - -is-binary-path@~2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz" - integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== - dependencies: - binary-extensions "^2.0.0" - -is-boolean-object@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" - integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-buffer@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== - -is-callable@^1.1.3: - version "1.2.7" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" - integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== - -is-callable@^1.1.4, is-callable@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz" - integrity sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw== - -is-callable@^1.2.2: - version "1.2.2" - resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz" - integrity sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA== - -is-ci@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz" - integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== - dependencies: - ci-info "^2.0.0" - -is-core-module@^2.1.0: - version "2.2.0" - resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz" - integrity sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ== - dependencies: - has "^1.0.3" - -is-core-module@^2.13.0: - version "2.13.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.0.tgz#bb52aa6e2cbd49a30c2ba68c42bf3435ba6072db" - integrity sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ== - dependencies: - has "^1.0.3" - -is-core-module@^2.9.0: - version "2.11.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144" - integrity sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw== - dependencies: - has "^1.0.3" - -is-cwebp-readable@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-cwebp-readable/-/is-cwebp-readable-3.0.0.tgz#0554aaa400977a2fc4de366d8c0244f13cde58cb" - integrity sha512-bpELc7/Q1/U5MWHn4NdHI44R3jxk0h9ew9ljzabiRl70/UIjL/ZAqRMb52F5+eke/VC8yTiv4Ewryo1fPWidvA== - dependencies: - file-type "^10.5.0" - -is-data-descriptor@^0.1.4: - version "0.1.4" - resolved "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz" - integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= - dependencies: - kind-of "^3.0.2" - -is-data-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz" - integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== - dependencies: - kind-of "^6.0.0" - -is-date-object@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz" - integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== - -is-date-object@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" - integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== - dependencies: - has-tostringtag "^1.0.0" - -is-decimal@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-2.0.1.tgz#9469d2dc190d0214fd87d78b78caecc0cc14eef7" - integrity sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A== - -is-descriptor@^0.1.0: - version "0.1.6" - resolved "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz" - integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== - dependencies: - is-accessor-descriptor "^0.1.6" - is-data-descriptor "^0.1.4" - kind-of "^5.0.0" - -is-descriptor@^1.0.0, is-descriptor@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz" - integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== - dependencies: - is-accessor-descriptor "^1.0.0" - is-data-descriptor "^1.0.0" - kind-of "^6.0.2" - -is-docker@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/is-docker/-/is-docker-2.0.0.tgz" - integrity sha512-pJEdRugimx4fBMra5z2/5iRdZ63OhYV0vr0Dwm5+xtW4D1FvRkB8hamMIhnWfyJeDdyr/aa7BDyNbtG38VxgoQ== - -is-docker@^2.1.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" - integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== - -is-extendable@^0.1.0, is-extendable@^0.1.1: - version "0.1.1" - resolved "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz" - integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= - -is-extendable@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz" - integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== - dependencies: - is-plain-object "^2.0.4" - -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz" - integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -is-generator-fn@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz" - integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== - -is-gif@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/is-gif/-/is-gif-3.0.0.tgz" - integrity sha512-IqJ/jlbw5WJSNfwQ/lHEDXF8rxhRgF6ythk2oiEvhpG29F704eX9NO6TvPfMiq9DrbwgcEDnETYNcZDPewQoVw== - dependencies: - file-type "^10.4.0" - -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz" - integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== - dependencies: - is-extglob "^2.1.1" - -is-glob@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" - integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== - dependencies: - is-extglob "^2.1.1" - -is-hexadecimal@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz#86b5bf668fca307498d319dfc03289d781a90027" - integrity sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg== - -is-jpg@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/is-jpg/-/is-jpg-2.0.0.tgz" - integrity sha1-LhmX+m6RZuqsAkLarkQ0A+TvHZc= - -is-lite@^0.8.2: - version "0.8.2" - resolved "https://registry.yarnpkg.com/is-lite/-/is-lite-0.8.2.tgz#26ab98b32aae8cc8b226593b9a641d2bf4bd3b6a" - integrity sha512-JZfH47qTsslwaAsqbMI3Q6HNNjUuq6Cmzzww50TdP5Esb6e1y2sK2UAaZZuzfAzpoI2AkxoPQapZdlDuP6Vlsw== - -is-lite@^0.9.2: - version "0.9.3" - resolved "https://registry.yarnpkg.com/is-lite/-/is-lite-0.9.3.tgz#b59cbc7b12e164bc68f263fd32b3d37150cc93bf" - integrity sha512-lbyynwsRRUMh1fHEinXkde/thdjj8OpW/okyGAVgmW4r/FkCEP966oSEg0B8ON5+mm73MJjFXB4ZViuaAldw4g== - -is-map@^2.0.1, is-map@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" - integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg== - -is-natural-number@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz" - integrity sha1-q5124dtM7VHjXeDHLr7PCfc0zeg= - -is-negative-zero@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz" - integrity sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE= - -is-number-object@^1.0.4: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" - integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== - dependencies: - has-tostringtag "^1.0.0" - -is-number@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz" - integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= - dependencies: - kind-of "^3.0.2" - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - -is-object@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz" - integrity sha1-iVJojF7C/9awPsyF52ngKQMINHA= - -is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz" - integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= - -is-plain-obj@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-3.0.0.tgz#af6f2ea14ac5a646183a5bbdb5baabbc156ad9d7" - integrity sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA== - -is-plain-obj@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-4.1.0.tgz#d65025edec3657ce032fd7db63c97883eaed71f0" - integrity sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg== - -is-plain-object@^2.0.3, is-plain-object@^2.0.4: - version "2.0.4" - resolved "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz" - integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== - dependencies: - isobject "^3.0.1" - -is-png@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/is-png/-/is-png-2.0.0.tgz" - integrity sha512-4KPGizaVGj2LK7xwJIz8o5B2ubu1D/vcQsgOGFEDlpcvgZHto4gBnyd0ig7Ws+67ixmwKoNmu0hYnpo6AaKb5g== - -is-potential-custom-element-name@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz" - integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== - -is-regex@^1.0.4, is-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz" - integrity sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw== - dependencies: - has-symbols "^1.0.1" - -is-regex@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz" - integrity sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg== - dependencies: - has-symbols "^1.0.1" - -is-regex@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" - integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-retry-allowed@^1.0.0, is-retry-allowed@^1.1.0: - version "1.2.0" - resolved "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz" - integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg== - -is-set@^2.0.1, is-set@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec" - integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g== - -is-shared-array-buffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" - integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== - dependencies: - call-bind "^1.0.2" - -is-stream@^1.0.0, is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz" - integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= - -is-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz" - integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== - -is-string@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz" - integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ== - -is-string@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" - integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== - dependencies: - has-tostringtag "^1.0.0" - -is-svg@^4.2.1: - version "4.4.0" - resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-4.4.0.tgz#34db20a38146be5f2b3060154da33d11e6f74b7c" - integrity sha512-v+AgVwiK5DsGtT9ng+m4mClp6zDAmwrW8nZi6Gg15qzvBnRWWdfWA1TGaXyCDnWq5g5asofIgMVl3PjKxvk1ug== - dependencies: - fast-xml-parser "^4.1.3" - -is-symbol@^1.0.1, is-symbol@^1.0.2: - version "1.0.3" - resolved "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz" - integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== - dependencies: - has-symbols "^1.0.1" - -is-symbol@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" - integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== - dependencies: - has-symbols "^1.0.2" - -is-touch-device@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/is-touch-device/-/is-touch-device-1.0.1.tgz" - integrity sha512-LAYzo9kMT1b2p19L/1ATGt2XcSilnzNlyvq6c0pbPRVisLbAPpLqr53tIJS00kvrTkj0HtR8U7+u8X0yR8lPSw== - -is-typed-array@^1.1.10: - version "1.1.12" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.12.tgz#d0bab5686ef4a76f7a73097b95470ab199c57d4a" - integrity sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg== - dependencies: - which-typed-array "^1.1.11" - -is-typedarray@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz" - integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= - -is-weakmap@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.1.tgz#5008b59bdc43b698201d18f62b37b2ca243e8cf2" - integrity sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA== - -is-weakset@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.2.tgz#4569d67a747a1ce5a994dfd4ef6dcea76e7c0a1d" - integrity sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.1" - -is-windows@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz" - integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== - -is-wsl@^2.2.0: - version "2.2.0" - resolved "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz" - integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== - dependencies: - is-docker "^2.0.0" - -is_js@^0.9.0: - version "0.9.0" - resolved "https://registry.npmjs.org/is_js/-/is_js-0.9.0.tgz" - integrity sha1-CrlFQFArp6+iTIVqqYVWFmnpxS0= - -isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= - -isarray@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" - integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - -isobject@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz" - integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= - dependencies: - isarray "1.0.0" - -isobject@^3.0.0, isobject@^3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz" - integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= - -istanbul-lib-coverage@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz" - integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg== - -istanbul-lib-coverage@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" - integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== - -istanbul-lib-instrument@^4.0.0, istanbul-lib-instrument@^4.0.3: - version "4.0.3" - resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz" - integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ== - dependencies: - "@babel/core" "^7.7.5" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-coverage "^3.0.0" - semver "^6.3.0" - -istanbul-lib-instrument@^5.0.4: - version "5.2.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" - integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== - dependencies: - "@babel/core" "^7.12.3" - "@babel/parser" "^7.14.7" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-coverage "^3.2.0" - semver "^6.3.0" - -istanbul-lib-report@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz" - integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== - dependencies: - istanbul-lib-coverage "^3.0.0" - make-dir "^3.0.0" - supports-color "^7.1.0" - -istanbul-lib-source-maps@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz" - integrity sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg== - dependencies: - debug "^4.1.1" - istanbul-lib-coverage "^3.0.0" - source-map "^0.6.1" - -istanbul-reports@^3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz" - integrity sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw== - dependencies: - html-escaper "^2.0.0" - istanbul-lib-report "^3.0.0" - -isurl@^1.0.0-alpha5: - version "1.0.0" - resolved "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz" - integrity sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w== - dependencies: - has-to-string-tag-x "^1.2.0" - is-object "^1.0.1" - -jest-changed-files@^26.6.2: - version "26.6.2" - resolved "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-26.6.2.tgz" - integrity sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ== - dependencies: - "@jest/types" "^26.6.2" - execa "^4.0.0" - throat "^5.0.0" - -jest-cli@^26.6.3: - version "26.6.3" - resolved "https://registry.npmjs.org/jest-cli/-/jest-cli-26.6.3.tgz" - integrity sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg== - dependencies: - "@jest/core" "^26.6.3" - "@jest/test-result" "^26.6.2" - "@jest/types" "^26.6.2" - chalk "^4.0.0" - exit "^0.1.2" - graceful-fs "^4.2.4" - import-local "^3.0.2" - is-ci "^2.0.0" - jest-config "^26.6.3" - jest-util "^26.6.2" - jest-validate "^26.6.2" - prompts "^2.0.1" - yargs "^15.4.1" - -jest-config@^26.6.3: - version "26.6.3" - resolved "https://registry.npmjs.org/jest-config/-/jest-config-26.6.3.tgz" - integrity sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg== - dependencies: - "@babel/core" "^7.1.0" - "@jest/test-sequencer" "^26.6.3" - "@jest/types" "^26.6.2" - babel-jest "^26.6.3" - chalk "^4.0.0" - deepmerge "^4.2.2" - glob "^7.1.1" - graceful-fs "^4.2.4" - jest-environment-jsdom "^26.6.2" - jest-environment-node "^26.6.2" - jest-get-type "^26.3.0" - jest-jasmine2 "^26.6.3" - jest-regex-util "^26.0.0" - jest-resolve "^26.6.2" - jest-util "^26.6.2" - jest-validate "^26.6.2" - micromatch "^4.0.2" - pretty-format "^26.6.2" - -jest-diff@^25.2.1: - version "25.5.0" - resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-25.5.0.tgz" - integrity sha512-z1kygetuPiREYdNIumRpAHY6RXiGmp70YHptjdaxTWGmA085W3iCnXNx0DhflK3vwrKmrRWyY1wUpkPMVxMK7A== - dependencies: - chalk "^3.0.0" - diff-sequences "^25.2.6" - jest-get-type "^25.2.6" - pretty-format "^25.5.0" - -jest-diff@^26.6.2: - version "26.6.2" - resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz" - integrity sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA== - dependencies: - chalk "^4.0.0" - diff-sequences "^26.6.2" - jest-get-type "^26.3.0" - pretty-format "^26.6.2" - -jest-docblock@^26.0.0: - version "26.0.0" - resolved "https://registry.npmjs.org/jest-docblock/-/jest-docblock-26.0.0.tgz" - integrity sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w== - dependencies: - detect-newline "^3.0.0" - -jest-each@^26.6.2: - version "26.6.2" - resolved "https://registry.npmjs.org/jest-each/-/jest-each-26.6.2.tgz" - integrity sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A== - dependencies: - "@jest/types" "^26.6.2" - chalk "^4.0.0" - jest-get-type "^26.3.0" - jest-util "^26.6.2" - pretty-format "^26.6.2" - -jest-environment-jsdom@^26.6.2: - version "26.6.2" - resolved "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz" - integrity sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q== - dependencies: - "@jest/environment" "^26.6.2" - "@jest/fake-timers" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/node" "*" - jest-mock "^26.6.2" - jest-util "^26.6.2" - jsdom "^16.4.0" - -jest-environment-node@^26.6.2: - version "26.6.2" - resolved "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-26.6.2.tgz" - integrity sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag== - dependencies: - "@jest/environment" "^26.6.2" - "@jest/fake-timers" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/node" "*" - jest-mock "^26.6.2" - jest-util "^26.6.2" - -jest-get-type@^25.2.6: - version "25.2.6" - resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-25.2.6.tgz" - integrity sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig== - -jest-get-type@^26.3.0: - version "26.3.0" - resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz" - integrity sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig== - -jest-haste-map@^26.6.2: - version "26.6.2" - resolved "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-26.6.2.tgz" - integrity sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w== - dependencies: - "@jest/types" "^26.6.2" - "@types/graceful-fs" "^4.1.2" - "@types/node" "*" - anymatch "^3.0.3" - fb-watchman "^2.0.0" - graceful-fs "^4.2.4" - jest-regex-util "^26.0.0" - jest-serializer "^26.6.2" - jest-util "^26.6.2" - jest-worker "^26.6.2" - micromatch "^4.0.2" - sane "^4.0.3" - walker "^1.0.7" - optionalDependencies: - fsevents "^2.1.2" - -jest-haste-map@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.6.2.tgz#298c25ea5255cfad8b723179d4295cf3a50a70d1" - integrity sha512-+51XleTDAAysvU8rT6AnS1ZJ+WHVNqhj1k6nTvN2PYP+HjU3kqlaKQ1Lnw3NYW3bm2r8vq82X0Z1nDDHZMzHVA== - dependencies: - "@jest/types" "^29.6.1" - "@types/graceful-fs" "^4.1.3" - "@types/node" "*" - anymatch "^3.0.3" - fb-watchman "^2.0.0" - graceful-fs "^4.2.9" - jest-regex-util "^29.4.3" - jest-util "^29.6.2" - jest-worker "^29.6.2" - micromatch "^4.0.4" - walker "^1.0.8" - optionalDependencies: - fsevents "^2.3.2" - -jest-jasmine2@^26.6.3: - version "26.6.3" - resolved "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz" - integrity sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg== - dependencies: - "@babel/traverse" "^7.1.0" - "@jest/environment" "^26.6.2" - "@jest/source-map" "^26.6.2" - "@jest/test-result" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/node" "*" - chalk "^4.0.0" - co "^4.6.0" - expect "^26.6.2" - is-generator-fn "^2.0.0" - jest-each "^26.6.2" - jest-matcher-utils "^26.6.2" - jest-message-util "^26.6.2" - jest-runtime "^26.6.3" - jest-snapshot "^26.6.2" - jest-util "^26.6.2" - pretty-format "^26.6.2" - throat "^5.0.0" - -jest-leak-detector@^26.6.2: - version "26.6.2" - resolved "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz" - integrity sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg== - dependencies: - jest-get-type "^26.3.0" - pretty-format "^26.6.2" - -jest-matcher-utils@^26.6.2: - version "26.6.2" - resolved "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz" - integrity sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw== - dependencies: - chalk "^4.0.0" - jest-diff "^26.6.2" - jest-get-type "^26.3.0" - pretty-format "^26.6.2" - -jest-message-util@^26.6.2: - version "26.6.2" - resolved "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz" - integrity sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA== - dependencies: - "@babel/code-frame" "^7.0.0" - "@jest/types" "^26.6.2" - "@types/stack-utils" "^2.0.0" - chalk "^4.0.0" - graceful-fs "^4.2.4" - micromatch "^4.0.2" - pretty-format "^26.6.2" - slash "^3.0.0" - stack-utils "^2.0.2" - -jest-mock@^26.6.2: - version "26.6.2" - resolved "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz" - integrity sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew== - dependencies: - "@jest/types" "^26.6.2" - "@types/node" "*" - -jest-pnp-resolver@^1.2.2: - version "1.2.2" - resolved "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz" - integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w== - -jest-regex-util@^26.0.0: - version "26.0.0" - resolved "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz" - integrity sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A== - -jest-regex-util@^29.4.3: - version "29.4.3" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.4.3.tgz#a42616141e0cae052cfa32c169945d00c0aa0bb8" - integrity sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg== - -jest-resolve-dependencies@^26.6.3: - version "26.6.3" - resolved "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz" - integrity sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg== - dependencies: - "@jest/types" "^26.6.2" - jest-regex-util "^26.0.0" - jest-snapshot "^26.6.2" - -jest-resolve@^26.6.2: - version "26.6.2" - resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz" - integrity sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ== - dependencies: - "@jest/types" "^26.6.2" - chalk "^4.0.0" - graceful-fs "^4.2.4" - jest-pnp-resolver "^1.2.2" - jest-util "^26.6.2" - read-pkg-up "^7.0.1" - resolve "^1.18.1" - slash "^3.0.0" - -jest-runner@^26.6.3: - version "26.6.3" - resolved "https://registry.npmjs.org/jest-runner/-/jest-runner-26.6.3.tgz" - integrity sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ== - dependencies: - "@jest/console" "^26.6.2" - "@jest/environment" "^26.6.2" - "@jest/test-result" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/node" "*" - chalk "^4.0.0" - emittery "^0.7.1" - exit "^0.1.2" - graceful-fs "^4.2.4" - jest-config "^26.6.3" - jest-docblock "^26.0.0" - jest-haste-map "^26.6.2" - jest-leak-detector "^26.6.2" - jest-message-util "^26.6.2" - jest-resolve "^26.6.2" - jest-runtime "^26.6.3" - jest-util "^26.6.2" - jest-worker "^26.6.2" - source-map-support "^0.5.6" - throat "^5.0.0" - -jest-runtime@^26.6.3: - version "26.6.3" - resolved "https://registry.npmjs.org/jest-runtime/-/jest-runtime-26.6.3.tgz" - integrity sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw== - dependencies: - "@jest/console" "^26.6.2" - "@jest/environment" "^26.6.2" - "@jest/fake-timers" "^26.6.2" - "@jest/globals" "^26.6.2" - "@jest/source-map" "^26.6.2" - "@jest/test-result" "^26.6.2" - "@jest/transform" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/yargs" "^15.0.0" - chalk "^4.0.0" - cjs-module-lexer "^0.6.0" - collect-v8-coverage "^1.0.0" - exit "^0.1.2" - glob "^7.1.3" - graceful-fs "^4.2.4" - jest-config "^26.6.3" - jest-haste-map "^26.6.2" - jest-message-util "^26.6.2" - jest-mock "^26.6.2" - jest-regex-util "^26.0.0" - jest-resolve "^26.6.2" - jest-snapshot "^26.6.2" - jest-util "^26.6.2" - jest-validate "^26.6.2" - slash "^3.0.0" - strip-bom "^4.0.0" - yargs "^15.4.1" - -jest-serializer@^26.6.2: - version "26.6.2" - resolved "https://registry.npmjs.org/jest-serializer/-/jest-serializer-26.6.2.tgz" - integrity sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g== - dependencies: - "@types/node" "*" - graceful-fs "^4.2.4" - -jest-snapshot@^26.6.2: - version "26.6.2" - resolved "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.6.2.tgz" - integrity sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og== - dependencies: - "@babel/types" "^7.0.0" - "@jest/types" "^26.6.2" - "@types/babel__traverse" "^7.0.4" - "@types/prettier" "^2.0.0" - chalk "^4.0.0" - expect "^26.6.2" - graceful-fs "^4.2.4" - jest-diff "^26.6.2" - jest-get-type "^26.3.0" - jest-haste-map "^26.6.2" - jest-matcher-utils "^26.6.2" - jest-message-util "^26.6.2" - jest-resolve "^26.6.2" - natural-compare "^1.4.0" - pretty-format "^26.6.2" - semver "^7.3.2" - -jest-transform-stub@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/jest-transform-stub/-/jest-transform-stub-2.0.0.tgz" - integrity sha512-lspHaCRx/mBbnm3h4uMMS3R5aZzMwyNpNIJLXj4cEsV0mIUtS4IjYJLSoyjRCtnxb6RIGJ4NL2quZzfIeNhbkg== - -jest-util@^26.6.2: - version "26.6.2" - resolved "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz" - integrity sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q== - dependencies: - "@jest/types" "^26.6.2" - "@types/node" "*" - chalk "^4.0.0" - graceful-fs "^4.2.4" - is-ci "^2.0.0" - micromatch "^4.0.2" - -jest-util@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.6.2.tgz#8a052df8fff2eebe446769fd88814521a517664d" - integrity sha512-3eX1qb6L88lJNCFlEADKOkjpXJQyZRiavX1INZ4tRnrBVr2COd3RgcTLyUiEXMNBlDU/cgYq6taUS0fExrWW4w== - dependencies: - "@jest/types" "^29.6.1" - "@types/node" "*" - chalk "^4.0.0" - ci-info "^3.2.0" - graceful-fs "^4.2.9" - picomatch "^2.2.3" - -jest-validate@^26.6.2: - version "26.6.2" - resolved "https://registry.npmjs.org/jest-validate/-/jest-validate-26.6.2.tgz" - integrity sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ== - dependencies: - "@jest/types" "^26.6.2" - camelcase "^6.0.0" - chalk "^4.0.0" - jest-get-type "^26.3.0" - leven "^3.1.0" - pretty-format "^26.6.2" - -jest-watcher@^26.6.2: - version "26.6.2" - resolved "https://registry.npmjs.org/jest-watcher/-/jest-watcher-26.6.2.tgz" - integrity sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ== - dependencies: - "@jest/test-result" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/node" "*" - ansi-escapes "^4.2.1" - chalk "^4.0.0" - jest-util "^26.6.2" - string-length "^4.0.1" - -jest-worker@^26.6.2: - version "26.6.2" - resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz" - integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ== - dependencies: - "@types/node" "*" - merge-stream "^2.0.0" - supports-color "^7.0.0" - -jest-worker@^27.4.5: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" - integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== - dependencies: - "@types/node" "*" - merge-stream "^2.0.0" - supports-color "^8.0.0" - -jest-worker@^29.4.3, jest-worker@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.6.2.tgz#682fbc4b6856ad0aa122a5403c6d048b83f3fb44" - integrity sha512-l3ccBOabTdkng8I/ORCkADz4eSMKejTYv1vB/Z83UiubqhC1oQ5Li6dWCyqOIvSifGjUBxuvxvlm6KGK2DtuAQ== - dependencies: - "@types/node" "*" - jest-util "^29.6.2" - merge-stream "^2.0.0" - supports-color "^8.0.0" - -jest@^26.6.3: - version "26.6.3" - resolved "https://registry.npmjs.org/jest/-/jest-26.6.3.tgz" - integrity sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q== - dependencies: - "@jest/core" "^26.6.3" - import-local "^3.0.2" - jest-cli "^26.6.3" - -jiti@^1.18.2: - version "1.19.1" - resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.19.1.tgz#fa99e4b76a23053e0e7cde098efe1704a14c16f1" - integrity sha512-oVhqoRDaBXf7sjkll95LHVS6Myyyb1zaunVwk4Z0+WPSW4gjS0pl01zYKHScTuyEhQsFxV5L4DR5r+YqSyqyyg== - -jquery@^3.5.1: - version "3.5.1" - resolved "https://registry.npmjs.org/jquery/-/jquery-3.5.1.tgz" - integrity sha512-XwIBPqcMn57FxfT+Go5pzySnm4KWkT1Tv7gjrpT1srtf8Weynl6R273VJ5GjkRb51IzMp5nbaPjJXMWeju2MKg== - -"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -js-yaml@^3.13.1: - version "3.14.0" - resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz" - integrity sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -js-yaml@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" - integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== - dependencies: - argparse "^2.0.1" - -jsdom@^16.4.0: - version "16.7.0" - resolved "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz" - integrity sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw== - dependencies: - abab "^2.0.5" - acorn "^8.2.4" - acorn-globals "^6.0.0" - cssom "^0.4.4" - cssstyle "^2.3.0" - data-urls "^2.0.0" - decimal.js "^10.2.1" - domexception "^2.0.1" - escodegen "^2.0.0" - form-data "^3.0.0" - html-encoding-sniffer "^2.0.1" - http-proxy-agent "^4.0.1" - https-proxy-agent "^5.0.0" - is-potential-custom-element-name "^1.0.1" - nwsapi "^2.2.0" - parse5 "6.0.1" - saxes "^5.0.1" - symbol-tree "^3.2.4" - tough-cookie "^4.0.0" - w3c-hr-time "^1.0.2" - w3c-xmlserializer "^2.0.0" - webidl-conversions "^6.1.0" - whatwg-encoding "^1.0.5" - whatwg-mimetype "^2.3.0" - whatwg-url "^8.5.0" - ws "^7.4.6" - xml-name-validator "^3.0.0" - -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - -jsesc@~0.5.0: - version "0.5.0" - resolved "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz" - integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= - -json-buffer@3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz" - integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= - -json-parse-better-errors@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz" - integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== - -json-parse-even-better-errors@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" - integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-schema-traverse@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" - integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== - -json-stable-stringify-without-jsonify@^1.0.1: - 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= - -json-stringify-safe@~5.0.0: - version "5.0.1" - resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz" - integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= - -json5@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz" - integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== - dependencies: - minimist "^1.2.0" - -json5@^2.1.2: - version "2.1.3" - resolved "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz" - integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== - dependencies: - minimist "^1.2.5" - -json5@^2.2.2: - version "2.2.3" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" - integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== - -"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.1.0.tgz" - integrity sha512-d4/UOjg+mxAWxCiF0c5UTSwyqbchkbqCvK87aBovhnh8GtysTjWmgC63tY0cJx/HzGgm9qnA147jVBdpOiQ2RA== - dependencies: - array-includes "^3.1.1" - object.assign "^4.1.1" - -junk@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/junk/-/junk-3.1.0.tgz" - integrity sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ== - -katex@^0.16.0, katex@^0.16.21: - version "0.16.21" - resolved "https://registry.yarnpkg.com/katex/-/katex-0.16.21.tgz#8f63c659e931b210139691f2cc7bb35166b792a3" - integrity sha512-XvqR7FgOHtWupfMiigNzmh+MgUVmDGU2kXZm899ZkPfcuoPuFxyHmXsgATDpFZDAXCI8tvinaVcDo8PIIJSo4A== - dependencies: - commander "^8.3.0" - -keyv@3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/keyv/-/keyv-3.0.0.tgz" - integrity sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA== - dependencies: - json-buffer "3.0.0" - -kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: - version "3.2.2" - resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz" - integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= - dependencies: - is-buffer "^1.1.5" - -kind-of@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz" - integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= - dependencies: - is-buffer "^1.1.5" - -kind-of@^5.0.0: - version "5.1.0" - resolved "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz" - integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== - -kind-of@^6.0.0, kind-of@^6.0.2: - version "6.0.3" - resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz" - integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== - -kleur@^3.0.3: - version "3.0.3" - resolved "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz" - integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== - -language-subtag-registry@~0.3.2: - version "0.3.20" - resolved "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.20.tgz" - integrity sha512-KPMwROklF4tEx283Xw0pNKtfTj1gZ4UByp4EsIFWLgBavJltF4TiYPc39k06zSTsLzxTVXXDSpbwaQXaFB4Qeg== - -language-tags@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz" - integrity sha1-0yHbxNowuovzAk4ED6XBRmH5GTo= - dependencies: - language-subtag-registry "~0.3.2" - -launch-editor@^2.6.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/launch-editor/-/launch-editor-2.6.0.tgz#4c0c1a6ac126c572bd9ff9a30da1d2cae66defd7" - integrity sha512-JpDCcQnyAAzZZaZ7vEiSqL690w7dAEyLao+KC96zBplnYbJS7TYNjvM3M7y3dGz+v7aIsJk3hllWuc0kWAjyRQ== - dependencies: - picocolors "^1.0.0" - shell-quote "^1.7.3" - -leven@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz" - integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== - -levn@^0.4.1: - version "0.4.1" - resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz" - integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== - dependencies: - prelude-ls "^1.2.1" - type-check "~0.4.0" - -levn@~0.3.0: - version "0.3.0" - resolved "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz" - integrity sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA== - dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" - -lilconfig@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" - integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== - -lines-and-columns@^1.1.6: - version "1.1.6" - resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz" - integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= - -load-json-file@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz" - integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg= - dependencies: - graceful-fs "^4.1.2" - parse-json "^2.2.0" - pify "^2.0.0" - strip-bom "^3.0.0" - -loader-runner@^4.2.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1" - integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg== - -loader-utils@^2.0.0, loader-utils@^2.0.2, loader-utils@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.4.tgz#8b5cb38b5c34a9a018ee1fc0e6a066d1dfcc528c" - integrity sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw== - dependencies: - big.js "^5.2.2" - emojis-list "^3.0.0" - json5 "^2.1.2" - -locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz" - integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= - dependencies: - p-locate "^2.0.0" - path-exists "^3.0.0" - -locate-path@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz" - integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== - dependencies: - p-locate "^4.1.0" - -locate-path@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" - integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== - dependencies: - p-locate "^5.0.0" - -locate-path@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-7.2.0.tgz#69cb1779bd90b35ab1e771e1f2f89a202c2a8a8a" - integrity sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA== - dependencies: - p-locate "^6.0.0" - -lodash-es@^4.17.11, lodash-es@^4.17.14: - version "4.17.21" - resolved "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz" - integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== - -lodash.clonedeep@^4.5.0: - version "4.5.0" - resolved "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz" - integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= - -lodash.debounce@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" - integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== - -lodash.isequal@^4.5.0: - version "4.5.0" - resolved "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz" - integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA= - -lodash.memoize@^4.1.2: - version "4.1.2" - resolved "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz" - integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= - -lodash.uniq@^4.5.0: - version "4.5.0" - resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz" - integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= - -lodash@^4.1.1, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0: - version "4.17.21" - resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -longest-streak@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-3.1.0.tgz#62fa67cd958742a1574af9f39866364102d90cd4" - integrity sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g== - -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - -lowercase-keys@1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz" - integrity sha1-TjNms55/VFfjXxMkvfb4jQv8cwY= - -lowercase-keys@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz" - integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== - -lru-cache@^4.0.1: - version "4.1.5" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz" - integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== - dependencies: - pseudomap "^1.0.2" - yallist "^2.1.2" - -lru-cache@^5.1.1: - version "5.1.1" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz" - integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== - dependencies: - yallist "^3.0.2" - -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - -lru-cache@~2.2.1: - version "2.2.4" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-2.2.4.tgz" - integrity sha1-bGWGGb7PFAMdDQtZSxYELOTcBj0= - -lz-string@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.5.0.tgz#c1ab50f77887b712621201ba9fd4e3a6ed099941" - integrity sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ== - -make-dir@^1.0.0, make-dir@^1.2.0: - version "1.3.0" - resolved "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz" - integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== - dependencies: - pify "^3.0.0" - -make-dir@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz" - integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== - dependencies: - pify "^4.0.1" - semver "^5.6.0" - -make-dir@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz" - integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== - dependencies: - semver "^6.0.0" - -makeerror@1.0.12: - version "1.0.12" - resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" - integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== - dependencies: - tmpl "1.0.5" - -makeerror@1.0.x: - version "1.0.11" - resolved "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz" - integrity sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw= - dependencies: - tmpl "1.0.x" - -map-cache@^0.2.2: - version "0.2.2" - resolved "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz" - integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= - -map-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz" - integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= - dependencies: - object-visit "^1.0.0" - -match-sorter@^2.3.0: - version "2.3.0" - resolved "https://registry.npmjs.org/match-sorter/-/match-sorter-2.3.0.tgz" - integrity sha512-0/F1ezfjs5vegTvdH0sJEDrIi+w7wvUeDW/yqLMsK6jQWgNNJRv8jYCLBc8QrCxQNpSEpei6vrOcnJwAbnYhkw== - dependencies: - diacritic "0.0.2" - -mdast-util-from-markdown@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.1.tgz#32a6e8f512b416e1f51eb817fc64bd867ebcd9cc" - integrity sha512-aJEUyzZ6TzlsX2s5B4Of7lN7EQtAxvtradMMglCQDyaTFgse6CmtmdJ15ElnVRlCg1vpNyVtbem0PWzlNieZsA== - dependencies: - "@types/mdast" "^4.0.0" - "@types/unist" "^3.0.0" - decode-named-character-reference "^1.0.0" - devlop "^1.0.0" - mdast-util-to-string "^4.0.0" - micromark "^4.0.0" - micromark-util-decode-numeric-character-reference "^2.0.0" - micromark-util-decode-string "^2.0.0" - micromark-util-normalize-identifier "^2.0.0" - micromark-util-symbol "^2.0.0" - micromark-util-types "^2.0.0" - unist-util-stringify-position "^4.0.0" - -mdast-util-math@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/mdast-util-math/-/mdast-util-math-3.0.0.tgz#8d79dd3baf8ab8ac781f62b8853768190b9a00b0" - integrity sha512-Tl9GBNeG/AhJnQM221bJR2HPvLOSnLE/T9cJI9tlc6zwQk2nPk/4f0cHkOdEixQPC/j8UtKDdITswvLAy1OZ1w== - dependencies: - "@types/hast" "^3.0.0" - "@types/mdast" "^4.0.0" - devlop "^1.0.0" - longest-streak "^3.0.0" - mdast-util-from-markdown "^2.0.0" - mdast-util-to-markdown "^2.1.0" - unist-util-remove-position "^5.0.0" - -mdast-util-mdx-expression@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.0.tgz#4968b73724d320a379110d853e943a501bfd9d87" - integrity sha512-fGCu8eWdKUKNu5mohVGkhBXCXGnOTLuFqOvGMvdikr+J1w7lDJgxThOKpwRWzzbyXAU2hhSwsmssOY4yTokluw== - dependencies: - "@types/estree-jsx" "^1.0.0" - "@types/hast" "^3.0.0" - "@types/mdast" "^4.0.0" - devlop "^1.0.0" - mdast-util-from-markdown "^2.0.0" - mdast-util-to-markdown "^2.0.0" - -mdast-util-mdx-jsx@^3.0.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.1.2.tgz#daae777c72f9c4a106592e3025aa50fb26068e1b" - integrity sha512-eKMQDeywY2wlHc97k5eD8VC+9ASMjN8ItEZQNGwJ6E0XWKiW/Z0V5/H8pvoXUf+y+Mj0VIgeRRbujBmFn4FTyA== - dependencies: - "@types/estree-jsx" "^1.0.0" - "@types/hast" "^3.0.0" - "@types/mdast" "^4.0.0" - "@types/unist" "^3.0.0" - ccount "^2.0.0" - devlop "^1.1.0" - mdast-util-from-markdown "^2.0.0" - mdast-util-to-markdown "^2.0.0" - parse-entities "^4.0.0" - stringify-entities "^4.0.0" - unist-util-remove-position "^5.0.0" - unist-util-stringify-position "^4.0.0" - vfile-message "^4.0.0" - -mdast-util-mdxjs-esm@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz#019cfbe757ad62dd557db35a695e7314bcc9fa97" - integrity sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg== - dependencies: - "@types/estree-jsx" "^1.0.0" - "@types/hast" "^3.0.0" - "@types/mdast" "^4.0.0" - devlop "^1.0.0" - mdast-util-from-markdown "^2.0.0" - mdast-util-to-markdown "^2.0.0" - -mdast-util-phrasing@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz#7cc0a8dec30eaf04b7b1a9661a92adb3382aa6e3" - integrity sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w== - dependencies: - "@types/mdast" "^4.0.0" - unist-util-is "^6.0.0" - -mdast-util-to-hast@^13.0.0: - version "13.1.0" - resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-13.1.0.tgz#1ae54d903150a10fe04d59f03b2b95fd210b2124" - integrity sha512-/e2l/6+OdGp/FB+ctrJ9Avz71AN/GRH3oi/3KAx/kMnoUsD6q0woXlDT8lLEeViVKE7oZxE7RXzvO3T8kF2/sA== - dependencies: - "@types/hast" "^3.0.0" - "@types/mdast" "^4.0.0" - "@ungap/structured-clone" "^1.0.0" - devlop "^1.0.0" - micromark-util-sanitize-uri "^2.0.0" - trim-lines "^3.0.0" - unist-util-position "^5.0.0" - unist-util-visit "^5.0.0" - vfile "^6.0.0" - -mdast-util-to-markdown@^2.0.0, mdast-util-to-markdown@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.0.tgz#9813f1d6e0cdaac7c244ec8c6dabfdb2102ea2b4" - integrity sha512-SR2VnIEdVNCJbP6y7kVTJgPLifdr8WEU440fQec7qHoHOUz/oJ2jmNRqdDQ3rbiStOXb2mCDGTuwsK5OPUgYlQ== - dependencies: - "@types/mdast" "^4.0.0" - "@types/unist" "^3.0.0" - longest-streak "^3.0.0" - mdast-util-phrasing "^4.0.0" - mdast-util-to-string "^4.0.0" - micromark-util-decode-string "^2.0.0" - unist-util-visit "^5.0.0" - zwitch "^2.0.0" - -mdast-util-to-string@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz#7a5121475556a04e7eddeb67b264aae79d312814" - integrity sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg== - dependencies: - "@types/mdast" "^4.0.0" - -mdn-data@2.0.14: - version "2.0.14" - resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" - integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow== - -mdn-data@2.0.28: - version "2.0.28" - resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.28.tgz#5ec48e7bef120654539069e1ae4ddc81ca490eba" - integrity sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g== - -mdn-data@2.0.30: - version "2.0.30" - resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.30.tgz#ce4df6f80af6cfbe218ecd5c552ba13c4dfa08cc" - integrity sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA== - -media-typer@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== - -memfs@^3.4.3: - version "3.4.13" - resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.4.13.tgz#248a8bd239b3c240175cd5ec548de5227fc4f345" - integrity sha512-omTM41g3Skpvx5dSYeZIbXKcXoAVc/AoMNwn9TKx++L/gaen/+4TTttmu8ZSch5vfVJ8uJvGbroTsIlslRg6lg== - dependencies: - fs-monkey "^1.0.3" - -memoize-one@^4.0.2: - version "4.1.0" - resolved "https://registry.npmjs.org/memoize-one/-/memoize-one-4.1.0.tgz" - integrity sha512-2GApq0yI/b22J2j9rhbrAlsHb0Qcz+7yWxeLG8h+95sl1XPUgeLimQSOdur4Vw7cUhrBHwaUZxWFZueojqNRzA== - -memoize-one@^5.0.0: - version "5.1.1" - resolved "https://registry.npmjs.org/memoize-one/-/memoize-one-5.1.1.tgz" - integrity sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA== - -memoize-one@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045" - integrity sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw== - -merge-descriptors@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5" - integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ== - -merge-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz" - integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== - -merge2@^1.2.3, merge2@^1.3.0, merge2@^1.4.1: - version "1.4.1" - resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz" - integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== - -methods@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" - integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== - -micro-memoize@^4.1.2: - version "4.1.3" - resolved "https://registry.yarnpkg.com/micro-memoize/-/micro-memoize-4.1.3.tgz#17d5df0702acf575503cbf09df90fe691c12825f" - integrity sha512-DzRMi8smUZXT7rCGikRwldEh6eO6qzKiPPopcr1+2EY3AYKpy5fu159PKWwIS9A6IWnrvPKDMcuFtyrroZa8Bw== - -micromark-core-commonmark@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/micromark-core-commonmark/-/micromark-core-commonmark-2.0.1.tgz#9a45510557d068605c6e9a80f282b2bb8581e43d" - integrity sha512-CUQyKr1e///ZODyD1U3xit6zXwy1a8q2a1S1HKtIlmgvurrEpaw/Y9y6KSIbF8P59cn/NjzHyO+Q2fAyYLQrAA== - dependencies: - decode-named-character-reference "^1.0.0" - devlop "^1.0.0" - micromark-factory-destination "^2.0.0" - micromark-factory-label "^2.0.0" - micromark-factory-space "^2.0.0" - micromark-factory-title "^2.0.0" - micromark-factory-whitespace "^2.0.0" - micromark-util-character "^2.0.0" - micromark-util-chunked "^2.0.0" - micromark-util-classify-character "^2.0.0" - micromark-util-html-tag-name "^2.0.0" - micromark-util-normalize-identifier "^2.0.0" - micromark-util-resolve-all "^2.0.0" - micromark-util-subtokenize "^2.0.0" - micromark-util-symbol "^2.0.0" - micromark-util-types "^2.0.0" - -micromark-extension-math@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/micromark-extension-math/-/micromark-extension-math-3.0.0.tgz#c7a47d6ce990812243ad3946a30bb60e4c2a8c76" - integrity sha512-iJ2Q28vBoEovLN5o3GO12CpqorQRYDPT+p4zW50tGwTfJB+iv/VnB6Ini+gqa24K97DwptMBBIvVX6Bjk49oyQ== - dependencies: - "@types/katex" "^0.16.0" - devlop "^1.0.0" - katex "^0.16.0" - micromark-factory-space "^2.0.0" - micromark-util-character "^2.0.0" - micromark-util-symbol "^2.0.0" - micromark-util-types "^2.0.0" - -micromark-factory-destination@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz#857c94debd2c873cba34e0445ab26b74f6a6ec07" - integrity sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA== - dependencies: - micromark-util-character "^2.0.0" - micromark-util-symbol "^2.0.0" - micromark-util-types "^2.0.0" - -micromark-factory-label@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz#17c5c2e66ce39ad6f4fc4cbf40d972f9096f726a" - integrity sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw== - dependencies: - devlop "^1.0.0" - micromark-util-character "^2.0.0" - micromark-util-symbol "^2.0.0" - micromark-util-types "^2.0.0" - -micromark-factory-space@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz#5e7afd5929c23b96566d0e1ae018ae4fcf81d030" - integrity sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg== - dependencies: - micromark-util-character "^2.0.0" - micromark-util-types "^2.0.0" - -micromark-factory-title@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz#726140fc77892af524705d689e1cf06c8a83ea95" - integrity sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A== - dependencies: - micromark-factory-space "^2.0.0" - micromark-util-character "^2.0.0" - micromark-util-symbol "^2.0.0" - micromark-util-types "^2.0.0" - -micromark-factory-whitespace@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz#9e92eb0f5468083381f923d9653632b3cfb5f763" - integrity sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA== - dependencies: - micromark-factory-space "^2.0.0" - micromark-util-character "^2.0.0" - micromark-util-symbol "^2.0.0" - micromark-util-types "^2.0.0" - -micromark-util-character@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/micromark-util-character/-/micromark-util-character-2.1.0.tgz#31320ace16b4644316f6bf057531689c71e2aee1" - integrity sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ== - dependencies: - micromark-util-symbol "^2.0.0" - micromark-util-types "^2.0.0" - -micromark-util-chunked@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz#e51f4db85fb203a79dbfef23fd41b2f03dc2ef89" - integrity sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg== - dependencies: - micromark-util-symbol "^2.0.0" - -micromark-util-classify-character@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz#8c7537c20d0750b12df31f86e976d1d951165f34" - integrity sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw== - dependencies: - micromark-util-character "^2.0.0" - micromark-util-symbol "^2.0.0" - micromark-util-types "^2.0.0" - -micromark-util-combine-extensions@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz#75d6ab65c58b7403616db8d6b31315013bfb7ee5" - integrity sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ== - dependencies: - micromark-util-chunked "^2.0.0" - micromark-util-types "^2.0.0" - -micromark-util-decode-numeric-character-reference@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz#2698bbb38f2a9ba6310e359f99fcb2b35a0d2bd5" - integrity sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ== - dependencies: - micromark-util-symbol "^2.0.0" - -micromark-util-decode-string@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz#7dfa3a63c45aecaa17824e656bcdb01f9737154a" - integrity sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA== - dependencies: - decode-named-character-reference "^1.0.0" - micromark-util-character "^2.0.0" - micromark-util-decode-numeric-character-reference "^2.0.0" - micromark-util-symbol "^2.0.0" - -micromark-util-encode@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz#0921ac7953dc3f1fd281e3d1932decfdb9382ab1" - integrity sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA== - -micromark-util-html-tag-name@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz#ae34b01cbe063363847670284c6255bb12138ec4" - integrity sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw== - -micromark-util-normalize-identifier@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz#91f9a4e65fe66cc80c53b35b0254ad67aa431d8b" - integrity sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w== - dependencies: - micromark-util-symbol "^2.0.0" - -micromark-util-resolve-all@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz#189656e7e1a53d0c86a38a652b284a252389f364" - integrity sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA== - dependencies: - micromark-util-types "^2.0.0" - -micromark-util-sanitize-uri@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz#ec8fbf0258e9e6d8f13d9e4770f9be64342673de" - integrity sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw== - dependencies: - micromark-util-character "^2.0.0" - micromark-util-encode "^2.0.0" - micromark-util-symbol "^2.0.0" - -micromark-util-subtokenize@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.1.tgz#76129c49ac65da6e479c09d0ec4b5f29ec6eace5" - integrity sha512-jZNtiFl/1aY73yS3UGQkutD0UbhTt68qnRpw2Pifmz5wV9h8gOVsN70v+Lq/f1rKaU/W8pxRe8y8Q9FX1AOe1Q== - dependencies: - devlop "^1.0.0" - micromark-util-chunked "^2.0.0" - micromark-util-symbol "^2.0.0" - micromark-util-types "^2.0.0" - -micromark-util-symbol@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz#12225c8f95edf8b17254e47080ce0862d5db8044" - integrity sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw== - -micromark-util-types@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-types/-/micromark-util-types-2.0.0.tgz#63b4b7ffeb35d3ecf50d1ca20e68fc7caa36d95e" - integrity sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w== - -micromark@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/micromark/-/micromark-4.0.0.tgz#84746a249ebd904d9658cfabc1e8e5f32cbc6249" - integrity sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ== - dependencies: - "@types/debug" "^4.0.0" - debug "^4.0.0" - decode-named-character-reference "^1.0.0" - devlop "^1.0.0" - micromark-core-commonmark "^2.0.0" - micromark-factory-space "^2.0.0" - micromark-util-character "^2.0.0" - micromark-util-chunked "^2.0.0" - micromark-util-combine-extensions "^2.0.0" - micromark-util-decode-numeric-character-reference "^2.0.0" - micromark-util-encode "^2.0.0" - micromark-util-normalize-identifier "^2.0.0" - micromark-util-resolve-all "^2.0.0" - micromark-util-sanitize-uri "^2.0.0" - micromark-util-subtokenize "^2.0.0" - micromark-util-symbol "^2.0.0" - micromark-util-types "^2.0.0" - -micromatch@^3.1.4: - version "3.1.10" - resolved "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz" - integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - braces "^2.3.1" - define-property "^2.0.2" - extend-shallow "^3.0.2" - extglob "^2.0.4" - fragment-cache "^0.2.1" - kind-of "^6.0.2" - nanomatch "^1.2.9" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.2" - -micromatch@^4.0.2: - version "4.0.2" - resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz" - integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q== - dependencies: - braces "^3.0.1" - picomatch "^2.0.5" - -micromatch@^4.0.4: - version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== - dependencies: - braces "^3.0.2" - picomatch "^2.3.1" - -mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": - version "1.52.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" - integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== - -mime-db@^1.28.0: - version "1.44.0" - resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz" - integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg== - -mime-types@^2.1.12, mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.17, mime-types@~2.1.24, mime-types@~2.1.34: - version "2.1.35" - resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" - integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== - dependencies: - mime-db "1.52.0" - -mime@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" - integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== - -mimic-fn@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" - integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== - -mimic-response@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz" - integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== - -min-indent@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz" - integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== - -mini-css-extract-plugin@^2.7.3: - version "2.7.3" - resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.3.tgz#794aa4d598bf178a66b2a35fe287c3df3eac394e" - integrity sha512-CD9cXeKeXLcnMw8FZdtfrRrLaM7gwCl4nKuKn2YkY2Bw5wdlB8zU2cCzw+w2zS9RFvbrufTBkMCJACNPwqQA0w== - dependencies: - schema-utils "^4.0.0" - -minimalistic-assert@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" - integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== - -minimatch@^3.0.4, minimatch@^3.1.1: - version "3.1.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5: - version "1.2.6" - resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz" - integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== - -mixin-deep@^1.2.0: - version "1.3.2" - resolved "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz" - integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== - dependencies: - for-in "^1.0.2" - is-extendable "^1.0.1" - -"mkdirp@>=0.5 0", mkdirp@^0.5.1: - version "0.5.5" - resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz" - integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== - dependencies: - minimist "^1.2.5" - -moize@^6.1.6: - version "6.1.6" - resolved "https://registry.yarnpkg.com/moize/-/moize-6.1.6.tgz#ac2e723e74b951875fe2c0c3433405c2b098c3e6" - integrity sha512-vSKdIUO61iCmTqhdoIDrqyrtp87nWZUmBPniNjO0fX49wEYmyDO4lvlnFXiGcaH1JLE/s/9HbiK4LSHsbiUY6Q== - dependencies: - fast-equals "^3.0.1" - micro-memoize "^4.1.2" - -moment@>=1.6.0, moment@^2.29.4: - version "2.29.4" - resolved "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz" - integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w== - -monaco-editor-webpack-plugin@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/monaco-editor-webpack-plugin/-/monaco-editor-webpack-plugin-7.1.0.tgz#16f265c2b5dbb5fe08681b6b3b7d00d3c5b2ee97" - integrity sha512-ZjnGINHN963JQkFqjjcBtn1XBtUATDZBMgNQhDQwd78w2ukRhFXAPNgWuacaQiDZsUr4h1rWv5Mv6eriKuOSzA== - dependencies: - loader-utils "^2.0.2" - -monaco-editor@^0.52.2: - version "0.52.2" - resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.52.2.tgz#53c75a6fcc6802684e99fd1b2700299857002205" - integrity sha512-GEQWEZmfkOGLdd3XK8ryrfWz3AIP8YymVXiPHEdewrUq7mh0qrKrfHLNCXcbB6sTnMLnOZ3ztSiKcciFUkIJwQ== - -monaco-themes@^0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/monaco-themes/-/monaco-themes-0.4.4.tgz#28ab13e538c4867a9bc89dc67f15dfaf3fc69de1" - integrity sha512-Hbb9pvRrpSi0rZezcB/IOdQnpx10o55Lx4zFdRAAVpFMa1HP7FgaqEZdKffb4ovd90fETCixeFO9JPYFMAq+TQ== - dependencies: - fast-plist "^0.1.3" - -monaco-vim@^0.4.2: - version "0.4.2" - resolved "https://registry.yarnpkg.com/monaco-vim/-/monaco-vim-0.4.2.tgz#b56a6bbe2332c987391b3d04000134e0c645da19" - integrity sha512-rdbQC3O2rmpwX2Orzig/6gZjZfH7q7TIeB+uEl49sa+QyNm3jCKJOw5mwxBdFzTqbrPD+URfg6A2lEkuL5kymw== - -mozjpeg@^7.0.0: - version "7.1.1" - resolved "https://registry.yarnpkg.com/mozjpeg/-/mozjpeg-7.1.1.tgz#dfb61953536e66fcabd4ae795e7a312d42a51f18" - integrity sha512-iIDxWvzhWvLC9mcRJ1uSkiKaj4drF58oCqK2bITm5c2Jt6cJ8qQjSSru2PCaysG+hLIinryj8mgz5ZJzOYTv1A== - dependencies: - bin-build "^3.0.0" - bin-wrapper "^4.0.0" - -mrmime@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-1.0.1.tgz#5f90c825fad4bdd41dc914eff5d1a8cfdaf24f27" - integrity sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw== - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -ms@2.1.3: - version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - -multicast-dns@^7.2.5: - version "7.2.5" - resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-7.2.5.tgz#77eb46057f4d7adbd16d9290fa7299f6fa64cced" - integrity sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg== - dependencies: - dns-packet "^5.2.2" - thunky "^1.0.2" - -nanoid@^3.3.6: - version "3.3.8" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.8.tgz#b1be3030bee36aaff18bacb375e5cce521684baf" - integrity sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w== - -nanomatch@^1.2.9: - version "1.2.13" - resolved "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz" - integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - define-property "^2.0.2" - extend-shallow "^3.0.2" - fragment-cache "^0.2.1" - is-windows "^1.0.2" - kind-of "^6.0.2" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= - -negotiator@0.6.3: - version "0.6.3" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" - integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== - -neo-async@^2.6.2: - version "2.6.2" - resolved "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz" - integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== - -nice-try@^1.0.4: - version "1.0.5" - resolved "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz" - integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== - -node-forge@^1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" - integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== - -node-gettext@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/node-gettext/-/node-gettext-1.1.0.tgz" - integrity sha1-6WzZeyiShxNzgdZLbTPKThkfKfo= - dependencies: - gettext-parser "^1.1.2" - -node-int64@^0.4.0: - version "0.4.0" - resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz" - integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= - -node-modules-regexp@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz" - integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= - -node-notifier@^8.0.0: - version "8.0.0" - resolved "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.0.tgz" - integrity sha512-46z7DUmcjoYdaWyXouuFNNfUo6eFa94t23c53c+lG/9Cvauk4a98rAUp9672X5dxGdQmLpPzTxzu8f/OeEPaFA== - dependencies: - growly "^1.3.0" - is-wsl "^2.2.0" - semver "^7.3.2" - shellwords "^0.1.1" - uuid "^8.3.0" - which "^2.0.2" - -node-releases@^2.0.18: - version "2.0.18" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" - integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== - -normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: - version "2.5.0" - resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz" - integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== - dependencies: - hosted-git-info "^2.1.4" - resolve "^1.10.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" - -normalize-path@^2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz" - integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= - dependencies: - remove-trailing-separator "^1.0.1" - -normalize-path@^3.0.0, normalize-path@~3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - -normalize-url@2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz" - integrity sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw== - dependencies: - prepend-http "^2.0.0" - query-string "^5.0.1" - sort-keys "^2.0.0" - -npm-conf@^1.1.0: - version "1.1.3" - resolved "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz" - integrity sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw== - dependencies: - config-chain "^1.1.11" - pify "^3.0.0" - -npm-run-path@^2.0.0: - version "2.0.2" - resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz" - integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= - dependencies: - path-key "^2.0.0" - -npm-run-path@^4.0.0, npm-run-path@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz" - integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== - dependencies: - path-key "^3.0.0" - -nprogress@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz" - integrity sha1-y480xTIT2JVyP8urkH6UIq28r7E= - -nth-check@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d" - integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w== - dependencies: - boolbase "^1.0.0" - -nwsapi@^2.2.0: - version "2.2.0" - resolved "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz" - integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== - -object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== - -object-copy@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz" - integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= - dependencies: - copy-descriptor "^0.1.0" - define-property "^0.2.5" - kind-of "^3.0.3" - -object-inspect@^1.13.1: - version "1.13.2" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" - integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== - -object-inspect@^1.7.0, object-inspect@^1.8.0: - version "1.8.0" - resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz" - integrity sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA== - -object-inspect@^1.9.0: - version "1.12.2" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" - integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== - -object-is@^1.0.1: - version "1.1.2" - resolved "https://registry.npmjs.org/object-is/-/object-is-1.1.2.tgz" - integrity sha512-5lHCz+0uufF6wZ7CRFWJN3hp8Jqblpgve06U5CMQ3f//6iDjPr2PEo9MWCjEssDsa+UZEL4PkFpr+BMop6aKzQ== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.5" - -object-is@^1.1.2: - version "1.1.4" - resolved "https://registry.npmjs.org/object-is/-/object-is-1.1.4.tgz" - integrity sha512-1ZvAZ4wlF7IyPVOcE1Omikt7UpaFlOQq0HlSti+ZvDH3UiD2brwGMwDbyV43jao2bKJ+4+WdPJHSd7kgzKYVqg== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - -object-is@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" - integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - -object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz" - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== - -object-visit@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz" - integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= - dependencies: - isobject "^3.0.0" - -object.assign@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz" - integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== - dependencies: - define-properties "^1.1.2" - function-bind "^1.1.1" - has-symbols "^1.0.0" - object-keys "^1.0.11" - -object.assign@^4.1.1, object.assign@^4.1.2: - version "4.1.2" - resolved "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz" - integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - has-symbols "^1.0.1" - object-keys "^1.1.1" - -object.assign@^4.1.4: - version "4.1.4" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f" - integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - has-symbols "^1.0.3" - object-keys "^1.1.1" - -object.entries@^1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/object.entries/-/object.entries-1.1.2.tgz" - integrity sha512-BQdB9qKmb/HyNdMNWVr7O3+z5MUIx3aiegEIJqjMBbBf0YT9RRxTJSim4mzFqtyr7PDAHigq0N9dO0m0tRakQA== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.5" - has "^1.0.3" - -object.fromentries@^2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.2.tgz" - integrity sha512-r3ZiBH7MQppDJVLx6fhD618GKNG40CZYH9wgwdhKxBDDbQgjeWGGd4AtkZad84d291YxvWe7bJGuE65Anh0dxQ== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" - function-bind "^1.1.1" - has "^1.0.3" - -object.pick@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz" - integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= - dependencies: - isobject "^3.0.1" - -object.values@^1.0.4: - version "1.1.2" - resolved "https://registry.npmjs.org/object.values/-/object.values-1.1.2.tgz" - integrity sha512-MYC0jvJopr8EK6dPBiO8Nb9mvjdypOachO5REGk6MXzujbBrAisKo3HmdEI6kZDL6fC31Mwee/5YbtMebixeag== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - es-abstract "^1.18.0-next.1" - has "^1.0.3" - -object.values@^1.1.0, object.values@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz" - integrity sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" - function-bind "^1.1.1" - has "^1.0.3" - -obuf@^1.0.0, obuf@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" - integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== - -on-finished@2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" - integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== - dependencies: - ee-first "1.1.1" - -on-headers@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" - integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== - -once@^1.3.0, once@^1.3.1, once@^1.4.0: - version "1.4.0" - resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -onetime@^5.1.0: - version "5.1.0" - resolved "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz" - integrity sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q== - dependencies: - mimic-fn "^2.1.0" - -onetime@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" - integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== - dependencies: - mimic-fn "^2.1.0" - -open@^8.0.9: - version "8.4.2" - resolved "https://registry.yarnpkg.com/open/-/open-8.4.2.tgz#5b5ffe2a8f793dcd2aad73e550cb87b59cb084f9" - integrity sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ== - dependencies: - define-lazy-prop "^2.0.0" - is-docker "^2.1.1" - is-wsl "^2.2.0" - -opener@^1.5.2: - version "1.5.2" - resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598" - integrity sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A== - -optionator@^0.8.1: - version "0.8.3" - resolved "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz" - integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== - dependencies: - deep-is "~0.1.3" - fast-levenshtein "~2.0.6" - levn "~0.3.0" - prelude-ls "~1.1.2" - type-check "~0.3.2" - word-wrap "~1.2.3" - -optionator@^0.9.1: - version "0.9.1" - resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz" - integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== - 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" - -optipng-bin@^7.0.0: - version "7.0.1" - resolved "https://registry.yarnpkg.com/optipng-bin/-/optipng-bin-7.0.1.tgz#beb8e55a52f8a26f885ee57ab44fcf62397d6972" - integrity sha512-W99mpdW7Nt2PpFiaO+74pkht7KEqkXkeRomdWXfEz3SALZ6hns81y/pm1dsGZ6ItUIfchiNIP6ORDr1zETU1jA== - dependencies: - bin-build "^3.0.0" - bin-wrapper "^4.0.0" - -os-filter-obj@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/os-filter-obj/-/os-filter-obj-2.0.0.tgz" - integrity sha512-uksVLsqG3pVdzzPvmAHpBK0wKxYItuzZr7SziusRPoz67tGV8rL1szZ6IdeUrbqLjGDwApBtN29eEE3IqGHOjg== - dependencies: - arch "^2.1.0" - -outy@^0.1.2: - version "0.1.2" - resolved "https://registry.npmjs.org/outy/-/outy-0.1.2.tgz" - integrity sha1-WY05XkP5LlLZiq3/I7cqPnEotXI= - -ow@^0.17.0: - version "0.17.0" - resolved "https://registry.yarnpkg.com/ow/-/ow-0.17.0.tgz#4f938999fed6264c9048cd6254356e0f1e7f688c" - integrity sha512-i3keDzDQP5lWIe4oODyDFey1qVrq2hXKTuTH2VpqwpYtzPiKZt2ziRI4NBQmgW40AnV5Euz17OyWweCb+bNEQA== - dependencies: - type-fest "^0.11.0" - -p-cancelable@^0.3.0: - version "0.3.0" - resolved "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.3.0.tgz" - integrity sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw== - -p-cancelable@^0.4.0: - version "0.4.1" - resolved "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz" - integrity sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ== - -p-each-series@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/p-each-series/-/p-each-series-2.1.0.tgz" - integrity sha512-ZuRs1miPT4HrjFa+9fRfOFXxGJfORgelKV9f9nNOWw2gl6gVsRaVDOQP0+MI0G0wGKns1Yacsu0GjOFbTK0JFQ== - -p-event@^1.0.0: - version "1.3.0" - resolved "https://registry.npmjs.org/p-event/-/p-event-1.3.0.tgz" - integrity sha1-jmtPT2XHK8W2/ii3XtqHT5akoIU= - dependencies: - p-timeout "^1.1.1" - -p-event@^2.1.0: - version "2.3.1" - resolved "https://registry.npmjs.org/p-event/-/p-event-2.3.1.tgz" - integrity sha512-NQCqOFhbpVTMX4qMe8PF8lbGtzZ+LCiN7pcNrb/413Na7+TRoe1xkKUzuWa/YEJdGQ0FvKtj35EEbDoVPO2kbA== - dependencies: - p-timeout "^2.0.1" - -p-finally@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz" - integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= - -p-is-promise@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz" - integrity sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4= - -p-limit@^1.1.0: - version "1.3.0" - resolved "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz" - integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== - dependencies: - p-try "^1.0.0" - -p-limit@^2.2.0: - version "2.3.0" - resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" - integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== - dependencies: - p-try "^2.0.0" - -p-limit@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" - integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== - dependencies: - yocto-queue "^0.1.0" - -p-limit@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-4.0.0.tgz#914af6544ed32bfa54670b061cafcbd04984b644" - integrity sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ== - dependencies: - yocto-queue "^1.0.0" - -p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz" - integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= - dependencies: - p-limit "^1.1.0" - -p-locate@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz" - integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== - dependencies: - p-limit "^2.2.0" - -p-locate@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" - integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== - dependencies: - p-limit "^3.0.2" - -p-locate@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-6.0.0.tgz#3da9a49d4934b901089dca3302fa65dc5a05c04f" - integrity sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw== - dependencies: - p-limit "^4.0.0" - -p-map-series@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/p-map-series/-/p-map-series-1.0.0.tgz" - integrity sha1-v5j+V1cFZYqeE1G++4WuTB8Hvco= - dependencies: - p-reduce "^1.0.0" - -p-pipe@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/p-pipe/-/p-pipe-3.1.0.tgz" - integrity sha512-08pj8ATpzMR0Y80x50yJHn37NF6vjrqHutASaX5LiH5npS9XPvrUmscd9MF5R4fuYRHOxQR1FfMIlF7AzwoPqw== - -p-reduce@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz" - integrity sha1-GMKw3ZNqRpClKfgjH1ig/bakffo= - -p-retry@^4.5.0: - version "4.6.2" - resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-4.6.2.tgz#9baae7184057edd4e17231cee04264106e092a16" - integrity sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ== - dependencies: - "@types/retry" "0.12.0" - retry "^0.13.1" - -p-timeout@^1.1.1: - version "1.2.1" - resolved "https://registry.npmjs.org/p-timeout/-/p-timeout-1.2.1.tgz" - integrity sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y= - dependencies: - p-finally "^1.0.0" - -p-timeout@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz" - integrity sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA== - dependencies: - p-finally "^1.0.0" - -p-try@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz" - integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= - -p-try@^2.0.0: - version "2.2.0" - resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz" - integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== - -paginator@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/paginator/-/paginator-1.0.0.tgz" - integrity sha1-dWVwKvmrlhbcph/CLHDroqQ1cmU= - -parent-module@^1.0.0: - 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== - dependencies: - callsites "^3.0.0" - -parse-entities@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-4.0.1.tgz#4e2a01111fb1c986549b944af39eeda258fc9e4e" - integrity sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w== - dependencies: - "@types/unist" "^2.0.0" - character-entities "^2.0.0" - character-entities-legacy "^3.0.0" - character-reference-invalid "^2.0.0" - decode-named-character-reference "^1.0.0" - is-alphanumerical "^2.0.0" - is-decimal "^2.0.0" - is-hexadecimal "^2.0.0" - -parse-json@^2.2.0: - version "2.2.0" - resolved "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz" - integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= - dependencies: - error-ex "^1.2.0" - -parse-json@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz" - integrity sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw== - dependencies: - "@babel/code-frame" "^7.0.0" - error-ex "^1.3.1" - json-parse-better-errors "^1.0.1" - lines-and-columns "^1.1.6" - -parse5@6.0.1: - version "6.0.1" - resolved "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz" - integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== - -parse5@^7.0.0: - version "7.1.2" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.1.2.tgz#0736bebbfd77793823240a23b7fc5e010b7f8e32" - integrity sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw== - dependencies: - entities "^4.4.0" - -parseurl@~1.3.2, parseurl@~1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" - integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== - -pascalcase@^0.1.1: - version "0.1.1" - resolved "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz" - integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= - -path-browserify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" - integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g== - -path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz" - integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= - -path-exists@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" - integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== - -path-exists@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-5.0.0.tgz#a6aad9489200b21fab31e49cf09277e5116fb9e7" - integrity sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ== - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -path-key@^2.0.0, path-key@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz" - integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= - -path-key@^3.0.0, path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -path-parse@^1.0.6, path-parse@^1.0.7: - version "1.0.7" - resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" - integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== - -path-to-regexp@0.1.10: - version "0.1.10" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.10.tgz#67e9108c5c0551b9e5326064387de4763c4d5f8b" - integrity sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w== - -path-type@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz" - integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= - dependencies: - pify "^2.0.0" - -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== - -pend@~1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz" - integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= - -performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz" - integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= - -phoenix@^1.6.6: - version "1.6.15" - resolved "https://registry.yarnpkg.com/phoenix/-/phoenix-1.6.15.tgz#efb2088a310cde333b3762002831b79dedf76002" - integrity sha512-O6AG5jTkZOOkdd/GOSCsM4v3bzBoyRnC5bEi57KhX/Daba6FvnBRzt0nhEeRRiVQGLSxDlyb0dUe9CkYWMZd8g== - -phoenix_html@^3.2.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/phoenix_html/-/phoenix_html-3.3.0.tgz#75862f2270b8e6da3b5e528512a1a64de92f7874" - integrity sha512-Q/X9UhxQLMYOuA8cXrDSH7PWTK/+vCpX+rtSheoNaPb/qDVoi+R3GPYKgL9CJ06+VWhcC3kkZ05O/RVsby7m6A== - -phoenix_live_view@^0.18.6: - version "0.18.16" - resolved "https://registry.yarnpkg.com/phoenix_live_view/-/phoenix_live_view-0.18.16.tgz#88f5a18c9b523e3138d192297b0ca0ea6a59d449" - integrity sha512-Nttq6JcHJnhM5Yfrz7XRxrJGlI8O6Umc9JVW1h9CRF9PnP+mlhcWrlosqPK/nYQbiA6PVxjJ/1vcafDiZniq7A== - -picocolors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" - integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== - -picocolors@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" - integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== - -picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.2.1: - version "2.2.2" - resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz" - integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== - -picomatch@^2.2.3, picomatch@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" - integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== - -pify@^2.0.0, pify@^2.2.0, pify@^2.3.0: - version "2.3.0" - resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz" - integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= - -pify@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz" - integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= - -pify@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz" - integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== - -pinkie-promise@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz" - integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= - dependencies: - pinkie "^2.0.0" - -pinkie@^2.0.0: - version "2.0.4" - resolved "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz" - integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= - -pirates@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz" - integrity sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA== - dependencies: - node-modules-regexp "^1.0.0" - -pirates@^4.0.4: - version "4.0.6" - resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" - integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== - -pkg-dir@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz" - integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= - dependencies: - find-up "^2.1.0" - -pkg-dir@^4.2.0: - version "4.2.0" - resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz" - integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== - dependencies: - find-up "^4.0.0" - -pkg-dir@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-7.0.0.tgz#8f0c08d6df4476756c5ff29b3282d0bab7517d11" - integrity sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA== - dependencies: - find-up "^6.3.0" - -pkginfo@^0.4.0: - version "0.4.1" - resolved "https://registry.npmjs.org/pkginfo/-/pkginfo-0.4.1.tgz" - integrity sha1-tUGO8EOd5UJfxJlQQtztFPsqhP8= - -pngquant-bin@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/pngquant-bin/-/pngquant-bin-6.0.1.tgz#2b5789ca219eeb4d8509ab1ae082092801b7f07e" - integrity sha512-Q3PUyolfktf+hYio6wsg3SanQzEU/v8aICg/WpzxXcuCMRb7H2Q81okfpcEztbMvw25ILjd3a87doj2N9kvbpQ== - dependencies: - bin-build "^3.0.0" - bin-wrapper "^4.0.1" - execa "^4.0.0" - -polished@^2.3.0: - version "2.3.3" - resolved "https://registry.npmjs.org/polished/-/polished-2.3.3.tgz" - integrity sha512-59V4fDbdxtH4I1m9TWxFsoGJbC8nnOpUYo5uFmvMfKp9Qh+6suo4VMUle1TGIIUZIGxfkW+Rs485zPk0wcwR2Q== - dependencies: - "@babel/runtime" "^7.2.0" - -popper.js@^1.14.4, popper.js@^1.16.0, popper.js@^1.16.1: - version "1.16.1" - resolved "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz" - integrity sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ== - -posix-character-classes@^0.1.0: - version "0.1.1" - resolved "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz" - integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= - -postcss-calc@^9.0.0: - version "9.0.1" - resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-9.0.1.tgz#a744fd592438a93d6de0f1434c572670361eb6c6" - integrity sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ== - dependencies: - postcss-selector-parser "^6.0.11" - postcss-value-parser "^4.2.0" - -postcss-colormin@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-6.0.0.tgz#d4250652e952e1c0aca70c66942da93d3cdeaafe" - integrity sha512-EuO+bAUmutWoZYgHn2T1dG1pPqHU6L4TjzPlu4t1wZGXQ/fxV16xg2EJmYi0z+6r+MGV1yvpx1BHkUaRrPa2bw== - dependencies: - browserslist "^4.21.4" - caniuse-api "^3.0.0" - colord "^2.9.1" - postcss-value-parser "^4.2.0" - -postcss-convert-values@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-6.0.0.tgz#ec94a954957e5c3f78f0e8f65dfcda95280b8996" - integrity sha512-U5D8QhVwqT++ecmy8rnTb+RL9n/B806UVaS3m60lqle4YDFcpbS3ae5bTQIh3wOGUSDHSEtMYLs/38dNG7EYFw== - dependencies: - browserslist "^4.21.4" - postcss-value-parser "^4.2.0" - -postcss-discard-comments@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-6.0.0.tgz#9ca335e8b68919f301b24ba47dde226a42e535fe" - integrity sha512-p2skSGqzPMZkEQvJsgnkBhCn8gI7NzRH2683EEjrIkoMiwRELx68yoUJ3q3DGSGuQ8Ug9Gsn+OuDr46yfO+eFw== - -postcss-discard-duplicates@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.0.tgz#c26177a6c33070922e67e9a92c0fd23d443d1355" - integrity sha512-bU1SXIizMLtDW4oSsi5C/xHKbhLlhek/0/yCnoMQany9k3nPBq+Ctsv/9oMmyqbR96HYHxZcHyK2HR5P/mqoGA== - -postcss-discard-empty@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-6.0.0.tgz#06c1c4fce09e22d2a99e667c8550eb8a3a1b9aee" - integrity sha512-b+h1S1VT6dNhpcg+LpyiUrdnEZfICF0my7HAKgJixJLW7BnNmpRH34+uw/etf5AhOlIhIAuXApSzzDzMI9K/gQ== - -postcss-discard-overridden@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-6.0.0.tgz#49c5262db14e975e349692d9024442de7cd8e234" - integrity sha512-4VELwssYXDFigPYAZ8vL4yX4mUepF/oCBeeIT4OXsJPYOtvJumyz9WflmJWTfDwCUcpDR+z0zvCWBXgTx35SVw== - -postcss-loader@^7.3.3: - version "7.3.3" - resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-7.3.3.tgz#6da03e71a918ef49df1bb4be4c80401df8e249dd" - integrity sha512-YgO/yhtevGO/vJePCQmTxiaEwER94LABZN0ZMT4A0vsak9TpO+RvKRs7EmJ8peIlB9xfXCsS7M8LjqncsUZ5HA== - dependencies: - cosmiconfig "^8.2.0" - jiti "^1.18.2" - semver "^7.3.8" - -postcss-merge-longhand@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-6.0.0.tgz#6f627b27db939bce316eaa97e22400267e798d69" - integrity sha512-4VSfd1lvGkLTLYcxFuISDtWUfFS4zXe0FpF149AyziftPFQIWxjvFSKhA4MIxMe4XM3yTDgQMbSNgzIVxChbIg== - dependencies: - postcss-value-parser "^4.2.0" - stylehacks "^6.0.0" - -postcss-merge-rules@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-6.0.1.tgz#39f165746404e646c0f5c510222ccde4824a86aa" - integrity sha512-a4tlmJIQo9SCjcfiCcCMg/ZCEe0XTkl/xK0XHBs955GWg9xDX3NwP9pwZ78QUOWB8/0XCjZeJn98Dae0zg6AAw== - dependencies: - browserslist "^4.21.4" - caniuse-api "^3.0.0" - cssnano-utils "^4.0.0" - postcss-selector-parser "^6.0.5" - -postcss-minify-font-values@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-6.0.0.tgz#68d4a028f9fa5f61701974724b2cc9445d8e6070" - integrity sha512-zNRAVtyh5E8ndZEYXA4WS8ZYsAp798HiIQ1V2UF/C/munLp2r1UGHwf1+6JFu7hdEhJFN+W1WJQKBrtjhFgEnA== - dependencies: - postcss-value-parser "^4.2.0" - -postcss-minify-gradients@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-6.0.0.tgz#22b5c88cc63091dadbad34e31ff958404d51d679" - integrity sha512-wO0F6YfVAR+K1xVxF53ueZJza3L+R3E6cp0VwuXJQejnNUH0DjcAFe3JEBeTY1dLwGa0NlDWueCA1VlEfiKgAA== - dependencies: - colord "^2.9.1" - cssnano-utils "^4.0.0" - postcss-value-parser "^4.2.0" - -postcss-minify-params@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-6.0.0.tgz#2b3a85a9e3b990d7a16866f430f5fd1d5961b539" - integrity sha512-Fz/wMQDveiS0n5JPcvsMeyNXOIMrwF88n7196puSuQSWSa+/Ofc1gDOSY2xi8+A4PqB5dlYCKk/WfqKqsI+ReQ== - dependencies: - browserslist "^4.21.4" - cssnano-utils "^4.0.0" - postcss-value-parser "^4.2.0" - -postcss-minify-selectors@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-6.0.0.tgz#5046c5e8680a586e5a0cad52cc9aa36d6be5bda2" - integrity sha512-ec/q9JNCOC2CRDNnypipGfOhbYPuUkewGwLnbv6omue/PSASbHSU7s6uSQ0tcFRVv731oMIx8k0SP4ZX6be/0g== - dependencies: - postcss-selector-parser "^6.0.5" - -postcss-modules-extract-imports@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d" - integrity sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw== - -postcss-modules-local-by-default@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz#b08eb4f083050708998ba2c6061b50c2870ca524" - integrity sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA== - dependencies: - icss-utils "^5.0.0" - postcss-selector-parser "^6.0.2" - postcss-value-parser "^4.1.0" - -postcss-modules-scope@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz#9ef3151456d3bbfa120ca44898dfca6f2fa01f06" - integrity sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg== - dependencies: - postcss-selector-parser "^6.0.4" - -postcss-modules-values@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz#d7c5e7e68c3bb3c9b27cbf48ca0bb3ffb4602c9c" - integrity sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ== - dependencies: - icss-utils "^5.0.0" - -postcss-normalize-charset@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-6.0.0.tgz#36cc12457259064969fb96f84df491652a4b0975" - integrity sha512-cqundwChbu8yO/gSWkuFDmKrCZ2vJzDAocheT2JTd0sFNA4HMGoKMfbk2B+J0OmO0t5GUkiAkSM5yF2rSLUjgQ== - -postcss-normalize-display-values@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.0.tgz#8d2961415078644d8c6bbbdaf9a2fdd60f546cd4" - integrity sha512-Qyt5kMrvy7dJRO3OjF7zkotGfuYALETZE+4lk66sziWSPzlBEt7FrUshV6VLECkI4EN8Z863O6Nci4NXQGNzYw== - dependencies: - postcss-value-parser "^4.2.0" - -postcss-normalize-positions@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-6.0.0.tgz#25b96df99a69f8925f730eaee0be74416865e301" - integrity sha512-mPCzhSV8+30FZyWhxi6UoVRYd3ZBJgTRly4hOkaSifo0H+pjDYcii/aVT4YE6QpOil15a5uiv6ftnY3rm0igPg== - dependencies: - postcss-value-parser "^4.2.0" - -postcss-normalize-repeat-style@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.0.tgz#ddf30ad8762feb5b1eb97f39f251acd7b8353299" - integrity sha512-50W5JWEBiOOAez2AKBh4kRFm2uhrT3O1Uwdxz7k24aKtbD83vqmcVG7zoIwo6xI2FZ/HDlbrCopXhLeTpQib1A== - dependencies: - postcss-value-parser "^4.2.0" - -postcss-normalize-string@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-6.0.0.tgz#948282647a51e409d69dde7910f0ac2ff97cb5d8" - integrity sha512-KWkIB7TrPOiqb8ZZz6homet2KWKJwIlysF5ICPZrXAylGe2hzX/HSf4NTX2rRPJMAtlRsj/yfkrWGavFuB+c0w== - dependencies: - postcss-value-parser "^4.2.0" - -postcss-normalize-timing-functions@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.0.tgz#5f13e650b8c43351989fc5de694525cc2539841c" - integrity sha512-tpIXWciXBp5CiFs8sem90IWlw76FV4oi6QEWfQwyeREVwUy39VSeSqjAT7X0Qw650yAimYW5gkl2Gd871N5SQg== - dependencies: - postcss-value-parser "^4.2.0" - -postcss-normalize-unicode@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-6.0.0.tgz#741b3310f874616bdcf07764f5503695d3604730" - integrity sha512-ui5crYkb5ubEUDugDc786L/Me+DXp2dLg3fVJbqyAl0VPkAeALyAijF2zOsnZyaS1HyfPuMH0DwyY18VMFVNkg== - dependencies: - browserslist "^4.21.4" - postcss-value-parser "^4.2.0" - -postcss-normalize-url@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-6.0.0.tgz#d0a31e962a16401fb7deb7754b397a323fb650b4" - integrity sha512-98mvh2QzIPbb02YDIrYvAg4OUzGH7s1ZgHlD3fIdTHLgPLRpv1ZTKJDnSAKr4Rt21ZQFzwhGMXxpXlfrUBKFHw== - dependencies: - postcss-value-parser "^4.2.0" - -postcss-normalize-whitespace@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.0.tgz#accb961caa42e25ca4179b60855b79b1f7129d4d" - integrity sha512-7cfE1AyLiK0+ZBG6FmLziJzqQCpTQY+8XjMhMAz8WSBSCsCNNUKujgIgjCAmDT3cJ+3zjTXFkoD15ZPsckArVw== - dependencies: - postcss-value-parser "^4.2.0" - -postcss-ordered-values@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-6.0.0.tgz#374704cdff25560d44061d17ba3c6308837a3218" - integrity sha512-K36XzUDpvfG/nWkjs6d1hRBydeIxGpKS2+n+ywlKPzx1nMYDYpoGbcjhj5AwVYJK1qV2/SDoDEnHzlPD6s3nMg== - dependencies: - cssnano-utils "^4.0.0" - postcss-value-parser "^4.2.0" - -postcss-reduce-initial@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-6.0.0.tgz#7d16e83e60e27e2fa42f56ec0b426f1da332eca7" - integrity sha512-s2UOnidpVuXu6JiiI5U+fV2jamAw5YNA9Fdi/GRK0zLDLCfXmSGqQtzpUPtfN66RtCbb9fFHoyZdQaxOB3WxVA== - dependencies: - browserslist "^4.21.4" - caniuse-api "^3.0.0" - -postcss-reduce-transforms@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.0.tgz#28ff2601a6d9b96a2f039b3501526e1f4d584a46" - integrity sha512-FQ9f6xM1homnuy1wLe9lP1wujzxnwt1EwiigtWwuyf8FsqqXUDUp2Ulxf9A5yjlUOTdCJO6lonYjg1mgqIIi2w== - dependencies: - postcss-value-parser "^4.2.0" - -postcss-selector-parser@^6.0.11: - version "6.0.13" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz#d05d8d76b1e8e173257ef9d60b706a8e5e99bf1b" - integrity sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ== - dependencies: - cssesc "^3.0.0" - util-deprecate "^1.0.2" - -postcss-selector-parser@^6.0.2: - version "6.0.2" - resolved "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz" - integrity sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg== - dependencies: - cssesc "^3.0.0" - indexes-of "^1.0.1" - uniq "^1.0.1" - -postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5: - version "6.0.11" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz#2e41dc39b7ad74046e1615185185cd0b17d0c8dc" - integrity sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g== - dependencies: - cssesc "^3.0.0" - util-deprecate "^1.0.2" - -postcss-svgo@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-6.0.0.tgz#7b18742d38d4505a0455bbe70d52b49f00eaf69d" - integrity sha512-r9zvj/wGAoAIodn84dR/kFqwhINp5YsJkLoujybWG59grR/IHx+uQ2Zo+IcOwM0jskfYX3R0mo+1Kip1VSNcvw== - dependencies: - postcss-value-parser "^4.2.0" - svgo "^3.0.2" - -postcss-unique-selectors@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-6.0.0.tgz#c94e9b0f7bffb1203894e42294b5a1b3fb34fbe1" - integrity sha512-EPQzpZNxOxP7777t73RQpZE5e9TrnCrkvp7AH7a0l89JmZiPnS82y216JowHXwpBCQitfyxrof9TK3rYbi7/Yw== - dependencies: - postcss-selector-parser "^6.0.5" - -postcss-value-parser@^3.3.0: - version "3.3.1" - resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz" - integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== - -postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz" - integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ== - -postcss-value-parser@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" - integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== - -postcss@^8.2.14, postcss@^8.4.21, postcss@^8.4.24, postcss@^8.4.31: - version "8.4.31" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d" - integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ== - dependencies: - nanoid "^3.3.6" - picocolors "^1.0.0" - source-map-js "^1.0.2" - -prelude-ls@^1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz" - integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== - -prelude-ls@~1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz" - integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w== - -prepend-http@^1.0.1: - version "1.0.4" - resolved "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz" - integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= - -prepend-http@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz" - integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= - -pretty-format@^25.2.1, pretty-format@^25.5.0: - version "25.5.0" - resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-25.5.0.tgz" - integrity sha512-kbo/kq2LQ/A/is0PQwsEHM7Ca6//bGPPvU6UnsdDRSKTWxT/ru/xb88v4BJf6a69H+uTytOEsTusT9ksd/1iWQ== - dependencies: - "@jest/types" "^25.5.0" - ansi-regex "^5.0.0" - ansi-styles "^4.0.0" - react-is "^16.12.0" - -pretty-format@^26.6.2: - version "26.6.2" - resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz" - integrity sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg== - dependencies: - "@jest/types" "^26.6.2" - ansi-regex "^5.0.0" - ansi-styles "^4.0.0" - react-is "^17.0.1" - -pretty-format@^27.0.2: - version "27.5.1" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e" - integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ== - dependencies: - ansi-regex "^5.0.1" - ansi-styles "^5.0.0" - react-is "^17.0.1" - -process-nextick-args@~2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz" - integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== - -process@^0.11.10: - version "0.11.10" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" - integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== - -progress@^2.0.0: - version "2.0.3" - resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - -prompts@^2.0.1: - version "2.3.2" - resolved "https://registry.npmjs.org/prompts/-/prompts-2.3.2.tgz" - integrity sha512-Q06uKs2CkNYVID0VqwfAl9mipo99zkBv/n2JtWY89Yxa3ZabWSrs0e2KTudKVa3peLUvYXMefDqIleLPVUBZMA== - dependencies: - kleur "^3.0.3" - sisteransi "^1.0.4" - -prop-types-exact@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/prop-types-exact/-/prop-types-exact-1.2.0.tgz" - integrity sha512-K+Tk3Kd9V0odiXFP9fwDHUYRyvK3Nun3GVyPapSIs5OBkITAm15W0CPFD/YKTkMUAbc0b9CUwRQp2ybiBIq+eA== - dependencies: - has "^1.0.3" - object.assign "^4.1.0" - reflect.ownkeys "^0.2.0" - -prop-types-extra@^1.1.0: - version "1.1.1" - resolved "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz" - integrity sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew== - dependencies: - react-is "^16.3.2" - warning "^4.0.0" - -"prop-types@15.x.x - 16.x.x", prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2: - version "15.7.2" - resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz" - integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== - dependencies: - loose-envify "^1.4.0" - object-assign "^4.1.1" - react-is "^16.8.1" - -prop-types@^15.5.7, prop-types@^15.7.2, prop-types@^15.8.1: - version "15.8.1" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" - integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== - dependencies: - loose-envify "^1.4.0" - object-assign "^4.1.1" - react-is "^16.13.1" - -property-expr@^2.0.2: - version "2.0.4" - resolved "https://registry.npmjs.org/property-expr/-/property-expr-2.0.4.tgz" - integrity sha512-sFPkHQjVKheDNnPvotjQmm3KD3uk1fWKUN7CrpdbwmUx3CrG3QiM8QpTSimvig5vTXmTvjz7+TDvXOI9+4rkcg== - -property-information@^6.0.0: - version "6.5.0" - resolved "https://registry.yarnpkg.com/property-information/-/property-information-6.5.0.tgz#6212fbb52ba757e92ef4fb9d657563b933b7ffec" - integrity sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig== - -proto-list@~1.2.1: - version "1.2.4" - resolved "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz" - integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk= - -proxy-addr@~2.0.7: - version "2.0.7" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" - integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== - dependencies: - forwarded "0.2.0" - ipaddr.js "1.9.1" - -proxy-from-env@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" - integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== - -pseudomap@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz" - integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= - -psl@^1.1.33: - version "1.8.0" - resolved "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz" - integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== - -pump@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz" - integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - -punycode@^2.1.0, punycode@^2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - -qs@6.13.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906" - integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg== - dependencies: - side-channel "^1.0.6" - -qs@^6.9.4: - version "6.11.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" - integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== - dependencies: - side-channel "^1.0.4" - -query-string@^5.0.1: - version "5.1.1" - resolved "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz" - integrity sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw== - dependencies: - decode-uri-component "^0.2.0" - object-assign "^4.1.0" - strict-uri-encode "^1.0.0" - -querystringify@^2.1.1: - version "2.2.0" - resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" - integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== - -quill-delta@^4.2.2: - version "4.2.2" - resolved "https://registry.npmjs.org/quill-delta/-/quill-delta-4.2.2.tgz" - integrity sha512-qjbn82b/yJzOjstBgkhtBjN2TNK+ZHP/BgUQO+j6bRhWQQdmj2lH6hXG7+nwwLF41Xgn//7/83lxs9n2BkTtTg== - dependencies: - fast-diff "1.2.0" - lodash.clonedeep "^4.5.0" - lodash.isequal "^4.5.0" - -raf@^3.4.1: - version "3.4.1" - resolved "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz" - integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA== - dependencies: - performance-now "^2.1.0" - -randombytes@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz" - integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== - dependencies: - safe-buffer "^5.1.0" - -range-parser@^1.2.1, range-parser@~1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" - integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== - -raw-body@2.5.2: - version "2.5.2" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" - integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== - dependencies: - bytes "3.1.2" - http-errors "2.0.0" - iconv-lite "0.4.24" - unpipe "1.0.0" - -react-bootstrap@^1.6.7: - version "1.6.7" - resolved "https://registry.yarnpkg.com/react-bootstrap/-/react-bootstrap-1.6.7.tgz#7afea926cada8175d67df07b893dbad2998ae463" - integrity sha512-IzCYXuLSKDEjGFglbFWk0/iHmdhdcJzTmtS6lXxc0kaNFx2PFgrQf5jKnx5sarF2tiXh9Tgx3pSt3pdK7YwkMA== - dependencies: - "@babel/runtime" "^7.14.0" - "@restart/context" "^2.1.4" - "@restart/hooks" "^0.4.7" - "@types/invariant" "^2.2.33" - "@types/prop-types" "^15.7.3" - "@types/react" ">=16.14.8" - "@types/react-transition-group" "^4.4.1" - "@types/warning" "^3.0.0" - classnames "^2.3.1" - dom-helpers "^5.2.1" - invariant "^2.2.4" - prop-types "^15.7.2" - prop-types-extra "^1.1.0" - react-overlays "^5.1.2" - react-transition-group "^4.4.1" - uncontrollable "^7.2.1" - warning "^4.0.3" - -react-calendar-heatmap@^1.8.1: - version "1.8.1" - resolved "https://registry.npmjs.org/react-calendar-heatmap/-/react-calendar-heatmap-1.8.1.tgz" - integrity sha512-4Hbq/pDMJoCPzZnyIWFfHgokLlLXzKyGsDcMgNhYpi7zcKHcvsK9soLEPvhW2dBBqgDrQOSp/uG4wtifaDg4eQ== - dependencies: - memoize-one "^5.0.0" - prop-types "^15.6.2" - -react-chartjs-2@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/react-chartjs-2/-/react-chartjs-2-5.2.0.tgz#43c1e3549071c00a1a083ecbd26c1ad34d385f5d" - integrity sha512-98iN5aguJyVSxp5U3CblRLH67J8gkfyGNbiK3c+l1QI/G4irHMPQw44aEPmjVag+YKTyQ260NcF82GTQ3bdscA== - -react-contexify@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/react-contexify/-/react-contexify-6.0.0.tgz#52959bb507d6a31224fe870ae147e211e359abe1" - integrity sha512-jMhz6yZI81Jv3UDj7TXqCkhdkCFEEmvwGCPXsQuA2ZUC8EbCuVQ6Cy8FzKMXa0y454XTDClBN2YFvvmoFlrFkg== - dependencies: - clsx "^1.2.1" - -react-dates@^21.8.0: - version "21.8.0" - resolved "https://registry.npmjs.org/react-dates/-/react-dates-21.8.0.tgz" - integrity sha512-PPriGqi30CtzZmoHiGdhlA++YPYPYGCZrhydYmXXQ6RAvAsaONcPtYgXRTLozIOrsQ5mSo40+DiA5eOFHnZ6xw== - dependencies: - airbnb-prop-types "^2.15.0" - consolidated-events "^1.1.1 || ^2.0.0" - enzyme-shallow-equal "^1.0.0" - is-touch-device "^1.0.1" - lodash "^4.1.1" - object.assign "^4.1.0" - object.values "^1.1.0" - prop-types "^15.7.2" - raf "^3.4.1" - react-moment-proptypes "^1.6.0" - react-outside-click-handler "^1.2.4" - react-portal "^4.2.0" - react-with-direction "^1.3.1" - react-with-styles "^4.1.0" - react-with-styles-interface-css "^6.0.0" - -react-devicons@^2.14.0: - version "2.14.0" - resolved "https://registry.yarnpkg.com/react-devicons/-/react-devicons-2.14.0.tgz#718dc2f7261fd8bc6261a67fe1b242a309c6160f" - integrity sha512-4k/fQvDapIQJDlLKTEM8yxV5UTF8OvGrGeM4F06KRQYGYAtP8CxjC1LBWEyHL0M7rHga1rH9H14kJoFIb8O2kg== - dependencies: - react "^17.0.2" - -react-dom@^18.2.0: - version "18.2.0" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d" - integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g== - dependencies: - loose-envify "^1.1.0" - scheduler "^0.23.0" - -react-fast-compare@^2.0.1: - version "2.0.4" - resolved "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz" - integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw== - -react-feather@^2.0.10: - version "2.0.10" - resolved "https://registry.yarnpkg.com/react-feather/-/react-feather-2.0.10.tgz#0e9abf05a66754f7b7bb71757ac4da7fb6be3b68" - integrity sha512-BLhukwJ+Z92Nmdcs+EMw6dy1Z/VLiJTzEQACDUEnWMClhYnFykJCGWQx+NmwP/qQHGX/5CzQ+TGi8ofg2+HzVQ== - dependencies: - prop-types "^15.7.2" - -react-floater@^0.7.6: - version "0.7.6" - resolved "https://registry.yarnpkg.com/react-floater/-/react-floater-0.7.6.tgz#a98ee90e3d51200c6e6a564ff33496f3c0d7cfee" - integrity sha512-tt/15k/HpaShbtvWCwsQYLR+ebfUuYbl+oAUJ3DcEDkgYKeUcSkDey2PdAIERdVwzdFZANz47HbwoET2/Rduxg== - dependencies: - deepmerge "^4.2.2" - exenv "^1.2.2" - is-lite "^0.8.2" - popper.js "^1.16.0" - prop-types "^15.8.1" - react-proptype-conditional-require "^1.0.4" - tree-changes "^0.9.1" - -react-hotkeys-hook@^4.4.1: - version "4.4.1" - resolved "https://registry.yarnpkg.com/react-hotkeys-hook/-/react-hotkeys-hook-4.4.1.tgz#1f7a7a1c9c21d4fa3280bf340fcca8fd77d81994" - integrity sha512-sClBMBioFEgFGYLTWWRKvhxcCx1DRznd+wkFHwQZspnRBkHTgruKIHptlK/U/2DPX8BhHoRGzpMVWUXMmdZlmw== - -react-hotkeys@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/react-hotkeys/-/react-hotkeys-2.0.0.tgz" - integrity sha512-3n3OU8vLX/pfcJrR3xJ1zlww6KS1kEJt0Whxc4FiGV+MJrQ1mYSYI3qS/11d2MJDFm8IhOXMTFQirfu6AVOF6Q== - dependencies: - prop-types "^15.6.1" - -react-is@^16.10.2, react-is@^16.12.0, react-is@^16.13.1, react-is@^16.3.2, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.6, react-is@^16.9.0: - version "16.13.1" - resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" - integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== - -react-is@^17.0.1: - version "17.0.1" - resolved "https://registry.npmjs.org/react-is/-/react-is-17.0.1.tgz" - integrity sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA== - -react-is@^18.0.0: - version "18.2.0" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" - integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== - -react-joyride@^2.5.5: - version "2.5.5" - resolved "https://registry.yarnpkg.com/react-joyride/-/react-joyride-2.5.5.tgz#a12024902347bea0a565ad2e69b291e35c6a274b" - integrity sha512-/esW9IcsuQJr4NcRZJUH8UYYTvB/yzVC0IyElopbjMFYPw3aylSny91QO3mQRRKPQJUqYa6wREOtQpsaLbu9fw== - dependencies: - deepmerge "^4.3.1" - exenv "^1.2.2" - is-lite "^0.9.2" - prop-types "^15.8.1" - react-floater "^0.7.6" - react-is "^16.13.1" - scroll "^3.0.1" - scrollparent "^2.1.0" - tree-changes "^0.9.2" - -react-js-pagination@^3.0.3: - version "3.0.3" - resolved "https://registry.npmjs.org/react-js-pagination/-/react-js-pagination-3.0.3.tgz" - integrity sha512-podyA6Rd0uxc8uQakXWXxnonoOPI6NnFOROXfc6qPKNYm44s+Bgpn0JkyflcfbHf/GFKahnL8JN8rxBHZiBskg== - dependencies: - classnames "^2.2.5" - fstream "1.0.12" - paginator "^1.0.0" - prop-types "15.x.x - 16.x.x" - react "15.x.x - 16.x.x" - tar "2.2.2" - -react-lifecycles-compat@^3.0.0, react-lifecycles-compat@^3.0.4: - version "3.0.4" - resolved "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz" - integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== - -react-loading@^2.0.3: - version "2.0.3" - resolved "https://registry.npmjs.org/react-loading/-/react-loading-2.0.3.tgz" - integrity sha512-Vdqy79zq+bpeWJqC+xjltUjuGApyoItPgL0vgVfcJHhqwU7bAMKzysfGW/ADu6i0z0JiOCRJjo+IkFNkRNbA3A== - -react-markdown@^9.0.1: - version "9.0.1" - resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-9.0.1.tgz#c05ddbff67fd3b3f839f8c648e6fb35d022397d1" - integrity sha512-186Gw/vF1uRkydbsOIkcGXw7aHq0sZOCRFFjGrr7b9+nVZg4UfA4enXCaxm4fUzecU38sWfrNDitGhshuU7rdg== - dependencies: - "@types/hast" "^3.0.0" - devlop "^1.0.0" - hast-util-to-jsx-runtime "^2.0.0" - html-url-attributes "^3.0.0" - mdast-util-to-hast "^13.0.0" - remark-parse "^11.0.0" - remark-rehype "^11.0.0" - unified "^11.0.0" - unist-util-visit "^5.0.0" - vfile "^6.0.0" - -react-modal@^3.11.1: - version "3.12.1" - resolved "https://registry.npmjs.org/react-modal/-/react-modal-3.12.1.tgz" - integrity sha512-WGuXn7Fq31PbFJwtWmOk+jFtGC7E9tJVbFX0lts8ZoS5EPi9+WWylUJWLKKVm3H4GlQ7ZxY7R6tLlbSIBQ5oZA== - dependencies: - exenv "^1.2.0" - prop-types "^15.5.10" - react-lifecycles-compat "^3.0.0" - warning "^4.0.3" - -react-moment-proptypes@^1.6.0: - version "1.7.0" - resolved "https://registry.npmjs.org/react-moment-proptypes/-/react-moment-proptypes-1.7.0.tgz" - integrity sha512-ZbOn/P4u469WEGAw5hgkS/E+g1YZqdves2BjYsLluJobzUZCtManhjHiZKjniBVT7MSHM6D/iKtRVzlXVv3ikA== - dependencies: - moment ">=1.6.0" - -react-outside-click-handler@^1.2.4: - version "1.3.0" - resolved "https://registry.npmjs.org/react-outside-click-handler/-/react-outside-click-handler-1.3.0.tgz" - integrity sha512-Te/7zFU0oHpAnctl//pP3hEAeobfeHMyygHB8MnjP6sX5OR8KHT1G3jmLsV3U9RnIYo+Yn+peJYWu+D5tUS8qQ== - dependencies: - airbnb-prop-types "^2.15.0" - consolidated-events "^1.1.1 || ^2.0.0" - document.contains "^1.0.1" - object.values "^1.1.0" - prop-types "^15.7.2" - -react-overlays@^5.1.2: - version "5.2.1" - resolved "https://registry.yarnpkg.com/react-overlays/-/react-overlays-5.2.1.tgz#49dc007321adb6784e1f212403f0fb37a74ab86b" - integrity sha512-GLLSOLWr21CqtJn8geSwQfoJufdt3mfdsnIiQswouuQ2MMPns+ihZklxvsTDKD3cR2tF8ELbi5xUsvqVhR6WvA== - dependencies: - "@babel/runtime" "^7.13.8" - "@popperjs/core" "^2.11.6" - "@restart/hooks" "^0.4.7" - "@types/warning" "^3.0.0" - dom-helpers "^5.2.0" - prop-types "^15.7.2" - uncontrollable "^7.2.1" - warning "^4.0.3" - -react-player-controls@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/react-player-controls/-/react-player-controls-1.1.0.tgz" - integrity sha512-qEsKtljmaQD7satvlG6maTOMVw/ekP4F+Obe8ahTkwJEfO+NdollbFlFFsIFro+btMawfydpgneXW0aKEXFy9A== - dependencies: - autobind-decorator "^2.4.0" - prop-types "^15.6.2" - -react-popper@^1.3.6: - version "1.3.7" - resolved "https://registry.npmjs.org/react-popper/-/react-popper-1.3.7.tgz" - integrity sha512-nmqYTx7QVjCm3WUZLeuOomna138R1luC4EqkW3hxJUrAe+3eNz3oFCLYdnPwILfn0mX1Ew2c3wctrjlUMYYUww== - dependencies: - "@babel/runtime" "^7.1.2" - create-react-context "^0.3.0" - deep-equal "^1.1.1" - popper.js "^1.14.4" - prop-types "^15.6.1" - typed-styles "^0.0.7" - warning "^4.0.2" - -react-portal@^4.2.0: - version "4.2.1" - resolved "https://registry.npmjs.org/react-portal/-/react-portal-4.2.1.tgz" - integrity sha512-fE9kOBagwmTXZ3YGRYb4gcMy+kSA+yLO0xnPankjRlfBv4uCpFXqKPfkpsGQQR15wkZ9EssnvTOl1yMzbkxhPQ== - dependencies: - prop-types "^15.5.8" - -react-proptype-conditional-require@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/react-proptype-conditional-require/-/react-proptype-conditional-require-1.0.4.tgz" - integrity sha1-acLVdB5t9eCPIw82u8KUTuEiJVU= - -react-redux@^8.1.2: - version "8.1.2" - resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-8.1.2.tgz#9076bbc6b60f746659ad6d51cb05de9c5e1e9188" - integrity sha512-xJKYI189VwfsFc4CJvHqHlDrzyFTY/3vZACbE+rr/zQ34Xx1wQfB4OTOSeOSNrF6BDVe8OOdxIrAnMGXA3ggfw== - dependencies: - "@babel/runtime" "^7.12.1" - "@types/hoist-non-react-statics" "^3.3.1" - "@types/use-sync-external-store" "^0.0.3" - hoist-non-react-statics "^3.3.2" - react-is "^18.0.0" - use-sync-external-store "^1.0.0" - -react-refresh@^0.14.0: - version "0.14.0" - resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e" - integrity sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ== - -react-resize-aware@^3.0.0-beta.5: - version "3.1.0" - resolved "https://registry.npmjs.org/react-resize-aware/-/react-resize-aware-3.1.0.tgz" - integrity sha512-bIhHlxVTX7xKUz14ksXMEHjzCZPTpQZKZISY3nbTD273pDKPABGFNFBP6Tr42KECxzC5YQiKpMchjTVJCqaxpA== - -react-resize-detector@^7.1.2: - version "7.1.2" - resolved "https://registry.npmjs.org/react-resize-detector/-/react-resize-detector-7.1.2.tgz" - integrity sha512-zXnPJ2m8+6oq9Nn8zsep/orts9vQv3elrpA+R8XTcW7DVVUJ9vwDwMXaBtykAYjMnkCIaOoK9vObyR7ZgFNlOw== - dependencies: - lodash "^4.17.21" - -react-select@^5.7.4: - version "5.7.4" - resolved "https://registry.yarnpkg.com/react-select/-/react-select-5.7.4.tgz#d8cad96e7bc9d6c8e2709bdda8f4363c5dd7ea7d" - integrity sha512-NhuE56X+p9QDFh4BgeygHFIvJJszO1i1KSkg/JPcIJrbovyRtI+GuOEa4XzFCEpZRAEoEI8u/cAHK+jG/PgUzQ== - dependencies: - "@babel/runtime" "^7.12.0" - "@emotion/cache" "^11.4.0" - "@emotion/react" "^11.8.1" - "@floating-ui/dom" "^1.0.1" - "@types/react-transition-group" "^4.4.0" - memoize-one "^6.0.0" - prop-types "^15.6.0" - react-transition-group "^4.3.0" - use-isomorphic-layout-effect "^1.1.2" - -react-slack-feedback@^2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/react-slack-feedback/-/react-slack-feedback-2.1.1.tgz" - integrity sha512-I+AUaDNnTOYpyGlZgiFDt3oNATZOesAdOwh9aCJq9Sfl+EZhjuPoJ0vgIVeNBLDPXrzWfmv3a7bkXdWHqYkCYw== - dependencies: - classnames "^2.2.5" - deepmerge "^3.2.0" - -react-smooth@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/react-smooth/-/react-smooth-2.0.1.tgz" - integrity sha512-Own9TA0GPPf3as4vSwFhDouVfXP15ie/wIHklhyKBH5AN6NFtdk0UpHBnonV11BtqDkAWlt40MOUc+5srmW7NA== - dependencies: - fast-equals "^2.0.0" - react-transition-group "2.9.0" - -react-split@^2.0.14: - version "2.0.14" - resolved "https://registry.yarnpkg.com/react-split/-/react-split-2.0.14.tgz#ef198259bf43264d605f792fb3384f15f5b34432" - integrity sha512-bKWydgMgaKTg/2JGQnaJPg51T6dmumTWZppFgEbbY0Fbme0F5TuatAScCLaqommbGQQf/ZT1zaejuPDriscISA== - dependencies: - prop-types "^15.5.7" - split.js "^1.6.0" - -react-stay-scrolled@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/react-stay-scrolled/-/react-stay-scrolled-9.0.0.tgz#015394b0888553b6fc1293b096b13f781134ee51" - integrity sha512-CvrxDtHoUG8xevBkj8cYParmjFSr5v3xPBlMKHK/4zZgCoRKMoVDyxR1xXRxg0XRtfb8dxbUAir2ErDoMTZc4g== - dependencies: - memoize-one "^6.0.0" - tiny-invariant "^1.3.3" - -react-toastify@^5.5.0: - version "5.5.0" - resolved "https://registry.npmjs.org/react-toastify/-/react-toastify-5.5.0.tgz" - integrity sha512-jsVme7jALIFGRyQsri/g4YTsRuaaGI70T6/ikjwZMB4mwTZaCWqj5NqxhGrRStKlJc5npXKKvKeqTiRGQl78LQ== - dependencies: - "@babel/runtime" "^7.4.2" - classnames "^2.2.6" - prop-types "^15.7.2" - react-transition-group "^4" - -react-toastify@^6.1.0: - version "6.1.0" - resolved "https://registry.npmjs.org/react-toastify/-/react-toastify-6.1.0.tgz" - integrity sha512-Ne+wIoO9A+jZlaqGqgeuXDC/DQfqTuJdyoc7G5SsuCHsr8mNRx7W26417YKtHRH0LcnFFd5ii76tGnmm0cMlLg== - dependencies: - clsx "^1.1.1" - prop-types "^15.7.2" - react-transition-group "^4.4.1" - -react-transition-group@2.9.0: - version "2.9.0" - resolved "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz" - integrity sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg== - dependencies: - dom-helpers "^3.4.0" - loose-envify "^1.4.0" - prop-types "^15.6.2" - react-lifecycles-compat "^3.0.4" - -react-transition-group@^4, react-transition-group@^4.3.0, react-transition-group@^4.4.1: - version "4.4.1" - resolved "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz" - integrity sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw== - dependencies: - "@babel/runtime" "^7.5.5" - dom-helpers "^5.0.1" - loose-envify "^1.4.0" - prop-types "^15.6.2" - -react-virtualized@^9.20.1: - version "9.22.3" - resolved "https://registry.npmjs.org/react-virtualized/-/react-virtualized-9.22.3.tgz" - integrity sha512-MKovKMxWTcwPSxE1kK1HcheQTWfuCxAuBoSTf2gwyMM21NdX/PXUhnoP8Uc5dRKd+nKm8v41R36OellhdCpkrw== - dependencies: - "@babel/runtime" "^7.7.2" - clsx "^1.0.4" - dom-helpers "^5.1.3" - loose-envify "^1.4.0" - prop-types "^15.7.2" - react-lifecycles-compat "^3.0.4" - -react-with-direction@^1.3.1: - version "1.3.1" - resolved "https://registry.npmjs.org/react-with-direction/-/react-with-direction-1.3.1.tgz" - integrity sha512-aGcM21ZzhqeXFvDCfPj0rVNYuaVXfTz5D3Rbn0QMz/unZe+CCiLHthrjQWO7s6qdfXORgYFtmS7OVsRgSk5LXQ== - dependencies: - airbnb-prop-types "^2.10.0" - brcast "^2.0.2" - deepmerge "^1.5.2" - direction "^1.0.2" - hoist-non-react-statics "^3.3.0" - object.assign "^4.1.0" - object.values "^1.0.4" - prop-types "^15.6.2" - -react-with-styles-interface-css@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/react-with-styles-interface-css/-/react-with-styles-interface-css-6.0.0.tgz" - integrity sha512-6khSG1Trf4L/uXOge/ZAlBnq2O2PEXlQEqAhCRbvzaQU4sksIkdwpCPEl6d+DtP3+IdhyffTWuHDO9lhe1iYvA== - dependencies: - array.prototype.flat "^1.2.1" - global-cache "^1.2.1" - -react-with-styles@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/react-with-styles/-/react-with-styles-4.1.0.tgz" - integrity sha512-zp05fyA6XFetqr07ox/a0bCFyEj//gUozI9cC1GW59zaGJ38STnxYvzotutgpzMyHOd7TFW9ZiZeBKjsYaS+RQ== - dependencies: - airbnb-prop-types "^2.14.0" - hoist-non-react-statics "^3.2.1" - object.assign "^4.1.0" - prop-types "^15.7.2" - react-with-direction "^1.3.1" - -"react@15.x.x - 16.x.x": - version "16.13.1" - resolved "https://registry.npmjs.org/react/-/react-16.13.1.tgz" - integrity sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - prop-types "^15.6.2" - -react@^17.0.2: - version "17.0.2" - resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" - integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - -react@^18.2.0: - version "18.2.0" - resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" - integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ== - dependencies: - loose-envify "^1.1.0" - -read-pkg-up@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz" - integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4= - dependencies: - find-up "^2.0.0" - read-pkg "^2.0.0" - -read-pkg-up@^7.0.1: - version "7.0.1" - resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz" - integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== - dependencies: - find-up "^4.1.0" - read-pkg "^5.2.0" - type-fest "^0.8.1" - -read-pkg@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz" - integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= - dependencies: - load-json-file "^2.0.0" - normalize-package-data "^2.3.2" - path-type "^2.0.0" - -read-pkg@^5.2.0: - version "5.2.0" - resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz" - integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg== - dependencies: - "@types/normalize-package-data" "^2.4.0" - normalize-package-data "^2.5.0" - parse-json "^5.0.0" - type-fest "^0.6.0" - -readable-stream@^2.0.0, readable-stream@^2.3.0, readable-stream@^2.3.5: - version "2.3.7" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz" - integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - -readable-stream@^2.0.1: - version "2.3.8" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" - integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - -readable-stream@^3.0.6: - version "3.6.2" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" - integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - -readdirp@~3.5.0: - version "3.5.0" - resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz" - integrity sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ== - dependencies: - picomatch "^2.2.1" - -readdirp@~3.6.0: - version "3.6.0" - resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz" - integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== - dependencies: - picomatch "^2.2.1" - -recharts-scale@^0.4.4: - version "0.4.5" - resolved "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz" - integrity sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w== - dependencies: - decimal.js-light "^2.4.1" - -recharts@^2.1.16: - version "2.1.16" - resolved "https://registry.npmjs.org/recharts/-/recharts-2.1.16.tgz" - integrity sha512-aYn1plTjYzRCo3UGxtWsduslwYd+Cuww3h/YAAEoRdGe0LRnBgYgaXSlVrNFkWOOSXrBavpmnli9h7pvRuk5wg== - dependencies: - "@types/d3-interpolate" "^2.0.0" - "@types/d3-scale" "^3.0.0" - "@types/d3-shape" "^2.0.0" - classnames "^2.2.5" - d3-interpolate "^2.0.0" - d3-scale "^3.0.0" - d3-shape "^2.0.0" - eventemitter3 "^4.0.1" - lodash "^4.17.19" - react-is "^16.10.2" - react-resize-detector "^7.1.2" - react-smooth "^2.0.1" - recharts-scale "^0.4.4" - reduce-css-calc "^2.1.8" - -rechoir@^0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.8.0.tgz#49f866e0d32146142da3ad8f0eff352b3215ff22" - integrity sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ== - dependencies: - resolve "^1.20.0" - -redent@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz" - integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg== - dependencies: - indent-string "^4.0.0" - strip-indent "^3.0.0" - -reduce-css-calc@^2.1.8: - version "2.1.8" - resolved "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz" - integrity sha512-8liAVezDmUcH+tdzoEGrhfbGcP7nOV4NkGE3a74+qqvE7nt9i4sKLGBuZNOnpI4WiGksiNPklZxva80061QiPg== - dependencies: - css-unit-converter "^1.1.1" - postcss-value-parser "^3.3.0" - -redux-persist@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/redux-persist/-/redux-persist-6.0.0.tgz" - integrity sha512-71LLMbUq2r02ng2We9S215LtPu3fY0KgaGE0k8WRgl6RkqxtGfl7HUozz1Dftwsb0D/5mZ8dwAaPbtnzfvbEwQ== - -redux-thunk@^2.3.0: - version "2.3.0" - resolved "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.3.0.tgz" - integrity sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw== - -redux@^4.1.0: - version "4.1.2" - resolved "https://registry.npmjs.org/redux/-/redux-4.1.2.tgz" - integrity sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw== - dependencies: - "@babel/runtime" "^7.9.2" - -reflect.ownkeys@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/reflect.ownkeys/-/reflect.ownkeys-0.2.0.tgz" - integrity sha1-dJrO7H8/34tj+SegSAnpDFwLNGA= - -regenerate-unicode-properties@^10.1.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz#7c3192cab6dd24e21cb4461e5ddd7dd24fa8374c" - integrity sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ== - dependencies: - regenerate "^1.4.2" - -regenerate-unicode-properties@^8.2.0: - version "8.2.0" - resolved "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz" - integrity sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA== - dependencies: - regenerate "^1.4.0" - -regenerate@^1.4.0: - version "1.4.1" - resolved "https://registry.npmjs.org/regenerate/-/regenerate-1.4.1.tgz" - integrity sha512-j2+C8+NtXQgEKWk49MMP5P/u2GhnahTtVkRIHr5R5lVRlbKvmQ+oS+A5aLKWp2ma5VkT8sh6v+v4hbH0YHR66A== - -regenerate@^1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" - integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== - -regenerator-runtime@^0.13.11: - version "0.13.11" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" - integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== - -regenerator-runtime@^0.13.4: - version "0.13.7" - resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz" - integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew== - -regenerator-runtime@^0.14.0: - version "0.14.0" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz#5e19d68eb12d486f797e15a3c6a918f7cec5eb45" - integrity sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA== - -regenerator-transform@^0.15.1: - version "0.15.1" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.1.tgz#f6c4e99fc1b4591f780db2586328e4d9a9d8dc56" - integrity sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg== - dependencies: - "@babel/runtime" "^7.8.4" - -regex-not@^1.0.0, regex-not@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz" - integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== - dependencies: - extend-shallow "^3.0.2" - safe-regex "^1.1.0" - -regex-parser@^2.2.11: - version "2.2.11" - resolved "https://registry.yarnpkg.com/regex-parser/-/regex-parser-2.2.11.tgz#3b37ec9049e19479806e878cabe7c1ca83ccfe58" - integrity sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q== - -regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz" - integrity sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" - -regexp.prototype.flags@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz#fe7ce25e7e4cca8db37b6634c8a2c7009199b9cb" - integrity sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - functions-have-names "^1.2.3" - -regexpp@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz" - integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q== - -regexpu-core@^4.7.0: - version "4.7.0" - resolved "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.0.tgz" - integrity sha512-TQ4KXRnIn6tz6tjnrXEkD/sshygKH/j5KzK86X8MkeHyZ8qst/LZ89j3X4/8HEIfHANTFIP/AbXakeRhWIl5YQ== - dependencies: - regenerate "^1.4.0" - regenerate-unicode-properties "^8.2.0" - regjsgen "^0.5.1" - regjsparser "^0.6.4" - unicode-match-property-ecmascript "^1.0.4" - unicode-match-property-value-ecmascript "^1.2.0" - -regexpu-core@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.3.1.tgz#66900860f88def39a5cb79ebd9490e84f17bcdfb" - integrity sha512-nCOzW2V/X15XpLsK2rlgdwrysrBq+AauCn+omItIz4R1pIcmeot5zvjdmOBRLzEH/CkC6IxMJVmxDe3QcMuNVQ== - dependencies: - "@babel/regjsgen" "^0.8.0" - regenerate "^1.4.2" - regenerate-unicode-properties "^10.1.0" - regjsparser "^0.9.1" - unicode-match-property-ecmascript "^2.0.0" - unicode-match-property-value-ecmascript "^2.1.0" - -regjsgen@^0.5.1: - version "0.5.2" - resolved "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz" - integrity sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A== - -regjsparser@^0.6.4: - version "0.6.4" - resolved "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.4.tgz" - integrity sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw== - dependencies: - jsesc "~0.5.0" - -regjsparser@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.9.1.tgz#272d05aa10c7c1f67095b1ff0addae8442fc5709" - integrity sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ== - dependencies: - jsesc "~0.5.0" - -rehype-katex@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/rehype-katex/-/rehype-katex-7.0.0.tgz#f5e9e2825981175a7b0a4d58ed9816c33576dfed" - integrity sha512-h8FPkGE00r2XKU+/acgqwWUlyzve1IiOKwsEkg4pDL3k48PiE0Pt+/uLtVHDVkN1yA4iurZN6UES8ivHVEQV6Q== - dependencies: - "@types/hast" "^3.0.0" - "@types/katex" "^0.16.0" - hast-util-from-html-isomorphic "^2.0.0" - hast-util-to-text "^4.0.0" - katex "^0.16.0" - unist-util-visit-parents "^6.0.0" - vfile "^6.0.0" - -remark-math@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/remark-math/-/remark-math-6.0.0.tgz#0acdf74675f1c195fea6efffa78582f7ed7fc0d7" - integrity sha512-MMqgnP74Igy+S3WwnhQ7kqGlEerTETXMvJhrUzDikVZ2/uogJCb+WHUg97hK9/jcfc0dkD73s3LN8zU49cTEtA== - dependencies: - "@types/mdast" "^4.0.0" - mdast-util-math "^3.0.0" - micromark-extension-math "^3.0.0" - unified "^11.0.0" - -remark-parse@^11.0.0: - version "11.0.0" - resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-11.0.0.tgz#aa60743fcb37ebf6b069204eb4da304e40db45a1" - integrity sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA== - dependencies: - "@types/mdast" "^4.0.0" - mdast-util-from-markdown "^2.0.0" - micromark-util-types "^2.0.0" - unified "^11.0.0" - -remark-rehype@^11.0.0: - version "11.1.0" - resolved "https://registry.yarnpkg.com/remark-rehype/-/remark-rehype-11.1.0.tgz#d5f264f42bcbd4d300f030975609d01a1697ccdc" - integrity sha512-z3tJrAs2kIs1AqIIy6pzHmAHlF1hWQ+OdY4/hv+Wxe35EhyLKcajL33iUEn3ScxtFox9nUvRufR/Zre8Q08H/g== - dependencies: - "@types/hast" "^3.0.0" - "@types/mdast" "^4.0.0" - mdast-util-to-hast "^13.0.0" - unified "^11.0.0" - vfile "^6.0.0" - -remove-trailing-separator@^1.0.1: - version "1.1.0" - resolved "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz" - integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= - -repeat-element@^1.1.2: - version "1.1.3" - resolved "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz" - integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== - -repeat-string@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - integrity sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w== - -replace-ext@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz" - integrity sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw== - -request-ip@~2.0.1: - version "2.0.2" - resolved "https://registry.npmjs.org/request-ip/-/request-ip-2.0.2.tgz" - integrity sha1-3urm1K8hdoSX24zQX6NxQ/jxJX4= - dependencies: - is_js "^0.9.0" - -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" - integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= - -require-from-string@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" - integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== - -require-main-filename@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz" - integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== - -require-package-name@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/require-package-name/-/require-package-name-2.0.1.tgz" - integrity sha1-wR6XJ2tluOKSP3Xav1+y7ww4Qbk= - -requires-port@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" - integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== - -reselect@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/reselect/-/reselect-4.0.0.tgz" - integrity sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA== - -resolve-cwd@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz" - integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== - dependencies: - resolve-from "^5.0.0" - -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - -resolve-from@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz" - integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== - -resolve-url-loader@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz#ee3142fb1f1e0d9db9524d539cfa166e9314f795" - integrity sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg== - dependencies: - adjust-sourcemap-loader "^4.0.0" - convert-source-map "^1.7.0" - loader-utils "^2.0.0" - postcss "^8.2.14" - source-map "0.6.1" - -resolve-url@^0.2.1: - version "0.2.1" - resolved "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz" - integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= - -resolve@^1.10.0, resolve@^1.13.1, resolve@^1.17.0, resolve@^1.3.2: - version "1.17.0" - resolved "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz" - integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== - dependencies: - path-parse "^1.0.6" - -resolve@^1.14.2, resolve@^1.20.0: - version "1.22.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" - integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== - dependencies: - is-core-module "^2.9.0" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - -resolve@^1.18.1: - version "1.19.0" - resolved "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz" - integrity sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg== - dependencies: - is-core-module "^2.1.0" - path-parse "^1.0.6" - -resolve@^1.19.0: - version "1.22.4" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.4.tgz#1dc40df46554cdaf8948a486a10f6ba1e2026c34" - integrity sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg== - dependencies: - is-core-module "^2.13.0" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - -responselike@1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz" - integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= - dependencies: - lowercase-keys "^1.0.0" - -ret@~0.1.10: - version "0.1.15" - resolved "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz" - integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== - -retry@^0.13.1: - version "0.13.1" - resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" - integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== - -reusify@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz" - integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== - -rimraf@2, rimraf@^2.5.4: - version "2.7.1" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz" - integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== - dependencies: - glob "^7.1.3" - -rimraf@2.6.3: - version "2.6.3" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== - dependencies: - glob "^7.1.3" - -rimraf@^3.0.0, rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - -rollbar-redux-middleware@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/rollbar-redux-middleware/-/rollbar-redux-middleware-0.2.0.tgz" - integrity sha1-qTDPxWQaeV6/oKJYzLrBAPymBxk= - -rollbar@^2.19.4: - version "2.19.4" - resolved "https://registry.npmjs.org/rollbar/-/rollbar-2.19.4.tgz" - integrity sha512-8ErcMfJE2zkhgrFtpGRyejHBhyO0hU7dZ3EvG2ylNZ7qSu4yw5PZfhGx+Qyq3ksKshLFeQh9Y/Bh2S1TOPIhvw== - dependencies: - async "~1.2.1" - console-polyfill "0.3.0" - error-stack-parser "^2.0.4" - json-stringify-safe "~5.0.0" - lru-cache "~2.2.1" - request-ip "~2.0.1" - source-map "^0.5.7" - uuid "3.0.x" - optionalDependencies: - decache "^3.0.5" - -rsvp@^4.8.4: - version "4.8.5" - resolved "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz" - integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== - -run-parallel@^1.1.9: - version "1.1.9" - resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz" - integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q== - -safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@~5.2.0: - version "5.2.1" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -safe-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz" - integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= - dependencies: - ret "~0.1.10" - -"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": - version "2.1.2" - resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -sane@^4.0.3: - version "4.1.0" - resolved "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz" - integrity sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA== - dependencies: - "@cnakazawa/watch" "^1.0.3" - anymatch "^2.0.0" - capture-exit "^2.0.0" - exec-sh "^0.3.2" - execa "^1.0.0" - fb-watchman "^2.0.0" - micromatch "^3.1.4" - minimist "^1.1.1" - walker "~1.0.5" - -sass-loader@^13.3.2: - version "13.3.2" - resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-13.3.2.tgz#460022de27aec772480f03de17f5ba88fa7e18c6" - integrity sha512-CQbKl57kdEv+KDLquhC+gE3pXt74LEAzm+tzywcA0/aHZuub8wTErbjAoNI57rPUWRYRNC5WUnNl8eGJNbDdwg== - dependencies: - neo-async "^2.6.2" - -sass@^1.44.0: - version "1.44.0" - resolved "https://registry.npmjs.org/sass/-/sass-1.44.0.tgz" - integrity sha512-0hLREbHFXGQqls/K8X+koeP+ogFRPF4ZqetVB19b7Cst9Er8cOR0rc6RU7MaI4W1JmUShd1BPgPoeqmmgMMYFw== - dependencies: - chokidar ">=3.0.0 <4.0.0" - immutable "^4.0.0" - -saxes@^5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz" - integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== - dependencies: - xmlchars "^2.2.0" - -scheduler@^0.23.0: - version "0.23.0" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe" - integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw== - dependencies: - loose-envify "^1.1.0" - -schema-utils@^2.7.1: - version "2.7.1" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.1.tgz#1ca4f32d1b24c590c203b8e7a50bf0ea4cd394d7" - integrity sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg== - dependencies: - "@types/json-schema" "^7.0.5" - ajv "^6.12.4" - ajv-keywords "^3.5.2" - -schema-utils@^3.0.0, schema-utils@^3.1.1, schema-utils@^3.2.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe" - integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg== - dependencies: - "@types/json-schema" "^7.0.8" - ajv "^6.12.5" - ajv-keywords "^3.5.2" - -schema-utils@^4.0.0, schema-utils@^4.0.1: - version "4.2.0" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.2.0.tgz#70d7c93e153a273a805801882ebd3bff20d89c8b" - integrity sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw== - dependencies: - "@types/json-schema" "^7.0.9" - ajv "^8.9.0" - ajv-formats "^2.1.1" - ajv-keywords "^5.1.0" - -scroll@^3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/scroll/-/scroll-3.0.1.tgz" - integrity sha512-pz7y517OVls1maEzlirKO5nPYle9AXsFzTMNJrRGmT951mzpIBy7sNHOg5o/0MQd/NqliCiWnAi0kZneMPFLcg== - -scrollparent@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/scrollparent/-/scrollparent-2.1.0.tgz#6cae915c953835886a6ba0d77fdc2bb1ed09076d" - integrity sha512-bnnvJL28/Rtz/kz2+4wpBjHzWoEzXhVg/TE8BeVGJHUqE8THNIRnDxDWMktwM+qahvlRdvlLdsQfYe+cuqfZeA== - -seek-bzip@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.5.tgz" - integrity sha1-z+kXyz0nS8/6x5J1ivUxc+sfq9w= - dependencies: - commander "~2.8.1" - -select-hose@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" - integrity sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg== - -selfsigned@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-2.1.1.tgz#18a7613d714c0cd3385c48af0075abf3f266af61" - integrity sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ== - dependencies: - node-forge "^1" - -semver-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/semver-regex/-/semver-regex-2.0.0.tgz" - integrity sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw== - -semver-truncate@^1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/semver-truncate/-/semver-truncate-1.1.2.tgz" - integrity sha1-V/Qd5pcHpicJp+AQS6IRcQnqR+g= - dependencies: - semver "^5.3.0" - -"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0: - version "5.7.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" - integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== - -semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0, semver@^6.3.1: - version "6.3.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" - integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== - -semver@^7.2.1, semver@^7.3.2, semver@^7.3.8: - version "7.5.4" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" - integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== - dependencies: - lru-cache "^6.0.0" - -send@0.19.0: - version "0.19.0" - resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8" - integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw== - dependencies: - debug "2.6.9" - depd "2.0.0" - destroy "1.2.0" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - fresh "0.5.2" - http-errors "2.0.0" - mime "1.6.0" - ms "2.1.3" - on-finished "2.4.1" - range-parser "~1.2.1" - statuses "2.0.1" - -serialize-javascript@^6.0.0, serialize-javascript@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.1.tgz#b206efb27c3da0b0ab6b52f48d170b7996458e5c" - integrity sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w== - dependencies: - randombytes "^2.1.0" - -serve-index@^1.9.1: - version "1.9.1" - resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" - integrity sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw== - dependencies: - accepts "~1.3.4" - batch "0.6.1" - debug "2.6.9" - escape-html "~1.0.3" - http-errors "~1.6.2" - mime-types "~2.1.17" - parseurl "~1.3.2" - -serve-static@1.16.2: - version "1.16.2" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.2.tgz#b6a5343da47f6bdd2673848bf45754941e803296" - integrity sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw== - dependencies: - encodeurl "~2.0.0" - escape-html "~1.0.3" - parseurl "~1.3.3" - send "0.19.0" - -set-blocking@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz" - integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= - -set-function-length@^1.2.1: - version "1.2.2" - resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" - integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== - dependencies: - define-data-property "^1.1.4" - es-errors "^1.3.0" - function-bind "^1.1.2" - get-intrinsic "^1.2.4" - gopd "^1.0.1" - has-property-descriptors "^1.0.2" - -set-value@^2.0.0, set-value@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz" - integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== - dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.3" - split-string "^3.0.1" - -set-value@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/set-value/-/set-value-4.0.1.tgz" - integrity sha512-ayATicCYPVnlNpFmjq2/VmVwhoCQA9+13j8qWp044fmFE3IFphosPtRM+0CJ5xoIx5Uy52fCcwg3XeH2pHbbPQ== - dependencies: - is-plain-object "^2.0.4" - -setprototypeof@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" - integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== - -setprototypeof@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" - integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== - -shallow-clone@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz" - integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== - dependencies: - kind-of "^6.0.2" - -shallowequal@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz" - integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ== - -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz" - integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= - dependencies: - shebang-regex "^1.0.0" - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz" - integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -shell-quote@^1.7.3: - version "1.8.1" - resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680" - integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA== - -shellwords@^0.1.1: - version "0.1.1" - resolved "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz" - integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== - -side-channel@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.0.2.tgz" - integrity sha512-7rL9YlPHg7Ancea1S96Pa8/QWb4BtXL/TZvS6B8XFetGBeuhAsfmUspK6DokBeZ64+Kj9TCNRD/30pVz1BvQNA== - dependencies: - es-abstract "^1.17.0-next.1" - object-inspect "^1.7.0" - -side-channel@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" - integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== - dependencies: - call-bind "^1.0.0" - get-intrinsic "^1.0.2" - object-inspect "^1.9.0" - -side-channel@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" - integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== - dependencies: - call-bind "^1.0.7" - es-errors "^1.3.0" - get-intrinsic "^1.2.4" - object-inspect "^1.13.1" - -signal-exit@^3.0.0, signal-exit@^3.0.2: - version "3.0.3" - resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz" - integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== - -signal-exit@^3.0.3, signal-exit@^3.0.7: - version "3.0.7" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" - integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== - -sirv@^1.0.7: - version "1.0.19" - resolved "https://registry.yarnpkg.com/sirv/-/sirv-1.0.19.tgz#1d73979b38c7fe91fcba49c85280daa9c2363b49" - integrity sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ== - dependencies: - "@polka/url" "^1.0.0-next.20" - mrmime "^1.0.0" - totalist "^1.0.0" - -sisteransi@^1.0.4: - version "1.0.5" - resolved "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz" - integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== - -slash@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz" - integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== - -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== - -slash@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-4.0.0.tgz#2422372176c4c6c5addb5e2ada885af984b396a7" - integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew== - -slice-ansi@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz" - integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== - dependencies: - ansi-styles "^3.2.0" - astral-regex "^1.0.0" - is-fullwidth-code-point "^2.0.0" - -snapdragon-node@^2.0.1: - version "2.1.1" - resolved "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz" - integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== - dependencies: - define-property "^1.0.0" - isobject "^3.0.0" - snapdragon-util "^3.0.1" - -snapdragon-util@^3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz" - integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== - dependencies: - kind-of "^3.2.0" - -snapdragon@^0.8.1: - version "0.8.2" - resolved "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz" - integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== - dependencies: - base "^0.11.1" - debug "^2.2.0" - define-property "^0.2.5" - extend-shallow "^2.0.1" - map-cache "^0.2.2" - source-map "^0.5.6" - source-map-resolve "^0.5.0" - use "^3.1.0" - -sockjs@^0.3.24: - version "0.3.24" - resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.24.tgz#c9bc8995f33a111bea0395ec30aa3206bdb5ccce" - integrity sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ== - dependencies: - faye-websocket "^0.11.3" - uuid "^8.3.2" - websocket-driver "^0.7.4" - -sort-keys-length@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz" - integrity sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg= - dependencies: - sort-keys "^1.0.0" - -sort-keys@^1.0.0: - version "1.1.2" - resolved "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz" - integrity sha1-RBttTTRnmPG05J6JIK37oOVD+a0= - dependencies: - is-plain-obj "^1.0.0" - -sort-keys@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz" - integrity sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg= - dependencies: - is-plain-obj "^1.0.0" - -source-map-js@^1.0.1, source-map-js@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" - integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== - -source-map-resolve@^0.5.0: - version "0.5.3" - resolved "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz" - integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== - dependencies: - atob "^2.1.2" - decode-uri-component "^0.2.0" - resolve-url "^0.2.1" - source-map-url "^0.4.0" - urix "^0.1.0" - -source-map-support@^0.5.6, source-map-support@~0.5.20: - version "0.5.21" - resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz" - integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map-url@^0.4.0: - version "0.4.0" - resolved "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz" - integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= - -source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: - version "0.6.1" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7: - version "0.5.7" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= - -source-map@^0.7.3: - version "0.7.3" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz" - integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== - -space-separated-tokens@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz#1ecd9d2350a3844572c3f4a312bceb018348859f" - integrity sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q== - -spdx-correct@^3.0.0: - version "3.1.1" - resolved "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz" - integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w== - dependencies: - spdx-expression-parse "^3.0.0" - spdx-license-ids "^3.0.0" - -spdx-exceptions@^2.1.0: - version "2.3.0" - resolved "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz" - integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== - -spdx-expression-parse@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz" - integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== - dependencies: - spdx-exceptions "^2.1.0" - spdx-license-ids "^3.0.0" - -spdx-license-ids@^3.0.0: - version "3.0.5" - resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz" - integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q== - -spdy-transport@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" - integrity sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw== - dependencies: - debug "^4.1.0" - detect-node "^2.0.4" - hpack.js "^2.1.6" - obuf "^1.1.2" - readable-stream "^3.0.6" - wbuf "^1.7.3" - -spdy@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.2.tgz#b74f466203a3eda452c02492b91fb9e84a27677b" - integrity sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA== - dependencies: - debug "^4.1.0" - handle-thing "^2.0.0" - http-deceiver "^1.2.7" - select-hose "^2.0.0" - spdy-transport "^3.0.0" - -split-string@^3.0.1, split-string@^3.0.2: - version "3.1.0" - resolved "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz" - integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== - dependencies: - extend-shallow "^3.0.0" - -split.js@^1.6.0: - version "1.6.5" - resolved "https://registry.yarnpkg.com/split.js/-/split.js-1.6.5.tgz#f7f61da1044c9984cb42947df4de4fadb5a3f300" - integrity sha512-mPTnGCiS/RiuTNsVhCm9De9cCAUsrNFFviRbADdKiiV+Kk8HKp/0fWu7Kr8pi3/yBmsqLFHuXGT9UUZ+CNLwFw== - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - -stable@^0.1.8: - version "0.1.8" - resolved "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz" - integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== - -stack-utils@^2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.2.tgz" - integrity sha512-0H7QK2ECz3fyZMzQ8rH0j2ykpfbnd20BFtfg/SqVC2+sCTtcw0aDTGB7dk+de4U4uUeuz6nOtJcrkFFLG1B0Rg== - dependencies: - escape-string-regexp "^2.0.0" - -stackframe@^1.1.1: - version "1.2.0" - resolved "https://registry.npmjs.org/stackframe/-/stackframe-1.2.0.tgz" - integrity sha512-GrdeshiRmS1YLMYgzF16olf2jJ/IzxXY9lhKOskuVziubpTYcYqyOwYeJKzQkwy7uN0fYSsbsC4RQaXf9LCrYA== - -stackframe@^1.3.4: - version "1.3.4" - resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.3.4.tgz#b881a004c8c149a5e8efef37d51b16e412943310" - integrity sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw== - -state-local@^1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/state-local/-/state-local-1.0.7.tgz#da50211d07f05748d53009bee46307a37db386d5" - integrity sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w== - -static-extend@^0.1.1: - version "0.1.2" - resolved "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz" - integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= - dependencies: - define-property "^0.2.5" - object-copy "^0.1.0" - -statuses@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" - integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== - -"statuses@>= 1.4.0 < 2": - version "1.5.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" - integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== - -stop-iteration-iterator@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz#6a60be0b4ee757d1ed5254858ec66b10c49285e4" - integrity sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ== - dependencies: - internal-slot "^1.0.4" - -strict-uri-encode@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz" - integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM= - -string-length@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/string-length/-/string-length-4.0.1.tgz" - integrity sha512-PKyXUd0LK0ePjSOnWn34V2uD6acUWev9uy0Ft05k0E8xRW+SKcA0F7eMr7h5xlzfn+4O3N+55rduYyet3Jk+jw== - dependencies: - char-regex "^1.0.2" - strip-ansi "^6.0.0" - -string-width@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz" - integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== - dependencies: - emoji-regex "^7.0.1" - is-fullwidth-code-point "^2.0.0" - strip-ansi "^5.1.0" - -string-width@^4.1.0, string-width@^4.2.0: - version "4.2.0" - resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz" - integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.0" - -string.prototype.matchall@^4.0.2: - version "4.0.2" - resolved "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.2.tgz" - integrity sha512-N/jp6O5fMf9os0JU3E72Qhf590RSRZU/ungsL/qJUYVTNv7hTG0P/dbPjxINVN9jpscu3nzYwKESU3P3RY5tOg== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.0" - has-symbols "^1.0.1" - internal-slot "^1.0.2" - regexp.prototype.flags "^1.3.0" - side-channel "^1.0.2" - -string.prototype.trimend@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz" - integrity sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.5" - -string.prototype.trimstart@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz" - integrity sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.5" - -string_decoder@^1.1.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - dependencies: - safe-buffer "~5.2.0" - -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - -stringify-entities@^4.0.0: - version "4.0.4" - resolved "https://registry.yarnpkg.com/stringify-entities/-/stringify-entities-4.0.4.tgz#b3b79ef5f277cc4ac73caeb0236c5ba939b3a4f3" - integrity sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg== - dependencies: - character-entities-html4 "^2.0.0" - character-entities-legacy "^3.0.0" - -strip-ansi@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz" - integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= - dependencies: - ansi-regex "^2.0.0" - -strip-ansi@^5.1.0: - version "5.2.0" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz" - integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== - dependencies: - ansi-regex "^4.1.0" - -strip-ansi@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz" - integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== - dependencies: - ansi-regex "^5.0.0" - -strip-bom@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz" - integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= - -strip-bom@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz" - integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== - -strip-dirs@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz" - integrity sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g== - dependencies: - is-natural-number "^4.0.1" - -strip-eof@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz" - integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= - -strip-final-newline@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz" - integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== - -strip-indent@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz" - integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== - dependencies: - min-indent "^1.0.0" - -strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: - 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== - -strip-outer@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz" - integrity sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg== - dependencies: - escape-string-regexp "^1.0.2" - -strnum@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/strnum/-/strnum-1.0.5.tgz#5c4e829fe15ad4ff0d20c3db5ac97b73c9b072db" - integrity sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA== - -style-to-object@^1.0.0: - version "1.0.6" - resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-1.0.6.tgz#0c28aed8be1813d166c60d962719b2907c26547b" - integrity sha512-khxq+Qm3xEyZfKd/y9L3oIWQimxuc4STrQKtQn8aSDRHb8mFgpukgX1hdzfrMEW6JCjyJ8p89x+IUMVnCBI1PA== - dependencies: - inline-style-parser "0.2.3" - -styled-components@^5.0.0-beta.8, styled-components@^5.2.1: - version "5.2.1" - resolved "https://registry.npmjs.org/styled-components/-/styled-components-5.2.1.tgz" - integrity sha512-sBdgLWrCFTKtmZm/9x7jkIabjFNVzCUeKfoQsM6R3saImkUnjx0QYdLwJHBjY9ifEcmjDamJDVfknWm1yxZPxQ== - dependencies: - "@babel/helper-module-imports" "^7.0.0" - "@babel/traverse" "^7.4.5" - "@emotion/is-prop-valid" "^0.8.8" - "@emotion/stylis" "^0.8.4" - "@emotion/unitless" "^0.7.4" - babel-plugin-styled-components ">= 1" - css-to-react-native "^3.0.0" - hoist-non-react-statics "^3.0.0" - shallowequal "^1.1.0" - supports-color "^5.5.0" - -stylehacks@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-6.0.0.tgz#9fdd7c217660dae0f62e14d51c89f6c01b3cb738" - integrity sha512-+UT589qhHPwz6mTlCLSt/vMNTJx8dopeJlZAlBMJPWA3ORqu6wmQY7FBXf+qD+FsqoBJODyqNxOUP3jdntFRdw== - dependencies: - browserslist "^4.21.4" - postcss-selector-parser "^6.0.4" - -stylis@4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.2.0.tgz#79daee0208964c8fe695a42fcffcac633a211a51" - integrity sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw== - -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz" - integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= - -supports-color@^5.3.0, supports-color@^5.5.0: - version "5.5.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -supports-color@^7.0.0, supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -supports-color@^8.0.0: - version "8.1.1" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" - integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== - dependencies: - has-flag "^4.0.0" - -supports-hyperlinks@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz" - integrity sha512-zoE5/e+dnEijk6ASB6/qrK+oYdm2do1hjoLWrqUC/8WEIW1gbxFcKuBof7sW8ArN6e+AYvsE8HBGiVRWL/F5CA== - dependencies: - has-flag "^4.0.0" - supports-color "^7.0.0" - -supports-preserve-symlinks-flag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" - integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== - -svg-tags@1: - version "1.0.0" - resolved "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz" - integrity sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q= - -svgo@^2.1.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24" - integrity sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg== - dependencies: - "@trysound/sax" "0.2.0" - commander "^7.2.0" - css-select "^4.1.3" - css-tree "^1.1.3" - csso "^4.2.0" - picocolors "^1.0.0" - stable "^0.1.8" - -svgo@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/svgo/-/svgo-3.0.2.tgz#5e99eeea42c68ee0dc46aa16da093838c262fe0a" - integrity sha512-Z706C1U2pb1+JGP48fbazf3KxHrWOsLme6Rv7imFBn5EnuanDW1GPaA/P1/dvObE670JDePC3mnj0k0B7P0jjQ== - dependencies: - "@trysound/sax" "0.2.0" - commander "^7.2.0" - css-select "^5.1.0" - css-tree "^2.2.1" - csso "^5.0.5" - picocolors "^1.0.0" - -symbol-tree@^3.2.4: - version "3.2.4" - resolved "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz" - integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== - -synchronous-promise@^2.0.13: - version "2.0.15" - resolved "https://registry.npmjs.org/synchronous-promise/-/synchronous-promise-2.0.15.tgz" - integrity sha512-k8uzYIkIVwmT+TcglpdN50pS2y1BDcUnBPK9iJeGu0Pl1lOI8pD6wtzgw91Pjpe+RxtTncw32tLxs/R0yNL2Mg== - -table@^5.2.3: - version "5.4.6" - resolved "https://registry.npmjs.org/table/-/table-5.4.6.tgz" - integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== - dependencies: - ajv "^6.10.2" - lodash "^4.17.14" - slice-ansi "^2.1.0" - string-width "^3.0.0" - -tapable@^2.1.1, tapable@^2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" - integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== - -tar-stream@^1.5.2: - version "1.6.2" - resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz" - integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A== - dependencies: - bl "^1.0.0" - buffer-alloc "^1.2.0" - end-of-stream "^1.0.0" - fs-constants "^1.0.0" - readable-stream "^2.3.0" - to-buffer "^1.1.1" - xtend "^4.0.0" - -tar@2.2.2: - version "2.2.2" - resolved "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz" - integrity sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA== - dependencies: - block-stream "*" - fstream "^1.0.12" - inherits "2" - -temp-dir@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz" - integrity sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0= - -tempfile@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/tempfile/-/tempfile-2.0.0.tgz" - integrity sha1-awRGhWqbERTRhW/8vlCczLCXcmU= - dependencies: - temp-dir "^1.0.0" - uuid "^3.0.1" - -terminal-link@^2.0.0: - version "2.1.1" - resolved "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz" - integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== - dependencies: - ansi-escapes "^4.2.1" - supports-hyperlinks "^2.0.0" - -terser-webpack-plugin@^5.3.10, terser-webpack-plugin@^5.3.9: - version "5.3.10" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz#904f4c9193c6fd2a03f693a2150c62a92f40d199" - integrity sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w== - dependencies: - "@jridgewell/trace-mapping" "^0.3.20" - jest-worker "^27.4.5" - schema-utils "^3.1.1" - serialize-javascript "^6.0.1" - terser "^5.26.0" - -terser@^5.26.0: - version "5.31.6" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.31.6.tgz#c63858a0f0703988d0266a82fcbf2d7ba76422b1" - integrity sha512-PQ4DAriWzKj+qgehQ7LK5bQqCFNMmlhjR2PFFLuqGCpuCAauxemVBWwWOxo3UIwWQx8+Pr61Df++r76wDmkQBg== - dependencies: - "@jridgewell/source-map" "^0.3.3" - acorn "^8.8.2" - commander "^2.20.0" - source-map-support "~0.5.20" - -test-exclude@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz" - integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== - dependencies: - "@istanbuljs/schema" "^0.1.2" - glob "^7.1.4" - minimatch "^3.0.4" - -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= - -throat@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz" - integrity sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA== - -through@^2.3.8: - version "2.3.8" - resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= - -thunky@^1.0.2: - version "1.1.0" - resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" - integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== - -timed-out@^4.0.0, timed-out@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz" - integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8= - -tiny-invariant@^1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.3.tgz#46680b7a873a0d5d10005995eb90a70d74d60127" - integrity sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg== - -tiny-warning@^1.0.2: - version "1.0.3" - resolved "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz" - integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== - -tmpl@1.0.5, tmpl@1.0.x: - version "1.0.5" - resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" - integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== - -to-buffer@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz" - integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg== - -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" - integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= - -to-object-path@^0.3.0: - version "0.3.0" - resolved "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz" - integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= - dependencies: - kind-of "^3.0.2" - -to-regex-range@^2.1.0: - version "2.1.1" - resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz" - integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= - dependencies: - is-number "^3.0.0" - repeat-string "^1.6.1" - -to-regex-range@^5.0.1: - 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== - dependencies: - is-number "^7.0.0" - -to-regex@^3.0.1, to-regex@^3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz" - integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== - dependencies: - define-property "^2.0.2" - extend-shallow "^3.0.2" - regex-not "^1.0.2" - safe-regex "^1.1.0" - -toggle-selection@^1.0.6: - version "1.0.6" - resolved "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz" - integrity sha1-bkWxJj8gF/oKzH2J14sVuL932jI= - -toidentifier@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" - integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== - -toposort@^2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz" - integrity sha1-riF2gXXRVZ1IvvNUILL0li8JwzA= - -totalist@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/totalist/-/totalist-1.1.0.tgz#a4d65a3e546517701e3e5c37a47a70ac97fe56df" - integrity sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g== - -tough-cookie@^4.0.0: - version "4.1.3" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf" - integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw== - dependencies: - psl "^1.1.33" - punycode "^2.1.1" - universalify "^0.2.0" - url-parse "^1.5.3" - -tr46@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz" - integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw== - dependencies: - punycode "^2.1.1" - -traverse-chain@~0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/traverse-chain/-/traverse-chain-0.1.0.tgz" - integrity sha1-YdvC1Ttp/2CRoSoWj9fUMxB+QPE= - -tree-changes@^0.9.1, tree-changes@^0.9.2: - version "0.9.3" - resolved "https://registry.yarnpkg.com/tree-changes/-/tree-changes-0.9.3.tgz#89433ab3b4250c2910d386be1f83912b7144efcc" - integrity sha512-vvvS+O6kEeGRzMglTKbc19ltLWNtmNt1cpBoSYLj/iEcPVvpJasemKOlxBrmZaCtDJoF+4bwv3m01UKYi8mukQ== - dependencies: - "@gilbarbara/deep-equal" "^0.1.1" - is-lite "^0.8.2" - -trim-lines@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/trim-lines/-/trim-lines-3.0.1.tgz#d802e332a07df861c48802c04321017b1bd87338" - integrity sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg== - -trim-repeated@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz" - integrity sha1-42RqLqTokTEr9+rObPsFOAvAHCE= - dependencies: - escape-string-regexp "^1.0.2" - -trough@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/trough/-/trough-2.2.0.tgz#94a60bd6bd375c152c1df911a4b11d5b0256f50f" - integrity sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw== - -tsconfig-paths@^3.9.0: - version "3.9.0" - resolved "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz" - integrity sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw== - dependencies: - "@types/json5" "^0.0.29" - json5 "^1.0.1" - minimist "^1.2.0" - strip-bom "^3.0.0" - -tslib@^1.10.0, tslib@^1.13.0, tslib@^1.8.1, tslib@^1.9.0: - version "1.14.1" - resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== - -tslib@^2.4.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e" - integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA== - -tsutils@^3.17.1: - version "3.17.1" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759" - integrity sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g== - dependencies: - tslib "^1.8.1" - -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz" - integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= - dependencies: - safe-buffer "^5.0.1" - -type-check@^0.4.0, type-check@~0.4.0: - version "0.4.0" - resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz" - integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== - dependencies: - prelude-ls "^1.2.1" - -type-check@~0.3.2: - version "0.3.2" - resolved "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz" - integrity sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg== - dependencies: - prelude-ls "~1.1.2" - -type-detect@4.0.8: - version "4.0.8" - resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz" - integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== - -type-fest@^0.11.0: - version "0.11.0" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz" - integrity sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ== - -type-fest@^0.6.0: - version "0.6.0" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz" - integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== - -type-fest@^0.8.1: - version "0.8.1" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz" - integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== - -type-is@~1.6.18: - version "1.6.18" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" - integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== - dependencies: - media-typer "0.3.0" - mime-types "~2.1.24" - -typed-styles@^0.0.7: - version "0.0.7" - resolved "https://registry.npmjs.org/typed-styles/-/typed-styles-0.0.7.tgz" - integrity sha512-pzP0PWoZUhsECYjABgCGQlRGL1n7tOHsgwYv3oIiEpJwGhFTuty/YNeduxQYzXXa3Ge5BdT6sHYIQYpl4uJ+5Q== - -typedarray-to-buffer@^3.1.5: - version "3.1.5" - resolved "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz" - integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== - dependencies: - is-typedarray "^1.0.0" - -unbzip2-stream@^1.0.9: - version "1.4.3" - resolved "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz" - integrity sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg== - dependencies: - buffer "^5.2.1" - through "^2.3.8" - -uncontrollable@^7.2.1: - version "7.2.1" - resolved "https://registry.yarnpkg.com/uncontrollable/-/uncontrollable-7.2.1.tgz#1fa70ba0c57a14d5f78905d533cf63916dc75738" - integrity sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ== - dependencies: - "@babel/runtime" "^7.6.3" - "@types/react" ">=16.9.11" - invariant "^2.2.4" - react-lifecycles-compat "^3.0.4" - -unicode-canonical-property-names-ecmascript@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz" - integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ== - -unicode-canonical-property-names-ecmascript@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" - integrity sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ== - -unicode-match-property-ecmascript@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz" - integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg== - dependencies: - unicode-canonical-property-names-ecmascript "^1.0.4" - unicode-property-aliases-ecmascript "^1.0.4" - -unicode-match-property-ecmascript@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" - integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== - dependencies: - unicode-canonical-property-names-ecmascript "^2.0.0" - unicode-property-aliases-ecmascript "^2.0.0" - -unicode-match-property-value-ecmascript@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz" - integrity sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ== - -unicode-match-property-value-ecmascript@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz#cb5fffdcd16a05124f5a4b0bf7c3770208acbbe0" - integrity sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA== - -unicode-property-aliases-ecmascript@^1.0.4: - version "1.1.0" - resolved "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz" - integrity sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg== - -unicode-property-aliases-ecmascript@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz#43d41e3be698bd493ef911077c9b131f827e8ccd" - integrity sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w== - -unified@^11.0.0: - version "11.0.4" - resolved "https://registry.yarnpkg.com/unified/-/unified-11.0.4.tgz#f4be0ac0fe4c88cb873687c07c64c49ed5969015" - integrity sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ== - dependencies: - "@types/unist" "^3.0.0" - bail "^2.0.0" - devlop "^1.0.0" - extend "^3.0.0" - is-plain-obj "^4.0.0" - trough "^2.0.0" - vfile "^6.0.0" - -union-value@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz" - integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== - dependencies: - arr-union "^3.1.0" - get-value "^2.0.6" - is-extendable "^0.1.1" - set-value "^2.0.1" - -uniq@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz" - integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8= - -uniqid@^5.0.3: - version "5.2.0" - resolved "https://registry.npmjs.org/uniqid/-/uniqid-5.2.0.tgz" - integrity sha512-LH8zsvwJ/GL6YtNfSOmMCrI9piraAUjBfw2MCvleNE6a4pVKJwXjG2+HWhkVeFcSg+nmaPKbMrMOoxwQluZ1Mg== - -unist-util-find-after@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz#3fccc1b086b56f34c8b798e1ff90b5c54468e896" - integrity sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ== - dependencies: - "@types/unist" "^3.0.0" - unist-util-is "^6.0.0" - -unist-util-is@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-6.0.0.tgz#b775956486aff107a9ded971d996c173374be424" - integrity sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw== - dependencies: - "@types/unist" "^3.0.0" - -unist-util-position@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/unist-util-position/-/unist-util-position-5.0.0.tgz#678f20ab5ca1207a97d7ea8a388373c9cf896be4" - integrity sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA== - dependencies: - "@types/unist" "^3.0.0" - -unist-util-remove-position@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz#fea68a25658409c9460408bc6b4991b965b52163" - integrity sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q== - dependencies: - "@types/unist" "^3.0.0" - unist-util-visit "^5.0.0" - -unist-util-stringify-position@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz#449c6e21a880e0855bf5aabadeb3a740314abac2" - integrity sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ== - dependencies: - "@types/unist" "^3.0.0" - -unist-util-visit-parents@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz#4d5f85755c3b8f0dc69e21eca5d6d82d22162815" - integrity sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw== - dependencies: - "@types/unist" "^3.0.0" - unist-util-is "^6.0.0" - -unist-util-visit@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-5.0.0.tgz#a7de1f31f72ffd3519ea71814cccf5fd6a9217d6" - integrity sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg== - dependencies: - "@types/unist" "^3.0.0" - unist-util-is "^6.0.0" - unist-util-visit-parents "^6.0.0" - -universalify@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" - integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== - -unpipe@1.0.0, unpipe@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== - -unset-value@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz" - integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= - dependencies: - has-value "^0.3.1" - isobject "^3.0.0" - -update-browserslist-db@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz#7ca61c0d8650766090728046e416a8cde682859e" - integrity sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ== - dependencies: - escalade "^3.1.2" - picocolors "^1.0.1" - -uri-js@^4.2.2: - version "4.4.0" - resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz" - integrity sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g== - dependencies: - punycode "^2.1.0" - -urix@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz" - integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= - -url-loader@^4.1.1: - version "4.1.1" - resolved "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz" - integrity sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA== - dependencies: - loader-utils "^2.0.0" - mime-types "^2.1.27" - schema-utils "^3.0.0" - -url-parse-lax@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz" - integrity sha1-evjzA2Rem9eaJy56FKxovAYJ2nM= - dependencies: - prepend-http "^1.0.1" - -url-parse-lax@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz" - integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww= - dependencies: - prepend-http "^2.0.0" - -url-parse@^1.5.3: - version "1.5.10" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" - integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== - dependencies: - querystringify "^2.1.1" - requires-port "^1.0.0" - -url-to-options@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz" - integrity sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k= - -use-isomorphic-layout-effect@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz#497cefb13d863d687b08477d9e5a164ad8c1a6fb" - integrity sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA== - -use-sync-external-store@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" - integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== - -use@^3.1.0: - version "3.1.1" - resolved "https://registry.npmjs.org/use/-/use-3.1.1.tgz" - integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== - -util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= - -utils-merge@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" - integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== - -uuid@3.0.x: - version "3.0.1" - resolved "https://registry.npmjs.org/uuid/-/uuid-3.0.1.tgz" - integrity sha1-ZUS7ot/ajBzxfmKaOjBeK7H+5sE= - -uuid@^3.0.1: - version "3.4.0" - resolved "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz" - integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== - -uuid@^8.3.0: - version "8.3.1" - resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz" - integrity sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg== - -uuid@^8.3.2: - version "8.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" - integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== - -v8-compile-cache@^2.0.3: - version "2.1.1" - resolved "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz" - integrity sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ== - -v8-to-istanbul@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.0.0.tgz" - integrity sha512-fLL2rFuQpMtm9r8hrAV2apXX/WqHJ6+IC4/eQVdMDGBUgH/YMV4Gv3duk3kjmyg6uiQWBAA9nJwue4iJUOkHeA== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.1" - convert-source-map "^1.6.0" - source-map "^0.7.3" - -validate-npm-package-license@^3.0.1: - version "3.0.4" - resolved "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz" - integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== - dependencies: - spdx-correct "^3.0.0" - spdx-expression-parse "^3.0.0" - -vary@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== - -vfile-location@^5.0.0: - version "5.0.2" - resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-5.0.2.tgz#220d9ca1ab6f8b2504a4db398f7ebc149f9cb464" - integrity sha512-NXPYyxyBSH7zB5U6+3uDdd6Nybz6o6/od9rk8bp9H8GR3L+cm/fC0uUTbqBmUTnMCUDslAGBOIKNfvvb+gGlDg== - dependencies: - "@types/unist" "^3.0.0" - vfile "^6.0.0" - -vfile-message@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-4.0.2.tgz#c883c9f677c72c166362fd635f21fc165a7d1181" - integrity sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw== - dependencies: - "@types/unist" "^3.0.0" - unist-util-stringify-position "^4.0.0" - -vfile@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/vfile/-/vfile-6.0.1.tgz#1e8327f41eac91947d4fe9d237a2dd9209762536" - integrity sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw== - dependencies: - "@types/unist" "^3.0.0" - unist-util-stringify-position "^4.0.0" - vfile-message "^4.0.0" - -w3c-hr-time@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz" - integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== - dependencies: - browser-process-hrtime "^1.0.0" - -w3c-xmlserializer@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz" - integrity sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA== - dependencies: - xml-name-validator "^3.0.0" - -walker@^1.0.7, walker@~1.0.5: - version "1.0.7" - resolved "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz" - integrity sha1-L3+bj9ENZ3JisYqITijRlhjgKPs= - dependencies: - makeerror "1.0.x" - -walker@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" - integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== - dependencies: - makeerror "1.0.12" - -warning@^4.0.0, warning@^4.0.2, warning@^4.0.3: - version "4.0.3" - resolved "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz" - integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w== - dependencies: - loose-envify "^1.0.0" - -watchpack@^2.4.1: - version "2.4.2" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.2.tgz#2feeaed67412e7c33184e5a79ca738fbd38564da" - integrity sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw== - dependencies: - glob-to-regexp "^0.4.1" - graceful-fs "^4.1.2" - -wbuf@^1.1.0, wbuf@^1.7.3: - version "1.7.3" - resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" - integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA== - dependencies: - minimalistic-assert "^1.0.0" - -web-namespaces@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/web-namespaces/-/web-namespaces-2.0.1.tgz#1010ff7c650eccb2592cebeeaf9a1b253fd40692" - integrity sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ== - -webidl-conversions@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz" - integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== - -webidl-conversions@^6.1.0: - version "6.1.0" - resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz" - integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== - -webpack-bundle-analyzer@^4.9.0: - version "4.9.0" - resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.9.0.tgz#fc093c4ab174fd3dcbd1c30b763f56d10141209d" - integrity sha512-+bXGmO1LyiNx0i9enBu3H8mv42sj/BJWhZNFwjz92tVnBa9J3JMGo2an2IXlEleoDOPn/Hofl5hr/xCpObUDtw== - dependencies: - "@discoveryjs/json-ext" "0.5.7" - acorn "^8.0.4" - acorn-walk "^8.0.0" - chalk "^4.1.0" - commander "^7.2.0" - gzip-size "^6.0.0" - lodash "^4.17.20" - opener "^1.5.2" - sirv "^1.0.7" - ws "^7.3.1" - -webpack-cli@^5.1.4: - version "5.1.4" - resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-5.1.4.tgz#c8e046ba7eaae4911d7e71e2b25b776fcc35759b" - integrity sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg== - dependencies: - "@discoveryjs/json-ext" "^0.5.0" - "@webpack-cli/configtest" "^2.1.1" - "@webpack-cli/info" "^2.0.2" - "@webpack-cli/serve" "^2.0.5" - colorette "^2.0.14" - commander "^10.0.1" - cross-spawn "^7.0.3" - envinfo "^7.7.3" - fastest-levenshtein "^1.0.12" - import-local "^3.0.2" - interpret "^3.1.1" - rechoir "^0.8.0" - webpack-merge "^5.7.3" - -webpack-dev-middleware@^5.3.1: - version "5.3.4" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz#eb7b39281cbce10e104eb2b8bf2b63fce49a3517" - integrity sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q== - dependencies: - colorette "^2.0.10" - memfs "^3.4.3" - mime-types "^2.1.31" - range-parser "^1.2.1" - schema-utils "^4.0.0" - -webpack-dev-server@^4.15.1: - version "4.15.1" - resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz#8944b29c12760b3a45bdaa70799b17cb91b03df7" - integrity sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA== - dependencies: - "@types/bonjour" "^3.5.9" - "@types/connect-history-api-fallback" "^1.3.5" - "@types/express" "^4.17.13" - "@types/serve-index" "^1.9.1" - "@types/serve-static" "^1.13.10" - "@types/sockjs" "^0.3.33" - "@types/ws" "^8.5.5" - ansi-html-community "^0.0.8" - bonjour-service "^1.0.11" - chokidar "^3.5.3" - colorette "^2.0.10" - compression "^1.7.4" - connect-history-api-fallback "^2.0.0" - default-gateway "^6.0.3" - express "^4.17.3" - graceful-fs "^4.2.6" - html-entities "^2.3.2" - http-proxy-middleware "^2.0.3" - ipaddr.js "^2.0.1" - launch-editor "^2.6.0" - open "^8.0.9" - p-retry "^4.5.0" - rimraf "^3.0.2" - schema-utils "^4.0.0" - selfsigned "^2.1.1" - serve-index "^1.9.1" - sockjs "^0.3.24" - spdy "^4.0.2" - webpack-dev-middleware "^5.3.1" - ws "^8.13.0" - -webpack-merge@^5.7.3: - version "5.8.0" - resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.8.0.tgz#2b39dbf22af87776ad744c390223731d30a68f61" - integrity sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q== - dependencies: - clone-deep "^4.0.1" - wildcard "^2.0.0" - -webpack-merge@^5.9.0: - version "5.9.0" - resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.9.0.tgz#dc160a1c4cf512ceca515cc231669e9ddb133826" - integrity sha512-6NbRQw4+Sy50vYNTw7EyOn41OZItPiXB8GNv3INSoe3PSFaHJEz3SHTrYVaRm2LilNGnFUzh0FAwqPEmU/CwDg== - dependencies: - clone-deep "^4.0.1" - wildcard "^2.0.0" - -webpack-sources@^3.2.3: - version "3.2.3" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" - integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== - -webpack@^5.94.0: - version "5.94.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.94.0.tgz#77a6089c716e7ab90c1c67574a28da518a20970f" - integrity sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg== - dependencies: - "@types/estree" "^1.0.5" - "@webassemblyjs/ast" "^1.12.1" - "@webassemblyjs/wasm-edit" "^1.12.1" - "@webassemblyjs/wasm-parser" "^1.12.1" - acorn "^8.7.1" - acorn-import-attributes "^1.9.5" - browserslist "^4.21.10" - chrome-trace-event "^1.0.2" - enhanced-resolve "^5.17.1" - es-module-lexer "^1.2.1" - eslint-scope "5.1.1" - events "^3.2.0" - glob-to-regexp "^0.4.1" - graceful-fs "^4.2.11" - json-parse-even-better-errors "^2.3.1" - loader-runner "^4.2.0" - mime-types "^2.1.27" - neo-async "^2.6.2" - schema-utils "^3.2.0" - tapable "^2.1.1" - terser-webpack-plugin "^5.3.10" - watchpack "^2.4.1" - webpack-sources "^3.2.3" - -websocket-driver@>=0.5.1, websocket-driver@^0.7.4: - version "0.7.4" - resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.4.tgz#89ad5295bbf64b480abcba31e4953aca706f5760" - integrity sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg== - dependencies: - http-parser-js ">=0.5.1" - safe-buffer ">=5.1.0" - websocket-extensions ">=0.1.1" - -websocket-extensions@>=0.1.1: - version "0.1.4" - resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" - integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== - -whatwg-encoding@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz" - integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== - dependencies: - iconv-lite "0.4.24" - -whatwg-mimetype@^2.3.0: - version "2.3.0" - resolved "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz" - integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== - -whatwg-url@^8.0.0, whatwg-url@^8.5.0: - version "8.7.0" - resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz" - integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg== - dependencies: - lodash "^4.7.0" - tr46 "^2.1.0" - webidl-conversions "^6.1.0" - -which-boxed-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" - integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== - dependencies: - is-bigint "^1.0.1" - is-boolean-object "^1.1.0" - is-number-object "^1.0.4" - is-string "^1.0.5" - is-symbol "^1.0.3" - -which-collection@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.1.tgz#70eab71ebbbd2aefaf32f917082fc62cdcb70906" - integrity sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A== - dependencies: - is-map "^2.0.1" - is-set "^2.0.1" - is-weakmap "^2.0.1" - is-weakset "^2.0.1" - -which-module@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz" - integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= - -which-typed-array@^1.1.11, which-typed-array@^1.1.9: - version "1.1.11" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.11.tgz#99d691f23c72aab6768680805a271b69761ed61a" - integrity sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - for-each "^0.3.3" - gopd "^1.0.1" - has-tostringtag "^1.0.0" - -which@^1.2.9: - version "1.3.1" - resolved "https://registry.npmjs.org/which/-/which-1.3.1.tgz" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - -which@^2.0.1, which@^2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -wildcard@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz" - integrity sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw== - -word-wrap@^1.2.3, word-wrap@~1.2.3: - version "1.2.4" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.4.tgz#cb4b50ec9aca570abd1f52f33cd45b6c61739a9f" - integrity sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA== - -wrap-ansi@^6.2.0: - version "6.2.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz" - integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrappy@1: - version "1.0.2" - resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -write-file-atomic@^3.0.0: - version "3.0.3" - resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz" - integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== - dependencies: - imurmurhash "^0.1.4" - is-typedarray "^1.0.0" - signal-exit "^3.0.2" - typedarray-to-buffer "^3.1.5" - -write-file-atomic@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" - integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== - dependencies: - imurmurhash "^0.1.4" - signal-exit "^3.0.7" - -write@1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/write/-/write-1.0.3.tgz" - integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== - dependencies: - mkdirp "^0.5.1" - -ws@^7.3.1, ws@^7.4.6: - version "7.5.10" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9" - integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== - -ws@^8.13.0: - version "8.17.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b" - integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ== - -xml-name-validator@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz" - integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== - -xmlchars@^2.2.0: - version "2.2.0" - resolved "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz" - integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== - -xstate@^4.37.2: - version "4.37.2" - resolved "https://registry.yarnpkg.com/xstate/-/xstate-4.37.2.tgz#c5f4c1d8062784238b91e2dfddca05f821cb4eac" - integrity sha512-Qm337O49CRTZ3PRyRuK6b+kvI+D3JGxXIZCTul+xEsyFCVkTFDt5jixaL1nBWcUBcaTQ9um/5CRGVItPi7fveg== - -xtend@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== - -y18n@^4.0.0: - version "4.0.1" - resolved "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz" - integrity sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ== - -yallist@^2.1.2: - version "2.1.2" - resolved "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz" - integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= - -yallist@^3.0.2: - version "3.1.1" - resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz" - integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== - -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - -yaml@^1.10.0: - version "1.10.2" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" - integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== - -yargs-parser@^18.1.2: - version "18.1.3" - resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz" - integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - -yargs@^15.4.1: - version "15.4.1" - resolved "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz" - integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== - dependencies: - cliui "^6.0.0" - decamelize "^1.2.0" - find-up "^4.1.0" - get-caller-file "^2.0.1" - require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^4.2.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^18.1.2" - -yauzl@^2.4.2: - version "2.10.0" - resolved "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz" - integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk= - dependencies: - buffer-crc32 "~0.2.3" - fd-slicer "~1.1.0" - -yocto-queue@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" - integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== - -yocto-queue@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.0.0.tgz#7f816433fb2cbc511ec8bf7d263c3b58a1a3c251" - integrity sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g== - -yup@^0.29.3: - version "0.29.3" - resolved "https://registry.npmjs.org/yup/-/yup-0.29.3.tgz" - integrity sha512-RNUGiZ/sQ37CkhzKFoedkeMfJM0vNQyaz+wRZJzxdKE7VfDeVKH8bb4rr7XhRLbHJz5hSjoDNwMEIaKhuMZ8gQ== - dependencies: - "@babel/runtime" "^7.10.5" - fn-name "~3.0.0" - lodash "^4.17.15" - lodash-es "^4.17.11" - property-expr "^2.0.2" - synchronous-promise "^2.0.13" - toposort "^2.0.2" - -zwitch@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-2.0.4.tgz#c827d4b0acb76fc3e685a4c6ec2902d51070e9d7" - integrity sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A== diff --git a/services/app/apps/phoenix_gon/LICENSE b/services/app/apps/phoenix_gon/LICENSE deleted file mode 100644 index aaed3a396..000000000 --- a/services/app/apps/phoenix_gon/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2017 Marat Khusnetdinov - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/services/app/apps/phoenix_gon/README.md b/services/app/apps/phoenix_gon/README.md deleted file mode 100644 index cec9ca68c..000000000 --- a/services/app/apps/phoenix_gon/README.md +++ /dev/null @@ -1,165 +0,0 @@ -# PhoenixGon [![Hex.pm](https://img.shields.io/hexpm/v/plug.svg)](https://hex.pm/packages/phoenix_gon) [![Build Status](https://travis-ci.org/khusnetdinov/phoenix_gon.svg?branch=master)](https://travis-ci.org/khusnetdinov/phoenix_gon) [![Open Source Helpers](https://www.codetriage.com/khusnetdinov/phoenix_gon/badges/users.svg)](https://www.codetriage.com/khusnetdinov/phoenix_gon) - -## Your Phoenix variables in your JavaScript. - -![img](http://res.cloudinary.com/dtoqqxqjv/image/upload/v1492849051/github/gon.png) - -## Installation - -The package can be installed by adding `phoenix_gon` to your list of dependencies in `mix.exs`: - -```elixir -def deps do - [{:phoenix_gon, "~> 0.4.0"}] -end -``` - -## Usage - -### Three steps configuration: - -1. You need add plug to `lib/project/router.ex` after plug `:fetch_session`. - -```elixir -defmodule Project.Router do - # ... - - pipeline :browser do - # ... - - plug :fetch_session - plug PhoenixGon.Pipeline - - # ... - end - - # ... -end -``` - -Plug accepts options: - - - `:env` - this option for hard overloading Mix.env. - - `:namespace` - namespace for javascript object in global window space. - - `:assets` - map for keeping permanent variables in javascript. - - `:camel_case` - if set to true, all assets names will be converted to camel case format on render. - -2. Add possibility to use view helper by adding `use PhoenixGon.View` in templates in `web/views/layout_view.ex` file: - -```elixir -defmodule Project.LayoutView do - # ... - - import PhoenixGon.View - - # ... -end - -``` - -3. Add helper `render_gon_script` to you layout in `/web/templates/layout/app.html.eex` before main javascript file: - -```elixir - - # ... - - <%= render_gon_script(@conn) %> - - -``` - -Now you can read phoenix variables in browser console and javascript code. - -### Phoenix controllers - -For using gon in controllers just add: - -```elixir -defmodule Project.Controller do - # ... - - import PhoenixGon.Controller - - # ... -end -``` - -#### Controller methods: - -All controller variables are kept in `assets` map. - -- `put_gon` - Put variable to assets. -- `update_gon` - Update variable in assets. -- `drop_gon` - Drop variable in assets. -- `get_gon` - Get variable from assets. - -Example: - -```elixir -def index(conn, _params) do - conn = put_gon(conn, controller: variable) - render conn, "index.html" -end -``` - -```elixir -def index(conn, _params) do - conn = put_gon(conn, controller: variable) - redirect conn, to: "/somewhere.html" -end -``` - -### JavaScript - -Gon object is kept in `window`. - -#### Browser - -Now you can access to you variables in console: - -```javascript -// browser console - -Gon.assets() - -// Object {controller: "variable"} -``` - -#### JavaScript assets - -```JavaScript -// Somewhere in javascript modules - -window.Gon.assets() - -``` - -#### JavaScript methods: - -Phoenix env methods: - -- `getEnv()` - Returns current phoenix env. -- `isDev()` - Returns boolean if development env. -- `isProd()` - Returns boolean if production env. -- `isCustomEnv(env)` - Return bollean if custom env. - -Assets variables methods: - -- `assets()` - Returns all variables setting in config and controllers. -- `getAsset(key)` - Returns variable by key. - -### JSON Library - -Per default the `Jason` is used to encode JSON data, however this can be changed via the application configuration, eg: - -```elixir -config :phoenix_gon, :json_library, Poison -``` - -## Contributors - -Special thanks to Andrey Soshchenko @getux. - -## License - -The library is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT). diff --git a/services/app/apps/phoenix_gon/lib/phoenix_gon.ex b/services/app/apps/phoenix_gon/lib/phoenix_gon.ex deleted file mode 100644 index f8652a175..000000000 --- a/services/app/apps/phoenix_gon/lib/phoenix_gon.ex +++ /dev/null @@ -1,18 +0,0 @@ -defmodule PhoenixGon do - @moduledoc """ - PhoenixGon hex - your Phoenix variables in your JavaScript. - - It includes: - - * `PhoenixGon.Pipeline` - Plug for initializing gon with settings. - - * `PhoenixGon.Storage` - Main struct that is keep as storage in conn for gon variabeles. - - * `PhoenixGon.View` - Adds templates helpers for rendering and adding javascript code to browser. - - * `PhoenixGon.Controller` - Adds helpers for working with gon on elixir controller modules. - - * `PhoenixGon.Utils` - Usefull methods for elixir modules. - - """ -end diff --git a/services/app/apps/phoenix_gon/lib/phoenix_gon/controller.ex b/services/app/apps/phoenix_gon/lib/phoenix_gon/controller.ex deleted file mode 100644 index d564dda0a..000000000 --- a/services/app/apps/phoenix_gon/lib/phoenix_gon/controller.ex +++ /dev/null @@ -1,64 +0,0 @@ -defmodule PhoenixGon.Controller do - import Plug.Conn - import PhoenixGon.Utils - - @moduledoc """ - Adds helpers for working with gon on elixir controller modules. - """ - - @doc """ - Put variables to gon. - """ - @spec put_gon(Plug.Conn.t(), Keyword.t() | map()) :: Plug.Conn.t() - def put_gon(conn, opts) when is_list(opts) do - put_gon(conn, Enum.into(opts, %{})) - end - - def put_gon(conn, opts) when is_map(opts) do - %PhoenixGon.Storage{assets: assets} = variables(conn) - assets = Map.merge(assets, opts) - put_private(conn, :phoenix_gon, %{variables(conn) | assets: assets}) - end - - @doc """ - Update variables in gon. - """ - @spec update_gon(Plug.Conn.t(), Keyword.t()) :: Plug.Conn.t() - def update_gon(_conn, _opts) - - @doc false - def update_gon(conn, opts) when is_list(opts) do - put_gon(conn, opts) - end - - @doc false - def update_gon(conn, opts) when is_map(opts) do - put_gon(conn, opts) - end - - @doc """ - Remove variable from gon. - """ - @spec drop_gon(Plug.Conn.t(), atom() | list()) :: Plug.Conn.t() - def drop_gon(_conn, _opts) - - @doc false - def drop_gon(conn, key) when is_atom(key) do - drop_gon(conn, [key]) - end - - @doc false - def drop_gon(conn, opts) when is_list(opts) do - %PhoenixGon.Storage{assets: assets} = variables(conn) - assets = Map.drop(assets, opts) - put_private(conn, :phoenix_gon, %{variables(conn) | assets: assets}) - end - - @doc """ - Returns variable. - """ - @spec get_gon(Plug.Conn.t(), atom()) :: any() - def get_gon(conn, key) when is_atom(key) do - Map.get(variables(conn).assets, key) - end -end diff --git a/services/app/apps/phoenix_gon/lib/phoenix_gon/pipeline.ex b/services/app/apps/phoenix_gon/lib/phoenix_gon/pipeline.ex deleted file mode 100644 index b33fbb2d1..000000000 --- a/services/app/apps/phoenix_gon/lib/phoenix_gon/pipeline.ex +++ /dev/null @@ -1,52 +0,0 @@ -defmodule PhoenixGon.Pipeline do - import Plug.Conn - - @moduledoc """ - Plug for initializing gon with settings. - """ - - @doc """ - Initializer methods. Returns map wiith configuration settings. - """ - @spec init(Keyword.t()) :: map() - def init(defaults) do - %{ - env: Keyword.get(defaults, :env, Mix.env()), - assets: Keyword.get(defaults, :assets, %{}), - namespace: Keyword.get(defaults, :namespace, nil), - camel_case: Keyword.get(defaults, :camel_case, false) - } - end - - @doc """ - Call method adds to conn %PhoenixGon.Store object with data. - """ - @spec call(Plug.Conn.t(), map()) :: Plug.Conn.t() - def call(conn, defaults) do - session_gon = get_session(conn, "phoenix_gon") - - conn = put_private(conn, :phoenix_gon, session_gon || variables_with(defaults)) - - register_before_send(conn, fn conn -> - gon = conn.private.phoenix_gon - assets_size = map_size(gon.assets || %{}) - - cond do - is_nil(session_gon) and assets_size == 0 -> - conn - - assets_size > 0 and conn.status in 300..308 -> - put_session(conn, "phoenix_gon", gon) - - true -> - delete_session(conn, "phoenix_gon") - end - end) - end - - @doc false - @spec variables_with(map()) :: PhoenixGon.Storage.t() - defp variables_with(%{assets: fun} = defaults) when is_function(fun), do: variables_with(Map.merge(defaults, %{assets: fun.()})) - defp variables_with(defaults), do: Map.merge(%PhoenixGon.Storage{}, defaults) - -end diff --git a/services/app/apps/phoenix_gon/lib/phoenix_gon/storage.ex b/services/app/apps/phoenix_gon/lib/phoenix_gon/storage.ex deleted file mode 100644 index 89b1a7d2f..000000000 --- a/services/app/apps/phoenix_gon/lib/phoenix_gon/storage.ex +++ /dev/null @@ -1,13 +0,0 @@ -defmodule PhoenixGon.Storage do - @moduledoc """ - Main struct that is keep as storage in conn for gon variabeles. - """ - @type t :: %__MODULE__{} - - @doc false - defstruct env: nil, - assets: %{}, - compatibility: :native, - namespace: nil, - camel_case: false -end diff --git a/services/app/apps/phoenix_gon/lib/phoenix_gon/utils.ex b/services/app/apps/phoenix_gon/lib/phoenix_gon/utils.ex deleted file mode 100644 index 478765e9e..000000000 --- a/services/app/apps/phoenix_gon/lib/phoenix_gon/utils.ex +++ /dev/null @@ -1,57 +0,0 @@ -defmodule PhoenixGon.Utils do - @moduledoc """ - Usefull methods for elixir modules - """ - - @doc """ - Return if mix env dev - """ - @spec mix_env_dev?(Plug.Conn.t()) :: boolean() - def mix_env_dev?(conn), do: variables(conn).env == :dev - - @doc """ - Return if mix env prod - """ - @spec mix_env_prod?(Plug.Conn.t()) :: boolean() - def mix_env_prod?(conn), do: variables(conn).env == :prod - - @doc """ - Return elixir gon struct. - """ - @spec variables(Plug.Conn.t()) :: PhoenixGon.Storage.t() - def variables(conn), do: conn.private[:phoenix_gon] - - @doc """ - Retusn elixir assets. - """ - @spec assets(Plug.Conn.t()) :: map() - def assets(conn), do: variables(conn).assets - - @doc """ - Returns all elixir settings. - """ - @spec settings(Plug.Conn.t()) :: list() - def settings(conn) do - Enum.filter(Map.from_struct(variables(conn)), fn {key, _} -> - key != :assets - end) - end - - @doc false - @spec settings(Plug.Conn.t(), atom()) :: any() - def settings(conn, key), do: settings(conn)[key] - - @doc """ - Return current gon namespace. - """ - @spec namespace(Plug.Conn.t()) :: String.t() - def namespace(conn) do - name = settings(conn, :namespace) - - if name == nil do - "Gon" - else - String.split(to_string(name), ".") |> List.last() - end - end -end diff --git a/services/app/apps/phoenix_gon/lib/phoenix_gon/view.ex b/services/app/apps/phoenix_gon/lib/phoenix_gon/view.ex deleted file mode 100644 index d155b60e3..000000000 --- a/services/app/apps/phoenix_gon/lib/phoenix_gon/view.ex +++ /dev/null @@ -1,89 +0,0 @@ -defmodule PhoenixGon.View do - import PhoenixGon.Utils - import Phoenix.HTML - import Phoenix.HTML.Tag - - @moduledoc """ - Adds templates helpers for rendering and adding javascript code to browser. - """ - - @doc """ - Returns javascript code what adds phoenix variables to javascript and browser. - """ - @spec render_gon_script(Plug.Conn.t()) :: any() - def render_gon_script(conn) do - content_tag(:script, type: "text/javascript") do - raw(script(conn)) - end - end - - @spec escape_assets(Plug.Conn.t()) :: String.t() - def escape_assets(conn) do - conn - |> assets - |> resolve_assets_case(conn) - |> json_library().encode! - |> javascript_escape - end - - @doc false - @spec script(Plug.Conn.t()) :: String.t() - defp script(conn) do - """ - var #{namespace(conn)} = (function(window) { - var phoenixEnv = '#{settings(conn)[:env]}'; - var phoenixAssets = JSON.parse("#{escape_assets(conn)}"); - - return { - getEnv: function() { - return phoenixEnv; - }, - isDev: function() { - return phoenixEnv === 'dev'; - }, - isProd: function() { - return phoenixEnv === 'prod'; - }, - isCustomEnv: function(customEnv) { - return phoenixEnv === customEnv; - }, - assets: function() { - return phoenixAssets; - }, - getAsset: function(property) { - return phoenixAssets[property]; - } - }; - })(window); - """ - end - - @doc false - @spec resolve_assets_case(map(), Plug.Conn.t()) :: map() - defp resolve_assets_case(assets, conn) do - if settings(conn)[:camel_case], - do: to_camel_case(assets), - else: assets - end - - @doc false - @spec to_camel_case(map()) :: map() - defp to_camel_case(map) when is_map(map) do - for {key, value} <- map, into: %{} do - new_key = - key - |> Atom.to_string() - |> Recase.to_camel() - |> String.to_atom() - - {new_key, to_camel_case(value)} - end - end - - defp to_camel_case(value), - do: value - - defp json_library do - Application.get_env(:phoenix_gon, :json_library, Jason) - end -end diff --git a/services/app/apps/phoenix_gon/mix.exs b/services/app/apps/phoenix_gon/mix.exs deleted file mode 100644 index 16373d9cd..000000000 --- a/services/app/apps/phoenix_gon/mix.exs +++ /dev/null @@ -1,59 +0,0 @@ -defmodule PhoenixGon.Mixfile do - use Mix.Project - - def project do - [ - app: :phoenix_gon, - version: "0.4.0", - build_path: "../../_build", - config_path: "../../config/config.exs", - deps_path: "../../deps", - lockfile: "../../mix.lock", - elixir: "~> 1.14", - elixirc_paths: elixirc_paths(Mix.env()), - start_permanent: Mix.env() == :prod, - preferred_cli_env: [ - coveralls: :test, - "coveralls.detail": :test, - "coveralls.post": :test, - "coveralls.json": :test, - "coveralls.html": :test - ], - test_coverage: [tool: ExCoveralls, threshold: 60], - description: description(), - deps: deps() - ] - end - - defp elixirc_paths(:test), do: ["lib", "test/support"] - defp elixirc_paths(_), do: ["lib"] - - def application do - [extra_applications: [:logger]] - end - - defp description do - """ - PhoenixGon hex - your Phoenix variables in your JavaScript. - """ - end - - # defp package do - # [ - # name: :phoenix_gon, - # files: ~w{lib} ++ ~w{mix.exs README.md}, - # maintainers: ["Marat Khusnetdinov"], - # licenses: ["MIT"], - # links: %{"GitHub" => "https://github.com/khusnetdinov/phoenix_gon"} - # ] - # end - - defp deps do - [ - {:jason, "~> 1.1"}, - {:phoenix_html, "~> 3.2"}, - {:plug, "~> 1.10"}, - {:recase, "~> 0.6"} - ] - end -end diff --git a/services/app/apps/phoenix_gon/test/phoenix_gon/controller_test.exs b/services/app/apps/phoenix_gon/test/phoenix_gon/controller_test.exs deleted file mode 100644 index c548ad570..000000000 --- a/services/app/apps/phoenix_gon/test/phoenix_gon/controller_test.exs +++ /dev/null @@ -1,66 +0,0 @@ -defmodule PhoenixGon.ControllerTest do - use ExUnit.Case, async: false - use RouterHelper - - import PhoenixGon.Controller - - alias Plug.Conn - - describe "#put_gon" do - test "conn" do - conn = - %Conn{} - |> with_gon - |> put_gon(test: :test) - - actual = conn.private[:phoenix_gon].assets[:test] - expectation = :test - - assert actual == expectation - end - end - - describe "update_gon" do - test "conn" do - conn = - %Conn{} - |> with_gon - |> put_gon(test: :not_test) - |> update_gon(test: :test) - - actual = conn.private[:phoenix_gon].assets[:test] - expectation = :test - - assert actual == expectation - end - end - - describe "drop_gon" do - test "conn" do - conn = - %Conn{} - |> with_gon - |> put_gon(test: :test) - |> drop_gon(:test) - - actual = conn.private[:phoenix_gon].assets[:test] - expectation = nil - - assert actual == expectation - end - end - - describe "get_gon" do - test "conn" do - conn = - %Conn{} - |> with_gon - |> put_gon(test: :test) - - actual = conn.private[:phoenix_gon].assets[:test] - expectation = get_gon(conn, :test) - - assert actual == expectation - end - end -end diff --git a/services/app/apps/phoenix_gon/test/phoenix_gon/pipeline_test.exs b/services/app/apps/phoenix_gon/test/phoenix_gon/pipeline_test.exs deleted file mode 100644 index 60b92fe30..000000000 --- a/services/app/apps/phoenix_gon/test/phoenix_gon/pipeline_test.exs +++ /dev/null @@ -1,37 +0,0 @@ -defmodule PhoenixGon.PipelineTest do - use ExUnit.Case, async: false - use RouterHelper - - alias PhoenixGon.Pipeline - alias Plug.Conn - - describe "initialization" do - test "init" do - defaults = [namespace: :test, camel_case: true] - - expectation = %{ - assets: %{}, - env: :test, - namespace: :test, - camel_case: true - } - - actual = Pipeline.init(defaults) - - assert actual == expectation - end - end - - describe "connection" do - test "call" do - conn = - %Conn{} - |> with_gon - - actual = conn.private[:phoenix_gon].env - expectation = Pipeline.init([]).env - - assert actual == expectation - end - end -end diff --git a/services/app/apps/phoenix_gon/test/phoenix_gon/storage_test.exs b/services/app/apps/phoenix_gon/test/phoenix_gon/storage_test.exs deleted file mode 100644 index a1f2f0acd..000000000 --- a/services/app/apps/phoenix_gon/test/phoenix_gon/storage_test.exs +++ /dev/null @@ -1,27 +0,0 @@ -defmodule PhoenixGon.StoregeTest do - use ExUnit.Case, async: false - - import PhoenixGon.Storage - - describe "default storage" do - test "env" do - storage = %PhoenixGon.Storage{} - assert storage.env == nil - end - - test "namespace" do - storage = %PhoenixGon.Storage{} - assert storage.namespace == nil - end - - test "camel_case" do - storage = %PhoenixGon.Storage{} - assert storage.camel_case == false - end - - test "assets" do - storage = %PhoenixGon.Storage{} - assert storage.assets == %{} - end - end -end diff --git a/services/app/apps/phoenix_gon/test/phoenix_gon/utils_test.exs b/services/app/apps/phoenix_gon/test/phoenix_gon/utils_test.exs deleted file mode 100644 index db7f4885a..000000000 --- a/services/app/apps/phoenix_gon/test/phoenix_gon/utils_test.exs +++ /dev/null @@ -1,92 +0,0 @@ -defmodule PhoenixGon.UtilsTest do - use ExUnit.Case, async: false - use RouterHelper - - import PhoenixGon.Utils - - alias Plug.Conn - - describe "#mix_env_dev?" do - test "env" do - conn = - %Conn{} - |> with_gon(env: :dev) - - actual = mix_env_dev?(conn) - expectation = true - - assert actual == expectation - end - end - - describe "#mix_env_prod?" do - test "prod" do - conn = - %Conn{} - |> with_gon(env: :prod) - - actual = mix_env_prod?(conn) - expectation = true - - assert actual == expectation - end - end - - describe "#variables" do - test "conn" do - conn = - %Conn{} - |> with_gon(env: nil) - - actual = variables(conn) - expectation = %PhoenixGon.Storage{} - - assert actual == expectation - end - end - - describe "#assets" do - test "conn" do - conn = - %Conn{} - |> with_gon(env: nil) - - actual = assets(conn) - expectation = %{} - - assert actual == expectation - end - end - - describe "settings" do - test "conn" do - conn = - %Conn{} - |> with_gon(env: nil) - - actual = settings(conn) - - expectation = [ - camel_case: false, - compatibility: :native, - env: nil, - namespace: nil - ] - - assert Enum.sort(actual) == Enum.sort(expectation) - end - end - - describe "#namescpase" do - test "conn" do - conn = - %Conn{} - |> with_gon(namespace: TestCase) - - actual = namespace(conn) - expectation = "TestCase" - - assert actual == expectation - end - end -end diff --git a/services/app/apps/phoenix_gon/test/phoenix_gon/view_test.exs b/services/app/apps/phoenix_gon/test/phoenix_gon/view_test.exs deleted file mode 100644 index 3e2489fcd..000000000 --- a/services/app/apps/phoenix_gon/test/phoenix_gon/view_test.exs +++ /dev/null @@ -1,71 +0,0 @@ -defmodule PhoenixGon.ViewTest do - use ExUnit.Case, async: false - use RouterHelper - - import PhoenixGon.Controller - - alias Plug.Conn - - describe "#render_gon_script" do - test "text" do - conn = - %Conn{} - |> with_gon - - actual = PhoenixGon.View.render_gon_script(conn) - - assert {:safe, _} = actual - end - end - - describe "#escape_assets" do - test "escapes javascript" do - conn = - %Conn{} - |> with_gon - - conn = - conn - |> put_gon(malicious: "all your base") - - actual = PhoenixGon.View.escape_assets(conn) - - expected = - "{\\\"malicious\\\":\\\"all your base<\\/script>