From d3ea643a2b7e1639ff909209abca7577d8ae648a Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 1 Nov 2025 22:50:13 -0700 Subject: [PATCH 01/26] fresh out of the oven --- .github/actions/setup-pnpm/action.yaml | 35 - .github/workflows/build.yaml | 8 +- .github/workflows/test.yaml | 28 +- .npmrc | 1 - Dockerfile | 25 +- README.md | 11 +- bun.lockb | Bin 0 -> 499214 bytes jest-puppeteer.build.config.js | 2 +- jest-puppeteer.config.js | 2 +- package.json | 6 +- pnpm-lock.yaml | 9790 ---------------------- src/components/utils/BackgroundImage.jsx | 100 - 12 files changed, 46 insertions(+), 9962 deletions(-) delete mode 100644 .github/actions/setup-pnpm/action.yaml delete mode 100644 .npmrc create mode 100755 bun.lockb delete mode 100644 pnpm-lock.yaml delete mode 100644 src/components/utils/BackgroundImage.jsx diff --git a/.github/actions/setup-pnpm/action.yaml b/.github/actions/setup-pnpm/action.yaml deleted file mode 100644 index 841bea97..00000000 --- a/.github/actions/setup-pnpm/action.yaml +++ /dev/null @@ -1,35 +0,0 @@ -name: Setup PNPM -author: Cameron Clough -description: Setup PNPM for use in GitHub Actions - -inputs: - node-version: - description: "The version of Node.js to use" - default: "20" - pnpm-version: - description: "The version of PNPM to use" - default: "9" - -runs: - using: "composite" - steps: - - uses: pnpm/action-setup@v4 - with: - version: ${{ inputs.pnpm-version }} - run_install: false - - - uses: actions/setup-node@v4 - with: - node-version: ${{ inputs.node-version }} - cache: pnpm - - - id: pnpm-cache - shell: bash - run: echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT - - - uses: actions/cache@v4 - with: - path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} - key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} - restore-keys: | - ${{ runner.os }}-pnpm-store- diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 17809bb3..d00a2ef1 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -12,14 +12,16 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: ./.github/actions/setup-pnpm + - uses: oven-sh/setup-bun@v2 + with: + bun-version: latest - name: get build info id: build_info run: echo timestamp=$(git show -s --format=%cI) >> $GITHUB_OUTPUT - - run: pnpm install - - run: pnpm build:production + - run: bun install + - run: bun run build:production env: VITE_APP_GIT_SHA: ${{ github.sha }} VITE_APP_GIT_TIMESTAMP: ${{ steps.build_info.outputs.timestamp }} diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 5a5a6324..b9c14d81 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -12,23 +12,24 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: ./.github/actions/setup-pnpm + - uses: oven-sh/setup-bun@v2 + with: + bun-version: latest - run: | - pnpm install - cd ./node_modules/puppeteer - pnpm install + bun install + node ./node_modules/puppeteer/install.js - - run: pnpm run build:development + - run: bun run build:development - name: Lint - run: pnpm lint + run: bun run lint - name: Run unit tests - run: pnpm test + run: bun run test - name: Run end-to-end tests - run: pnpm test-puppeteer-build + run: bun run test-puppeteer-build # bundle_size: # runs-on: ubuntu-latest @@ -47,15 +48,16 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: ./.github/actions/setup-pnpm + - uses: oven-sh/setup-bun@v2 + with: + bun-version: latest - - run: pnpm install - - run: pnpm build:production + - run: bun install + - run: bun run build:production - name: run Lighthouse CI run: | - pnpm add -g @lhci/cli@0.12.x - lhci autorun + bunx @lhci/cli@0.12.x autorun env: LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }} diff --git a/.npmrc b/.npmrc deleted file mode 100644 index cb53d4e5..00000000 --- a/.npmrc +++ /dev/null @@ -1 +0,0 @@ -prefer-frozen-lockfile=true diff --git a/Dockerfile b/Dockerfile index 1c9f42dc..469f6d6d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,27 +1,26 @@ -FROM node:20-alpine AS base - -ARG PNPM_VERSION=8.6.3 -RUN npm install -g pnpm@$PNPM_VERSION +FROM oven/bun:1 as base WORKDIR /app FROM base AS build -COPY ./pnpm-lock.yaml . -RUN pnpm fetch +# Install dependencies with Bun. If a bun.lockb is present it will be used. +COPY package.json ./ +RUN bun install +# Copy application source ADD . ./ -RUN pnpm install --offline ARG VITE_APP_GIT_SHA=unknown ARG VITE_APP_GIT_TIMESTAMP=1970-01-01T00:00:00Z ARG SENTRY_AUTH_TOKEN ARG SENTRY_RELEASE -ENV VITE_APP_GIT_SHA $VITE_APP_GIT_SHA -ENV VITE_APP_GIT_TIMESTAMP $VITE_APP_GIT_TIMESTAMP -ENV SENTRY_AUTH_TOKEN $SENTRY_AUTH_TOKEN -ENV SENTRY_RELEASE $SENTRY_RELEASE -RUN pnpm build:production +ENV VITE_APP_GIT_SHA=$VITE_APP_GIT_SHA \ + VITE_APP_GIT_TIMESTAMP=$VITE_APP_GIT_TIMESTAMP \ + SENTRY_AUTH_TOKEN=$SENTRY_AUTH_TOKEN \ + SENTRY_RELEASE=$SENTRY_RELEASE + +RUN bun run build:production FROM nginx:1.24 @@ -30,6 +29,6 @@ COPY config.js.template /etc/nginx/templates/config.js.template COPY nginx.conf /etc/nginx/conf.d/default.conf COPY --from=build /app/dist /usr/share/nginx/html -ENV NGINX_ENVSUBST_OUTPUT_DIR /usr/share/nginx/html +ENV NGINX_ENVSUBST_OUTPUT_DIR=/usr/share/nginx/html EXPOSE 80 diff --git a/README.md b/README.md index 1edb10b1..59b2d0f5 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,14 @@ The frontend to the comma connect progressive web app. This a react app using [Create React App](https://github.com/facebookincubator/create-react-app) ## Development -* Install pnpm: https://pnpm.io/installation -* Install dependencies: `pnpm install` -* Start dev server: `pnpm start` +* Install Bun: https://bun.sh +* Install dependencies: `bun install` +* Start dev server: `bun run start` + +### Other scripts +- Run unit tests: `bun run test` +- Run e2e tests: `bun run test-puppeteer` +- Build (production): `bun run build:production` ## Contributing diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 0000000000000000000000000000000000000000..2b18a6da6a2714a3ab1c120c1a639c94a6791b0f GIT binary patch literal 499214 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 @NQO_K#63tMcPdi5waPg{ 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 literal 0 HcmV?d00001 diff --git a/jest-puppeteer.build.config.js b/jest-puppeteer.build.config.js index 3cfeab8d..93f5d663 100644 --- a/jest-puppeteer.build.config.js +++ b/jest-puppeteer.build.config.js @@ -4,6 +4,6 @@ module.exports = { ...config, server: { ...config['server'], - command: 'pnpm serve --port 3003', + command: 'bun run serve --port 3003', }, }; diff --git a/jest-puppeteer.config.js b/jest-puppeteer.config.js index 2f12d9da..93887da5 100644 --- a/jest-puppeteer.config.js +++ b/jest-puppeteer.config.js @@ -8,7 +8,7 @@ module.exports = { args: [`--window-size=${width},${height}`], }, server: { - command: 'env-cmd .env.development pnpm start --port 3003', + command: 'env-cmd .env.development bun run start --port 3003', port: 3003, launchTimeout: 15000, debug: true, diff --git a/package.json b/package.json index 60e0677d..68d11227 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "test": "jest", "test-coverage": "jest --coverage", "test-puppeteer": "jest -c src/__puppeteer__/jest.config.js", - "test-puppeteer-build": "JEST_PUPPETEER_CONFIG=jest-puppeteer.build.config.js pnpm test-puppeteer" + "test-puppeteer-build": "JEST_PUPPETEER_CONFIG=jest-puppeteer.build.config.js bun run test-puppeteer" }, "repository": "https://github.com/commaai/connect.git", "author": "Chris Vickery ", @@ -20,8 +20,10 @@ "Cameron Clough " ], "private": true, + "packageManager": "bun@1.3.1", "engines": { - "node": ">=16" + "node": ">=16", + "bun": ">=1.3.0" }, "dependencies": { "@commaai/api": "github:commaai/comma-api#3.2.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml deleted file mode 100644 index d182f4a9..00000000 --- a/pnpm-lock.yaml +++ /dev/null @@ -1,9790 +0,0 @@ -lockfileVersion: '6.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -dependencies: - '@commaai/api': - specifier: github:commaai/comma-api#3.2.0 - version: github.com/commaai/comma-api/6325ff32b82aeddb2edc10a6175717349b7f75c5 - '@commaai/my-comma-auth': - specifier: ^1.4.1 - version: 1.4.1 - '@mapbox/mapbox-sdk': - specifier: ^0.15.3 - version: 0.15.3 - '@material-ui/core': - specifier: ^1.5.1 - version: 1.5.1(react-dom@18.2.0)(react@18.2.0) - '@material-ui/icons': - specifier: ^1.1.1 - version: 1.1.1(@material-ui/core@1.5.1)(react-dom@18.2.0)(react@18.2.0) - '@sentry/react': - specifier: ^7.64.0 - version: 7.64.0(react@18.2.0) - '@sentry/vite-plugin': - specifier: ^2.7.0 - version: 2.7.0 - connected-react-router: - specifier: ^4.5.0 - version: 4.5.0(react-redux@5.1.2)(react-router@5.3.4)(react@18.2.0)(redux@4.2.1) - dayjs: - specifier: ^1.11.9 - version: 1.11.9 - debounce: - specifier: ^1.2.1 - version: 1.2.1 - global: - specifier: ^4.4.0 - version: 4.4.0 - history: - specifier: ^4.10.1 - version: 4.10.1 - jwt-decode: - specifier: ^3.1.2 - version: 3.1.2 - localforage: - specifier: ^1.10.0 - version: 1.10.0 - mapbox-gl: - specifier: ^1.13.3 - version: 1.13.3 - obstruction: - specifier: ^2.1.0 - version: 2.1.0 - prop-types: - specifier: ^15.8.1 - version: 15.8.1 - qr-scanner: - specifier: ^1.4.2 - version: 1.4.2 - query-string: - specifier: ^6.14.1 - version: 6.14.1 - raf: - specifier: ^3.4.1 - version: 3.4.1 - react: - specifier: ~18.2.0 - version: 18.2.0 - react-dom: - specifier: ~18.2.0 - version: 18.2.0(react@18.2.0) - react-map-gl: - specifier: ^5.3.21 - version: 5.3.21(react@18.2.0) - react-measure: - specifier: ^2.5.2 - version: 2.5.2(react-dom@18.2.0)(react@18.2.0) - react-player: - specifier: ^2.12.0 - version: 2.12.0(react@18.2.0) - react-redux: - specifier: ^5.1.2 - version: 5.1.2(react@18.2.0)(redux@4.2.1) - react-router: - specifier: ^5.3.4 - version: 5.3.4(react@18.2.0) - react-router-dom: - specifier: ^5.3.4 - version: 5.3.4(react@18.2.0) - reduce-reducers: - specifier: ^1.0.4 - version: 1.0.4 - redux: - specifier: ^4.2.1 - version: 4.2.1 - redux-thunk: - specifier: ^2.4.2 - version: 2.4.2(redux@4.2.1) - web-vitals: - specifier: ^3.4.0 - version: 3.4.0 - -devDependencies: - '@swc/core': - specifier: ^1.3.80 - version: 1.3.80 - '@swc/jest': - specifier: ^0.2.29 - version: 0.2.29(@swc/core@1.3.80) - '@tailwindcss/typography': - specifier: ^0.5.9 - version: 0.5.9(tailwindcss@3.3.3) - '@testing-library/jest-dom': - specifier: ^5.17.0 - version: 5.17.0 - '@testing-library/react': - specifier: ^13.4.0 - version: 13.4.0(react-dom@18.2.0)(react@18.2.0) - '@types/react': - specifier: ^18.2.21 - version: 18.2.21 - '@types/react-dom': - specifier: ^18.2.7 - version: 18.2.7 - '@vitejs/plugin-react': - specifier: ^4.0.4 - version: 4.0.4(vite@4.5.3) - autoprefixer: - specifier: ^10.4.15 - version: 10.4.15(postcss@8.4.28) - camelcase: - specifier: ^6.3.0 - version: 6.3.0 - env-cmd: - specifier: ^8.0.2 - version: 8.0.2 - eslint: - specifier: ^8.48.0 - version: 8.48.0 - eslint-plugin-import: - specifier: ^2.28.1 - version: 2.28.1(eslint@8.48.0) - eslint-plugin-jest-dom: - specifier: ^5.1.0 - version: 5.1.0(eslint@8.48.0) - eslint-plugin-react: - specifier: ^7.33.2 - version: 7.33.2(eslint@8.48.0) - eslint-plugin-react-hooks: - specifier: ^4.6.0 - version: 4.6.0(eslint@8.48.0) - expect-puppeteer: - specifier: ^9.0.0 - version: 9.0.0 - identity-obj-proxy: - specifier: ^3.0.0 - version: 3.0.0 - jest: - specifier: ^27.5.1 - version: 27.5.1 - jest-chain-transform: - specifier: ^0.0.5 - version: 0.0.5(@jest/transform@27.5.1) - jest-environment-jsdom: - specifier: ^27.5.1 - version: 27.5.1 - jest-environment-puppeteer: - specifier: ^6.2.0 - version: 6.2.0 - jest-puppeteer: - specifier: ^6.2.0 - version: 6.2.0(puppeteer@19.11.1) - postcss: - specifier: ^8.4.28 - version: 8.4.28 - puppeteer: - specifier: ^19.11.1 - version: 19.11.1 - react-test-renderer: - specifier: ^18.2.0 - version: 18.2.0(react@18.2.0) - tailwindcss: - specifier: ^3.3.3 - version: 3.3.3 - vite: - specifier: ^4.5.3 - version: 4.5.3 - vite-plugin-pwa: - specifier: ^0.16.4 - version: 0.16.4(vite@4.5.3)(workbox-build@7.0.0)(workbox-window@7.0.0) - vite-plugin-svgr: - specifier: ^3.2.0 - version: 3.2.0(rollup@2.79.1)(vite@4.5.3) - whatwg-fetch: - specifier: ^3.6.17 - version: 3.6.17 - workbox-window: - specifier: ^7.0.0 - version: 7.0.0 - -packages: - - /@aashutoshrathi/word-wrap@1.2.6: - resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} - engines: {node: '>=0.10.0'} - dev: true - - /@adobe/css-tools@4.3.2: - resolution: {integrity: sha512-DA5a1C0gD/pLOvhv33YMrbf2FK3oUzwNl9oOJqE4XVjuEtt6XIakRcsd7eLiOSPkp1kTRQGICTA8cKra/vFbjw==} - dev: true - - /@alloc/quick-lru@5.2.0: - resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} - engines: {node: '>=10'} - dev: true - - /@ampproject/remapping@2.2.1: - resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} - engines: {node: '>=6.0.0'} - dependencies: - '@jridgewell/gen-mapping': 0.3.3 - '@jridgewell/trace-mapping': 0.3.19 - dev: true - - /@apideck/better-ajv-errors@0.3.6(ajv@8.12.0): - resolution: {integrity: sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA==} - engines: {node: '>=10'} - peerDependencies: - ajv: '>=8' - dependencies: - ajv: 8.12.0 - json-schema: 0.4.0 - jsonpointer: 5.0.1 - leven: 3.1.0 - dev: true - - /@babel/code-frame@7.22.10: - resolution: {integrity: sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/highlight': 7.22.10 - chalk: 2.4.2 - - /@babel/code-frame@7.23.5: - resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/highlight': 7.23.4 - chalk: 2.4.2 - dev: true - - /@babel/compat-data@7.22.9: - resolution: {integrity: sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/compat-data@7.23.5: - resolution: {integrity: sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/core@7.22.11: - resolution: {integrity: sha512-lh7RJrtPdhibbxndr6/xx0w8+CVlY5FJZiaSz908Fpy+G0xkBFTvwLcKJFF4PJxVfGhVWNebikpWGnOoC71juQ==} - engines: {node: '>=6.9.0'} - dependencies: - '@ampproject/remapping': 2.2.1 - '@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/core@7.22.11) - '@babel/helpers': 7.22.11 - '@babel/parser': 7.22.11 - '@babel/template': 7.22.5 - '@babel/traverse': 7.22.11 - '@babel/types': 7.22.11 - convert-source-map: 1.9.0 - debug: 4.3.4 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/core@7.23.5: - resolution: {integrity: sha512-Cwc2XjUrG4ilcfOw4wBAK+enbdgwAcAJCfGUItPBKR7Mjw4aEfAFYrLxeRp4jWgtNIKn3n2AlBOfwwafl+42/g==} - engines: {node: '>=6.9.0'} - dependencies: - '@ampproject/remapping': 2.2.1 - '@babel/code-frame': 7.23.5 - '@babel/generator': 7.23.5 - '@babel/helper-compilation-targets': 7.22.15 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.5) - '@babel/helpers': 7.23.5 - '@babel/parser': 7.23.5 - '@babel/template': 7.22.15 - '@babel/traverse': 7.23.5 - '@babel/types': 7.23.5 - convert-source-map: 2.0.0 - debug: 4.3.4 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/generator@7.22.10: - resolution: {integrity: sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.22.11 - '@jridgewell/gen-mapping': 0.3.3 - '@jridgewell/trace-mapping': 0.3.19 - jsesc: 2.5.2 - dev: true - - /@babel/generator@7.23.5: - resolution: {integrity: sha512-BPssCHrBD+0YrxviOa3QzpqwhNIXKEtOa2jQrm4FlmkC2apYgRnQcmPWiGZDlGxiNtltnUFolMe8497Esry+jA==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.23.5 - '@jridgewell/gen-mapping': 0.3.3 - '@jridgewell/trace-mapping': 0.3.20 - jsesc: 2.5.2 - dev: true - - /@babel/helper-annotate-as-pure@7.22.5: - resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.23.5 - dev: true - - /@babel/helper-builder-binary-assignment-operator-visitor@7.22.15: - resolution: {integrity: sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.23.5 - dev: true - - /@babel/helper-compilation-targets@7.22.10: - resolution: {integrity: sha512-JMSwHD4J7SLod0idLq5PKgI+6g/hLD/iuWBq08ZX49xE14VpVEojJ5rHWptpirV2j020MvypRLAXAO50igCJ5Q==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/compat-data': 7.22.9 - '@babel/helper-validator-option': 7.22.5 - browserslist: 4.22.1 - lru-cache: 5.1.1 - semver: 6.3.1 - dev: true - - /@babel/helper-compilation-targets@7.22.15: - resolution: {integrity: sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/compat-data': 7.23.5 - '@babel/helper-validator-option': 7.23.5 - browserslist: 4.22.1 - lru-cache: 5.1.1 - semver: 6.3.1 - dev: true - - /@babel/helper-create-class-features-plugin@7.23.5(@babel/core@7.23.5): - resolution: {integrity: sha512-QELlRWxSpgdwdJzSJn4WAhKC+hvw/AtHbbrIoncKHkhKKR/luAlKkgBDcri1EzWAo8f8VvYVryEHN4tax/V67A==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-function-name': 7.23.0 - '@babel/helper-member-expression-to-functions': 7.23.0 - '@babel/helper-optimise-call-expression': 7.22.5 - '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.5) - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 - semver: 6.3.1 - dev: true - - /@babel/helper-create-regexp-features-plugin@7.22.15(@babel/core@7.23.5): - resolution: {integrity: sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-annotate-as-pure': 7.22.5 - regexpu-core: 5.3.2 - semver: 6.3.1 - dev: true - - /@babel/helper-define-polyfill-provider@0.4.3(@babel/core@7.23.5): - resolution: {integrity: sha512-WBrLmuPP47n7PNwsZ57pqam6G/RGo1vw/87b0Blc53tZNGZ4x7YvZ6HgQe2vo1W/FR20OgjeZuGXzudPiXHFug==} - peerDependencies: - '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-compilation-targets': 7.22.15 - '@babel/helper-plugin-utils': 7.22.5 - debug: 4.3.4 - lodash.debounce: 4.0.8 - resolve: 1.22.8 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/helper-environment-visitor@7.22.20: - resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helper-environment-visitor@7.22.5: - resolution: {integrity: sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helper-function-name@7.22.5: - resolution: {integrity: sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/template': 7.22.5 - '@babel/types': 7.22.11 - dev: true - - /@babel/helper-function-name@7.23.0: - resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/template': 7.22.15 - '@babel/types': 7.23.5 - dev: true - - /@babel/helper-hoist-variables@7.22.5: - resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.22.11 - dev: true - - /@babel/helper-member-expression-to-functions@7.23.0: - resolution: {integrity: sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.23.5 - dev: true - - /@babel/helper-module-imports@7.22.15: - resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.23.5 - dev: true - - /@babel/helper-module-imports@7.22.5: - resolution: {integrity: sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.22.11 - dev: true - - /@babel/helper-module-transforms@7.22.9(@babel/core@7.22.11): - resolution: {integrity: sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.22.11 - '@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 - dev: true - - /@babel/helper-module-transforms@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-module-imports': 7.22.15 - '@babel/helper-simple-access': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 - '@babel/helper-validator-identifier': 7.22.20 - dev: true - - /@babel/helper-optimise-call-expression@7.22.5: - resolution: {integrity: sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.23.5 - dev: true - - /@babel/helper-plugin-utils@7.22.5: - resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helper-remap-async-to-generator@7.22.20(@babel/core@7.23.5): - resolution: {integrity: sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-wrap-function': 7.22.20 - dev: true - - /@babel/helper-replace-supers@7.22.20(@babel/core@7.23.5): - resolution: {integrity: sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-member-expression-to-functions': 7.23.0 - '@babel/helper-optimise-call-expression': 7.22.5 - dev: true - - /@babel/helper-simple-access@7.22.5: - resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.22.11 - dev: true - - /@babel/helper-skip-transparent-expression-wrappers@7.22.5: - resolution: {integrity: sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.23.5 - dev: true - - /@babel/helper-split-export-declaration@7.22.6: - resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.22.11 - dev: true - - /@babel/helper-string-parser@7.22.5: - resolution: {integrity: sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helper-string-parser@7.23.4: - resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helper-validator-identifier@7.22.20: - resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helper-validator-identifier@7.22.5: - resolution: {integrity: sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==} - engines: {node: '>=6.9.0'} - - /@babel/helper-validator-option@7.22.5: - resolution: {integrity: sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helper-validator-option@7.23.5: - resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helper-wrap-function@7.22.20: - resolution: {integrity: sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-function-name': 7.23.0 - '@babel/template': 7.22.15 - '@babel/types': 7.23.5 - dev: true - - /@babel/helpers@7.22.11: - resolution: {integrity: sha512-vyOXC8PBWaGc5h7GMsNx68OH33cypkEDJCHvYVVgVbbxJDROYVtexSk0gK5iCF1xNjRIN2s8ai7hwkWDq5szWg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/template': 7.22.5 - '@babel/traverse': 7.22.11 - '@babel/types': 7.22.11 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/helpers@7.23.5: - resolution: {integrity: sha512-oO7us8FzTEsG3U6ag9MfdF1iA/7Z6dz+MtFhifZk8C8o453rGJFFWUP1t+ULM9TUIAzC9uxXEiXjOiVMyd7QPg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/template': 7.22.15 - '@babel/traverse': 7.23.5 - '@babel/types': 7.23.5 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/highlight@7.22.10: - resolution: {integrity: sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-validator-identifier': 7.22.5 - chalk: 2.4.2 - js-tokens: 4.0.0 - - /@babel/highlight@7.23.4: - resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-validator-identifier': 7.22.20 - chalk: 2.4.2 - js-tokens: 4.0.0 - dev: true - - /@babel/parser@7.22.11: - resolution: {integrity: sha512-R5zb8eJIBPJriQtbH/htEQy4k7E2dHWlD2Y2VT07JCzwYZHBxV5ZYtM0UhXSNMT74LyxuM+b1jdL7pSesXbC/g==} - engines: {node: '>=6.0.0'} - hasBin: true - dependencies: - '@babel/types': 7.22.11 - dev: true - - /@babel/parser@7.23.5: - resolution: {integrity: sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ==} - engines: {node: '>=6.0.0'} - hasBin: true - dependencies: - '@babel/types': 7.23.5 - dev: true - - /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-WwlxbfMNdVEpQjZmK5mhm7oSwD3dS6eU+Iwsi4Knl9wAletWem7kaRsGOG+8UEbRyqxY4SS5zvtfXwX+jMxUwQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.13.0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.23.5) - dev: true - - /@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-XaJak1qcityzrX0/IU5nKHb34VaibwP3saKqG6a/tppelgllOH13LUann4ZCIBcVOeE6H18K4Vx9QKkVww3z/w==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.23.5): - resolution: {integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - dev: true - - /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.22.11): - resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.23.5): - resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.22.11): - resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.22.11): - resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.23.5): - resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.23.5): - resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.23.5): - resolution: {integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.23.5): - resolution: {integrity: sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-import-assertions@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-import-attributes@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-pawnE0P9g10xgoP7yKr6CK63K2FMsTE+FZidZO/1PwRdzmAPVs+HS1mAURUsgaoxammTJvULUdIkEK0gOcU2tA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.22.11): - resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.23.5): - resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.22.11): - resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.23.5): - resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.22.11): - resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.23.5): - resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.22.11): - resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.23.5): - resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.22.11): - resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.23.5): - resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.22.11): - resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.23.5): - resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.22.11): - resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.23.5): - resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.22.11): - resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.23.5): - resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.23.5): - resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.22.11): - resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.23.5): - resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-typescript@7.22.5(@babel/core@7.22.11): - resolution: {integrity: sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.23.5): - resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.5) - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-transform-arrow-functions@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-transform-async-generator-functions@7.23.4(@babel/core@7.23.5): - resolution: {integrity: sha512-efdkfPhHYTtn0G6n2ddrESE91fgXxjlqLsnUtPWnJs4a4mZIbUaK7ffqKIIUKXSHwcDvaCVX6GXkaJJFqtX7jw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.23.5) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.5) - dev: true - - /@babel/plugin-transform-async-to-generator@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-module-imports': 7.22.15 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.23.5) - dev: true - - /@babel/plugin-transform-block-scoped-functions@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-transform-block-scoping@7.23.4(@babel/core@7.23.5): - resolution: {integrity: sha512-0QqbP6B6HOh7/8iNR4CQU2Th/bbRtBp4KS9vcaZd1fZ0wSh5Fyssg0UCIHwxh+ka+pNDREbVLQnHCMHKZfPwfw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-transform-class-properties@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-uM+AN8yCIjDPccsKGlw271xjJtGii+xQIF/uMPS8H15L12jZTsLfF4o5vNO7d/oUguOyfdikHGc/yi9ge4SGIg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.23.5) - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-transform-class-static-block@7.23.4(@babel/core@7.23.5): - resolution: {integrity: sha512-nsWu/1M+ggti1SOALj3hfx5FXzAY06fwPJsUZD4/A5e1bWi46VUIWtD+kOX6/IdhXGsXBWllLFDSnqSCdUNydQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.12.0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.23.5) - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.23.5) - dev: true - - /@babel/plugin-transform-classes@7.23.5(@babel/core@7.23.5): - resolution: {integrity: sha512-jvOTR4nicqYC9yzOHIhXG5emiFEOpappSJAl73SDSEDcybD+Puuze8Tnpb9p9qEyYup24tq891gkaygIFvWDqg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-compilation-targets': 7.22.15 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-function-name': 7.23.0 - '@babel/helper-optimise-call-expression': 7.22.5 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.5) - '@babel/helper-split-export-declaration': 7.22.6 - globals: 11.12.0 - dev: true - - /@babel/plugin-transform-computed-properties@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/template': 7.22.15 - dev: true - - /@babel/plugin-transform-destructuring@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-transform-dotall-regex@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.5) - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-transform-duplicate-keys@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-RrqQ+BQmU3Oyav3J+7/myfvRCq7Tbz+kKLLshUmMwNlDHExbGL7ARhajvoBJEvc+fCguPPu887N+3RRXBVKZUA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-transform-dynamic-import@7.23.4(@babel/core@7.23.5): - resolution: {integrity: sha512-V6jIbLhdJK86MaLh4Jpghi8ho5fGzt3imHOBu/x0jlBaPYqDoWz4RDXjmMOfnh+JWNaQleEAByZLV0QzBT4YQQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.23.5) - dev: true - - /@babel/plugin-transform-exponentiation-operator@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-builder-binary-assignment-operator-visitor': 7.22.15 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-transform-export-namespace-from@7.23.4(@babel/core@7.23.5): - resolution: {integrity: sha512-GzuSBcKkx62dGzZI1WVgTWvkkz84FZO5TC5T8dl/Tht/rAla6Dg/Mz9Yhypg+ezVACf/rgDuQt3kbWEv7LdUDQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.23.5) - dev: true - - /@babel/plugin-transform-for-of@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-X8jSm8X1CMwxmK878qsUGJRmbysKNbdpTv/O1/v0LuY/ZkZrng5WYiekYSdg9m09OTmDDUWeEDsTE+17WYbAZw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-transform-function-name@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-I1QXp1LxIvt8yLaib49dRW5Okt7Q4oaxao6tFVKS/anCdEOMtYwWVKoiOA1p34GOWIZjUK0E+zCp7+l1pfQyiw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-compilation-targets': 7.22.15 - '@babel/helper-function-name': 7.23.0 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-transform-json-strings@7.23.4(@babel/core@7.23.5): - resolution: {integrity: sha512-81nTOqM1dMwZ/aRXQ59zVubN9wHGqk6UtqRK+/q+ciXmRy8fSolhGVvG09HHRGo4l6fr/c4ZhXUQH0uFW7PZbg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.23.5) - dev: true - - /@babel/plugin-transform-literals@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-transform-logical-assignment-operators@7.23.4(@babel/core@7.23.5): - resolution: {integrity: sha512-Mc/ALf1rmZTP4JKKEhUwiORU+vcfarFVLfcFiolKUo6sewoxSEgl36ak5t+4WamRsNr6nzjZXQjM35WsU+9vbg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.23.5) - dev: true - - /@babel/plugin-transform-member-expression-literals@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-sC3LdDBDi5x96LA+Ytekz2ZPk8i/Ck+DEuDbRAll5rknJ5XRTSaPKEYwomLcs1AA8wg9b3KjIQRsnApj+q51Ag==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-transform-modules-amd@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.5) - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-transform-modules-commonjs@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.5) - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-simple-access': 7.22.5 - dev: true - - /@babel/plugin-transform-modules-systemjs@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-ZxyKGTkF9xT9YJuKQRo19ewf3pXpopuYQd8cDXqNzc3mUNbOME0RKMoZxviQk74hwzfQsEe66dE92MaZbdHKNQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-hoist-variables': 7.22.5 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.5) - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-validator-identifier': 7.22.20 - dev: true - - /@babel/plugin-transform-modules-umd@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.5) - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-transform-named-capturing-groups-regex@7.22.5(@babel/core@7.23.5): - resolution: {integrity: sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.5) - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-transform-new-target@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-transform-nullish-coalescing-operator@7.23.4(@babel/core@7.23.5): - resolution: {integrity: sha512-jHE9EVVqHKAQx+VePv5LLGHjmHSJR76vawFPTdlxR/LVJPfOEGxREQwQfjuZEOPTwG92X3LINSh3M40Rv4zpVA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.5) - dev: true - - /@babel/plugin-transform-numeric-separator@7.23.4(@babel/core@7.23.5): - resolution: {integrity: sha512-mps6auzgwjRrwKEZA05cOwuDc9FAzoyFS4ZsG/8F43bTLf/TgkJg7QXOrPO1JO599iA3qgK9MXdMGOEC8O1h6Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.5) - dev: true - - /@babel/plugin-transform-object-rest-spread@7.23.4(@babel/core@7.23.5): - resolution: {integrity: sha512-9x9K1YyeQVw0iOXJlIzwm8ltobIIv7j2iLyP2jIhEbqPRQ7ScNgwQufU2I0Gq11VjyG4gI4yMXt2VFags+1N3g==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/compat-data': 7.23.5 - '@babel/core': 7.23.5 - '@babel/helper-compilation-targets': 7.22.15 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.5) - '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.23.5) - dev: true - - /@babel/plugin-transform-object-super@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.5) - dev: true - - /@babel/plugin-transform-optional-catch-binding@7.23.4(@babel/core@7.23.5): - resolution: {integrity: sha512-XIq8t0rJPHf6Wvmbn9nFxU6ao4c7WhghTR5WyV8SrJfUFzyxhCm4nhC+iAp3HFhbAKLfYpgzhJ6t4XCtVwqO5A==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.5) - dev: true - - /@babel/plugin-transform-optional-chaining@7.23.4(@babel/core@7.23.5): - resolution: {integrity: sha512-ZU8y5zWOfjM5vZ+asjgAPwDaBjJzgufjES89Rs4Lpq63O300R/kOz30WCLo6BxxX6QVEilwSlpClnG5cZaikTA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.5) - dev: true - - /@babel/plugin-transform-parameters@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-transform-private-methods@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-UzqRcRtWsDMTLrRWFvUBDwmw06tCQH9Rl1uAjfh6ijMSmGYQ+fpdB+cnqRC8EMh5tuuxSv0/TejGL+7vyj+50g==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.23.5) - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-transform-private-property-in-object@7.23.4(@babel/core@7.23.5): - resolution: {integrity: sha512-9G3K1YqTq3F4Vt88Djx1UZ79PDyj+yKRnUy7cZGSMe+a7jkwD259uKKuUzQlPkGam7R+8RJwh5z4xO27fA1o2A==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.23.5) - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.23.5) - dev: true - - /@babel/plugin-transform-property-literals@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-transform-react-jsx-self@7.22.5(@babel/core@7.22.11): - resolution: {integrity: sha512-nTh2ogNUtxbiSbxaT4Ds6aXnXEipHweN9YRgOX/oNXdf0cCrGn/+2LozFa3lnPV5D90MkjhgckCPBrsoSc1a7g==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-transform-react-jsx-source@7.22.5(@babel/core@7.22.11): - resolution: {integrity: sha512-yIiRO6yobeEIaI0RTbIr8iAK9FcBHLtZq0S89ZPjDLQXBA4xvghaKqI0etp/tF3htTM0sazJKKLz9oEiGRtu7w==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-transform-regenerator@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - regenerator-transform: 0.15.2 - dev: true - - /@babel/plugin-transform-reserved-words@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-transform-shorthand-properties@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-transform-spread@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - dev: true - - /@babel/plugin-transform-sticky-regex@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-transform-template-literals@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-transform-typeof-symbol@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-transform-unicode-escapes@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-transform-unicode-property-regex@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-KcLIm+pDZkWZQAFJ9pdfmh89EwVfmNovFBcXko8szpBeF8z68kWIPeKlmSOkT9BXJxs2C0uk+5LxoxIv62MROA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.5) - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-transform-unicode-regex@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.5) - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-transform-unicode-sets-regex@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-W7lliA/v9bNR83Qc3q1ip9CQMZ09CcHDbHfbLRDNuAhn1Mvkr1ZNF7hPmztMQvtTGVLJ9m8IZqWsTkXOml8dbw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.5) - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/preset-env@7.23.5(@babel/core@7.23.5): - resolution: {integrity: sha512-0d/uxVD6tFGWXGDSfyMD1p2otoaKmu6+GD+NfAx0tMaH+dxORnp7T9TaVQ6mKyya7iBtCIVxHjWT7MuzzM9z+A==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/compat-data': 7.23.5 - '@babel/core': 7.23.5 - '@babel/helper-compilation-targets': 7.22.15 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-validator-option': 7.23.5 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.23.3(@babel/core@7.23.5) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.23.3(@babel/core@7.23.5) - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.23.3(@babel/core@7.23.5) - '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.23.5) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.5) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.23.5) - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.23.5) - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.23.5) - '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.23.5) - '@babel/plugin-syntax-import-assertions': 7.23.3(@babel/core@7.23.5) - '@babel/plugin-syntax-import-attributes': 7.23.3(@babel/core@7.23.5) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.23.5) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.23.5) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.23.5) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.5) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.5) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.5) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.5) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.5) - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.23.5) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.23.5) - '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.23.5) - '@babel/plugin-transform-arrow-functions': 7.23.3(@babel/core@7.23.5) - '@babel/plugin-transform-async-generator-functions': 7.23.4(@babel/core@7.23.5) - '@babel/plugin-transform-async-to-generator': 7.23.3(@babel/core@7.23.5) - '@babel/plugin-transform-block-scoped-functions': 7.23.3(@babel/core@7.23.5) - '@babel/plugin-transform-block-scoping': 7.23.4(@babel/core@7.23.5) - '@babel/plugin-transform-class-properties': 7.23.3(@babel/core@7.23.5) - '@babel/plugin-transform-class-static-block': 7.23.4(@babel/core@7.23.5) - '@babel/plugin-transform-classes': 7.23.5(@babel/core@7.23.5) - '@babel/plugin-transform-computed-properties': 7.23.3(@babel/core@7.23.5) - '@babel/plugin-transform-destructuring': 7.23.3(@babel/core@7.23.5) - '@babel/plugin-transform-dotall-regex': 7.23.3(@babel/core@7.23.5) - '@babel/plugin-transform-duplicate-keys': 7.23.3(@babel/core@7.23.5) - '@babel/plugin-transform-dynamic-import': 7.23.4(@babel/core@7.23.5) - '@babel/plugin-transform-exponentiation-operator': 7.23.3(@babel/core@7.23.5) - '@babel/plugin-transform-export-namespace-from': 7.23.4(@babel/core@7.23.5) - '@babel/plugin-transform-for-of': 7.23.3(@babel/core@7.23.5) - '@babel/plugin-transform-function-name': 7.23.3(@babel/core@7.23.5) - '@babel/plugin-transform-json-strings': 7.23.4(@babel/core@7.23.5) - '@babel/plugin-transform-literals': 7.23.3(@babel/core@7.23.5) - '@babel/plugin-transform-logical-assignment-operators': 7.23.4(@babel/core@7.23.5) - '@babel/plugin-transform-member-expression-literals': 7.23.3(@babel/core@7.23.5) - '@babel/plugin-transform-modules-amd': 7.23.3(@babel/core@7.23.5) - '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.23.5) - '@babel/plugin-transform-modules-systemjs': 7.23.3(@babel/core@7.23.5) - '@babel/plugin-transform-modules-umd': 7.23.3(@babel/core@7.23.5) - '@babel/plugin-transform-named-capturing-groups-regex': 7.22.5(@babel/core@7.23.5) - '@babel/plugin-transform-new-target': 7.23.3(@babel/core@7.23.5) - '@babel/plugin-transform-nullish-coalescing-operator': 7.23.4(@babel/core@7.23.5) - '@babel/plugin-transform-numeric-separator': 7.23.4(@babel/core@7.23.5) - '@babel/plugin-transform-object-rest-spread': 7.23.4(@babel/core@7.23.5) - '@babel/plugin-transform-object-super': 7.23.3(@babel/core@7.23.5) - '@babel/plugin-transform-optional-catch-binding': 7.23.4(@babel/core@7.23.5) - '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.23.5) - '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.23.5) - '@babel/plugin-transform-private-methods': 7.23.3(@babel/core@7.23.5) - '@babel/plugin-transform-private-property-in-object': 7.23.4(@babel/core@7.23.5) - '@babel/plugin-transform-property-literals': 7.23.3(@babel/core@7.23.5) - '@babel/plugin-transform-regenerator': 7.23.3(@babel/core@7.23.5) - '@babel/plugin-transform-reserved-words': 7.23.3(@babel/core@7.23.5) - '@babel/plugin-transform-shorthand-properties': 7.23.3(@babel/core@7.23.5) - '@babel/plugin-transform-spread': 7.23.3(@babel/core@7.23.5) - '@babel/plugin-transform-sticky-regex': 7.23.3(@babel/core@7.23.5) - '@babel/plugin-transform-template-literals': 7.23.3(@babel/core@7.23.5) - '@babel/plugin-transform-typeof-symbol': 7.23.3(@babel/core@7.23.5) - '@babel/plugin-transform-unicode-escapes': 7.23.3(@babel/core@7.23.5) - '@babel/plugin-transform-unicode-property-regex': 7.23.3(@babel/core@7.23.5) - '@babel/plugin-transform-unicode-regex': 7.23.3(@babel/core@7.23.5) - '@babel/plugin-transform-unicode-sets-regex': 7.23.3(@babel/core@7.23.5) - '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.23.5) - babel-plugin-polyfill-corejs2: 0.4.6(@babel/core@7.23.5) - babel-plugin-polyfill-corejs3: 0.8.6(@babel/core@7.23.5) - babel-plugin-polyfill-regenerator: 0.5.3(@babel/core@7.23.5) - core-js-compat: 3.33.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.23.5): - resolution: {integrity: sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==} - peerDependencies: - '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/types': 7.23.5 - esutils: 2.0.3 - dev: true - - /@babel/regjsgen@0.8.0: - resolution: {integrity: sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==} - dev: true - - /@babel/runtime@7.0.0-beta.42: - resolution: {integrity: sha512-iOGRzUoONLOtmCvjUsZv3mZzgCT6ljHQY5fr1qG1QIiJQwtM7zbPWGGpa3QWETq+UqwWyJnoi5XZDZRwZDFciQ==} - dependencies: - core-js: 2.6.12 - regenerator-runtime: 0.11.1 - dev: false - - /@babel/runtime@7.0.0-beta.56: - resolution: {integrity: sha512-vP9XV2VP013UEyZdU9eWClCsm6rQPUYHVNCfmpcv5uKviW7mKmUZq71Y5cr5dYsFKfnGDxSo8h6plUGR60lwHg==} - dependencies: - regenerator-runtime: 0.12.1 - dev: false - - /@babel/runtime@7.0.0-rc.1: - resolution: {integrity: sha512-Nifv2kwP/nwR39cAOasNxzjYfpeuf/ZbZNtQz5eYxWTC9yHARU9wItFnAwz1GTZ62MU+AtSjzZPMbLK5Q9hmbg==} - dependencies: - regenerator-runtime: 0.12.1 - dev: false - - /@babel/runtime@7.22.11: - resolution: {integrity: sha512-ee7jVNlWN09+KftVOu9n7S8gQzD/Z6hN/I8VBRXW4P1+Xe7kJGXMwu8vds4aGIMHZnNbdpSWCfZZtinytpcAvA==} - engines: {node: '>=6.9.0'} - dependencies: - regenerator-runtime: 0.14.0 - - /@babel/runtime@7.23.5: - resolution: {integrity: sha512-NdUTHcPe4C99WxPub+K9l9tK5/lV4UXIoaHSYgzco9BCyjKAAwzdBI+wWtYqHt7LJdbo74ZjRPJgzVweq1sz0w==} - engines: {node: '>=6.9.0'} - dependencies: - regenerator-runtime: 0.14.0 - - /@babel/template@7.22.15: - resolution: {integrity: sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.23.5 - '@babel/parser': 7.23.5 - '@babel/types': 7.23.5 - dev: true - - /@babel/template@7.22.5: - resolution: {integrity: sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.22.10 - '@babel/parser': 7.22.11 - '@babel/types': 7.22.11 - dev: true - - /@babel/traverse@7.22.11: - resolution: {integrity: sha512-mzAenteTfomcB7mfPtyi+4oe5BZ6MXxWcn4CX+h4IRJ+OOGXBrWU6jDQavkQI9Vuc5P+donFabBfFCcmWka9lQ==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.22.10 - '@babel/generator': 7.22.10 - '@babel/helper-environment-visitor': 7.22.5 - '@babel/helper-function-name': 7.22.5 - '@babel/helper-hoist-variables': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 - '@babel/parser': 7.22.11 - '@babel/types': 7.22.11 - debug: 4.3.4 - globals: 11.12.0 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/traverse@7.23.5: - resolution: {integrity: sha512-czx7Xy5a6sapWWRx61m1Ke1Ra4vczu1mCTtJam5zRTBOonfdJ+S/B6HYmGYu3fJtr8GGET3si6IhgWVBhJ/m8w==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.23.5 - '@babel/generator': 7.23.5 - '@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.5 - '@babel/types': 7.23.5 - debug: 4.3.4 - globals: 11.12.0 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/types@7.22.11: - resolution: {integrity: sha512-siazHiGuZRz9aB9NpHy9GOs9xiQPKnMzgdr493iI1M67vRXpnEq8ZOOKzezC5q7zwuQ6sDhdSp4SD9ixKSqKZg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-string-parser': 7.22.5 - '@babel/helper-validator-identifier': 7.22.5 - to-fast-properties: 2.0.0 - dev: true - - /@babel/types@7.23.5: - resolution: {integrity: sha512-ON5kSOJwVO6xXVRTvOI0eOnWe7VdUcIpsovGo9U/Br4Ie4UVFQTboO2cYnDhAGU6Fp+UxSiT+pMft0SMHfuq6w==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-string-parser': 7.23.4 - '@babel/helper-validator-identifier': 7.22.20 - to-fast-properties: 2.0.0 - dev: true - - /@bcoe/v8-coverage@0.2.3: - resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} - dev: true - - /@commaai/my-comma-auth@1.4.1: - resolution: {integrity: sha512-74hSXZ3Bp9YhGkhIK3WvXTDuK+rh9qWoUm2UkiMW4wNmDQWxStNkKU/vLOLsrwLueikDZ1NdY6Diw67DJVXqEA==} - dependencies: - babel-runtime: 6.26.0 - localforage: 1.10.0 - querystringify: 2.2.0 - dev: false - - /@esbuild/android-arm64@0.18.20: - resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@esbuild/android-arm@0.18.20: - resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} - engines: {node: '>=12'} - cpu: [arm] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@esbuild/android-x64@0.18.20: - resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@esbuild/darwin-arm64@0.18.20: - resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@esbuild/darwin-x64@0.18.20: - resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@esbuild/freebsd-arm64@0.18.20: - resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/freebsd-x64@0.18.20: - resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-arm64@0.18.20: - resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-arm@0.18.20: - resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-ia32@0.18.20: - resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-loong64@0.18.20: - resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-mips64el@0.18.20: - resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-ppc64@0.18.20: - resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-riscv64@0.18.20: - resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-s390x@0.18.20: - resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-x64@0.18.20: - resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/netbsd-x64@0.18.20: - resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/openbsd-x64@0.18.20: - resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/sunos-x64@0.18.20: - resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - requiresBuild: true - dev: true - optional: true - - /@esbuild/win32-arm64@0.18.20: - resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@esbuild/win32-ia32@0.18.20: - resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@esbuild/win32-x64@0.18.20: - resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@eslint-community/eslint-utils@4.4.0(eslint@8.48.0): - resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - dependencies: - eslint: 8.48.0 - eslint-visitor-keys: 3.4.3 - dev: true - - /@eslint-community/regexpp@4.8.0: - resolution: {integrity: sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - dev: true - - /@eslint/eslintrc@2.1.2: - resolution: {integrity: sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - ajv: 6.12.6 - debug: 4.3.4 - espree: 9.6.1 - globals: 13.21.0 - ignore: 5.2.4 - import-fresh: 3.3.0 - js-yaml: 4.1.0 - minimatch: 3.1.2 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - dev: true - - /@eslint/js@8.48.0: - resolution: {integrity: sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true - - /@hapi/hoek@9.3.0: - resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} - dev: true - - /@hapi/topo@5.1.0: - resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==} - dependencies: - '@hapi/hoek': 9.3.0 - dev: true - - /@humanwhocodes/config-array@0.11.10: - resolution: {integrity: sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==} - engines: {node: '>=10.10.0'} - dependencies: - '@humanwhocodes/object-schema': 1.2.1 - debug: 4.3.4 - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color - dev: true - - /@humanwhocodes/module-importer@1.0.1: - resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} - engines: {node: '>=12.22'} - dev: true - - /@humanwhocodes/object-schema@1.2.1: - resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} - dev: true - - /@istanbuljs/load-nyc-config@1.1.0: - resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} - engines: {node: '>=8'} - dependencies: - camelcase: 5.3.1 - find-up: 4.1.0 - get-package-type: 0.1.0 - js-yaml: 3.14.1 - resolve-from: 5.0.0 - dev: true - - /@istanbuljs/schema@0.1.3: - resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} - engines: {node: '>=8'} - dev: true - - /@jest/console@27.5.1: - resolution: {integrity: sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@jest/types': 27.5.1 - '@types/node': 20.5.6 - chalk: 4.1.2 - jest-message-util: 27.5.1 - jest-util: 27.5.1 - slash: 3.0.0 - dev: true - - /@jest/core@27.5.1: - resolution: {integrity: sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - dependencies: - '@jest/console': 27.5.1 - '@jest/reporters': 27.5.1 - '@jest/test-result': 27.5.1 - '@jest/transform': 27.5.1 - '@jest/types': 27.5.1 - '@types/node': 20.5.6 - ansi-escapes: 4.3.2 - chalk: 4.1.2 - emittery: 0.8.1 - exit: 0.1.2 - graceful-fs: 4.2.11 - jest-changed-files: 27.5.1 - jest-config: 27.5.1 - jest-haste-map: 27.5.1 - jest-message-util: 27.5.1 - jest-regex-util: 27.5.1 - jest-resolve: 27.5.1 - jest-resolve-dependencies: 27.5.1 - jest-runner: 27.5.1 - jest-runtime: 27.5.1 - jest-snapshot: 27.5.1 - jest-util: 27.5.1 - jest-validate: 27.5.1 - jest-watcher: 27.5.1 - micromatch: 4.0.5 - rimraf: 3.0.2 - slash: 3.0.0 - strip-ansi: 6.0.1 - transitivePeerDependencies: - - bufferutil - - canvas - - supports-color - - ts-node - - utf-8-validate - dev: true - - /@jest/create-cache-key-function@27.5.1: - resolution: {integrity: sha512-dmH1yW+makpTSURTy8VzdUwFnfQh1G8R+DxO2Ho2FFmBbKFEVm+3jWdvFhE2VqB/LATCTokkP0dotjyQyw5/AQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@jest/types': 27.5.1 - dev: true - - /@jest/environment@27.5.1: - resolution: {integrity: sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@jest/fake-timers': 27.5.1 - '@jest/types': 27.5.1 - '@types/node': 20.5.6 - jest-mock: 27.5.1 - dev: true - - /@jest/expect-utils@29.6.4: - resolution: {integrity: sha512-FEhkJhqtvBwgSpiTrocquJCdXPsyvNKcl/n7A3u7X4pVoF4bswm11c9d4AV+kfq2Gpv/mM8x7E7DsRvH+djkrg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - jest-get-type: 29.6.3 - dev: true - - /@jest/fake-timers@27.5.1: - resolution: {integrity: sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@jest/types': 27.5.1 - '@sinonjs/fake-timers': 8.1.0 - '@types/node': 20.5.6 - jest-message-util: 27.5.1 - jest-mock: 27.5.1 - jest-util: 27.5.1 - dev: true - - /@jest/globals@27.5.1: - resolution: {integrity: sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@jest/environment': 27.5.1 - '@jest/types': 27.5.1 - expect: 27.5.1 - dev: true - - /@jest/reporters@27.5.1: - resolution: {integrity: sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - dependencies: - '@bcoe/v8-coverage': 0.2.3 - '@jest/console': 27.5.1 - '@jest/test-result': 27.5.1 - '@jest/transform': 27.5.1 - '@jest/types': 27.5.1 - '@types/node': 20.5.6 - chalk: 4.1.2 - collect-v8-coverage: 1.0.2 - exit: 0.1.2 - glob: 7.2.3 - graceful-fs: 4.2.11 - istanbul-lib-coverage: 3.2.0 - istanbul-lib-instrument: 5.2.1 - istanbul-lib-report: 3.0.1 - istanbul-lib-source-maps: 4.0.1 - istanbul-reports: 3.1.6 - jest-haste-map: 27.5.1 - jest-resolve: 27.5.1 - jest-util: 27.5.1 - jest-worker: 27.5.1 - slash: 3.0.0 - source-map: 0.6.1 - string-length: 4.0.2 - terminal-link: 2.1.1 - v8-to-istanbul: 8.1.1 - transitivePeerDependencies: - - supports-color - dev: true - - /@jest/schemas@29.6.3: - resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@sinclair/typebox': 0.27.8 - dev: true - - /@jest/source-map@27.5.1: - resolution: {integrity: sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - callsites: 3.1.0 - graceful-fs: 4.2.11 - source-map: 0.6.1 - dev: true - - /@jest/test-result@27.5.1: - resolution: {integrity: sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@jest/console': 27.5.1 - '@jest/types': 27.5.1 - '@types/istanbul-lib-coverage': 2.0.4 - collect-v8-coverage: 1.0.2 - dev: true - - /@jest/test-sequencer@27.5.1: - resolution: {integrity: sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@jest/test-result': 27.5.1 - graceful-fs: 4.2.11 - jest-haste-map: 27.5.1 - jest-runtime: 27.5.1 - transitivePeerDependencies: - - supports-color - dev: true - - /@jest/transform@27.5.1: - resolution: {integrity: sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@babel/core': 7.22.11 - '@jest/types': 27.5.1 - babel-plugin-istanbul: 6.1.1 - chalk: 4.1.2 - convert-source-map: 1.9.0 - fast-json-stable-stringify: 2.1.0 - graceful-fs: 4.2.11 - jest-haste-map: 27.5.1 - jest-regex-util: 27.5.1 - jest-util: 27.5.1 - micromatch: 4.0.5 - pirates: 4.0.6 - slash: 3.0.0 - source-map: 0.6.1 - write-file-atomic: 3.0.3 - transitivePeerDependencies: - - supports-color - dev: true - - /@jest/types@27.5.1: - resolution: {integrity: sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@types/istanbul-lib-coverage': 2.0.4 - '@types/istanbul-reports': 3.0.1 - '@types/node': 20.5.6 - '@types/yargs': 16.0.5 - chalk: 4.1.2 - dev: true - - /@jest/types@29.6.3: - resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/schemas': 29.6.3 - '@types/istanbul-lib-coverage': 2.0.4 - '@types/istanbul-reports': 3.0.1 - '@types/node': 20.5.6 - '@types/yargs': 17.0.24 - chalk: 4.1.2 - dev: true - - /@jridgewell/gen-mapping@0.3.3: - resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} - engines: {node: '>=6.0.0'} - dependencies: - '@jridgewell/set-array': 1.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 - '@jridgewell/trace-mapping': 0.3.19 - dev: true - - /@jridgewell/resolve-uri@3.1.1: - resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} - engines: {node: '>=6.0.0'} - dev: true - - /@jridgewell/set-array@1.1.2: - resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} - engines: {node: '>=6.0.0'} - dev: true - - /@jridgewell/source-map@0.3.5: - resolution: {integrity: sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==} - dependencies: - '@jridgewell/gen-mapping': 0.3.3 - '@jridgewell/trace-mapping': 0.3.20 - dev: true - - /@jridgewell/sourcemap-codec@1.4.15: - resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} - - /@jridgewell/trace-mapping@0.3.19: - resolution: {integrity: sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==} - dependencies: - '@jridgewell/resolve-uri': 3.1.1 - '@jridgewell/sourcemap-codec': 1.4.15 - dev: true - - /@jridgewell/trace-mapping@0.3.20: - resolution: {integrity: sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==} - dependencies: - '@jridgewell/resolve-uri': 3.1.1 - '@jridgewell/sourcemap-codec': 1.4.15 - dev: true - - /@mapbox/fusspot@0.4.0: - resolution: {integrity: sha512-6sys1vUlhNCqMvJOqPEPSi0jc9tg7aJ//oG1A16H3PXoIt9whtNngD7UzBHUVTH15zunR/vRvMtGNVsogm1KzA==} - dependencies: - is-plain-obj: 1.1.0 - xtend: 4.0.2 - dev: false - - /@mapbox/geojson-rewind@0.5.2: - resolution: {integrity: sha512-tJaT+RbYGJYStt7wI3cq4Nl4SXxG8W7JDG5DMJu97V25RnbNg3QtQtf+KD+VLjNpWKYsRvXDNmNrBgEETr1ifA==} - hasBin: true - dependencies: - get-stream: 6.0.1 - minimist: 1.2.8 - dev: false - - /@mapbox/geojson-types@1.0.2: - resolution: {integrity: sha512-e9EBqHHv3EORHrSfbR9DqecPNn+AmuAoQxV6aL8Xu30bJMJR1o8PZLZzpk1Wq7/NfCbuhmakHTPYRhoqLsXRnw==} - dev: false - - /@mapbox/jsonlint-lines-primitives@2.0.2: - resolution: {integrity: sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==} - engines: {node: '>= 0.6'} - dev: false - - /@mapbox/mapbox-gl-supported@1.5.0(mapbox-gl@1.13.3): - resolution: {integrity: sha512-/PT1P6DNf7vjEEiPkVIRJkvibbqWtqnyGaBz3nfRdcxclNSnSdaLU5tfAgcD7I8Yt5i+L19s406YLl1koLnLbg==} - peerDependencies: - mapbox-gl: '>=0.32.1 <2.0.0' - dependencies: - mapbox-gl: 1.13.3 - dev: false - - /@mapbox/mapbox-sdk@0.15.3: - resolution: {integrity: sha512-axkdkWzSnH5Nky6plqS1jZc5W4txWQimA3iF1CbYVQYuR1tBZZwe8JcWVB8Lw8y06VuYQLQ7SQscyZagdczUJg==} - engines: {node: '>=6'} - dependencies: - '@mapbox/fusspot': 0.4.0 - '@mapbox/parse-mapbox-token': 0.2.0 - '@mapbox/polyline': 1.2.0 - eventemitter3: 3.1.2 - form-data: 3.0.1 - got: 11.8.6 - is-plain-obj: 1.1.0 - xtend: 4.0.2 - dev: false - - /@mapbox/parse-mapbox-token@0.2.0: - resolution: {integrity: sha512-BjeuG4sodYaoTygwXIuAWlZV6zUv4ZriYAQhXikzx+7DChycMUQ9g85E79Htat+AsBg+nStFALehlOhClYm5cQ==} - dependencies: - base-64: 0.1.0 - dev: false - - /@mapbox/point-geometry@0.1.0: - resolution: {integrity: sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==} - dev: false - - /@mapbox/polyline@1.2.0: - resolution: {integrity: sha512-sIIi9clVZiTmXYqbXpSAoG+ZLsvQn7j9FJLqiNOG85KnXN8tz11MEhuW2M7NDEDIKi4hIMaSI1CKwH8oLuVxPQ==} - hasBin: true - dependencies: - meow: 6.1.1 - dev: false - - /@mapbox/tiny-sdf@1.2.5: - resolution: {integrity: sha512-cD8A/zJlm6fdJOk6DqPUV8mcpyJkRz2x2R+/fYcWDYG3oWbG7/L7Yl/WqQ1VZCjnL9OTIMAn6c+BC5Eru4sQEw==} - dev: false - - /@mapbox/unitbezier@0.0.0: - resolution: {integrity: sha512-HPnRdYO0WjFjRTSwO3frz1wKaU649OBFPX3Zo/2WZvuRi6zMiRGui8SnPQiQABgqCf8YikDe5t3HViTVw1WUzA==} - dev: false - - /@mapbox/vector-tile@1.3.1: - resolution: {integrity: sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw==} - dependencies: - '@mapbox/point-geometry': 0.1.0 - dev: false - - /@mapbox/whoots-js@3.1.0: - resolution: {integrity: sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==} - engines: {node: '>=6.0.0'} - dev: false - - /@material-ui/core@1.5.1(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-hGT0JelWZGZqgWZzRbON/uqFCgWa4XhmEFG/IEd9SBwCU4sWC99Kv1KpywLhYYWecobqT4Dh7ijO1ZaIAk8HyA==} - engines: {node: '>=6.0.0'} - deprecated: Material UI v4 doesn't receive active development since September 2021. See the guide https://mui.com/material-ui/migration/migration-v4/ to upgrade to v5. - peerDependencies: - react: ^16.3.0 - react-dom: ^16.3.0 - dependencies: - '@babel/runtime': 7.0.0-rc.1 - '@types/jss': 9.5.8 - '@types/react-transition-group': 2.9.2 - brcast: 3.0.2 - classnames: 2.3.2 - csstype: 2.6.21 - debounce: 1.2.1 - deepmerge: 2.2.1 - dom-helpers: 3.4.0 - hoist-non-react-statics: 2.5.5 - is-plain-object: 2.0.4 - jss: 9.8.7 - jss-camel-case: 6.1.0(jss@9.8.7) - jss-default-unit: 8.0.2(jss@9.8.7) - jss-global: 3.0.0(jss@9.8.7) - jss-nested: 6.0.1(jss@9.8.7) - jss-props-sort: 6.0.0(jss@9.8.7) - jss-vendor-prefixer: 7.0.0(jss@9.8.7) - keycode: 2.2.1 - normalize-scroll-left: 0.1.2 - popper.js: 1.16.1 - prop-types: 15.8.1 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - react-event-listener: 0.6.6(react@18.2.0) - react-jss: 8.6.1(react@18.2.0) - react-transition-group: 2.9.0(react-dom@18.2.0)(react@18.2.0) - recompose: 0.28.2(react@18.2.0) - warning: 4.0.3 - dev: false - - /@material-ui/icons@1.1.1(@material-ui/core@1.5.1)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-d7I2P1Td4S/1zMAYCIrVQVf+6NUZC5fcIuo0wTrKe/mKxYo9eQ+83lPesI9aBAh+ZTQTjPTqoIvm0WD5e+0uKQ==} - engines: {node: '>=6.0.0'} - deprecated: 'You can now upgrade to @mui/icons. See the guide: https://mui.com/guides/migration-v4/' - peerDependencies: - '@material-ui/core': ^1.0.0 - react: ^16.3.0 - react-dom: ^16.3.0 - dependencies: - '@babel/runtime': 7.0.0-beta.42 - '@material-ui/core': 1.5.1(react-dom@18.2.0)(react@18.2.0) - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - recompose: 0.27.1(react@18.2.0) - dev: false - - /@math.gl/web-mercator@3.6.3: - resolution: {integrity: sha512-UVrkSOs02YLehKaehrxhAejYMurehIHPfFQvPFZmdJHglHOU4V2cCUApTVEwOksvCp161ypEqVp+9H6mGhTTcw==} - dependencies: - '@babel/runtime': 7.23.5 - gl-matrix: 3.4.3 - dev: false - - /@nodelib/fs.scandir@2.1.5: - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 - dev: true - - /@nodelib/fs.stat@2.0.5: - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} - dev: true - - /@nodelib/fs.walk@1.2.8: - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.15.0 - dev: true - - /@puppeteer/browsers@0.5.0: - resolution: {integrity: sha512-Uw6oB7VvmPRLE4iKsjuOh8zgDabhNX67dzo8U/BB0f9527qx+4eeUs+korU98OhG5C4ubg7ufBgVi63XYwS6TQ==} - engines: {node: '>=14.1.0'} - hasBin: true - peerDependencies: - typescript: '>= 4.7.4' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - debug: 4.3.4 - extract-zip: 2.0.1 - https-proxy-agent: 5.0.1 - progress: 2.0.3 - proxy-from-env: 1.1.0 - tar-fs: 2.1.1 - unbzip2-stream: 1.4.3 - yargs: 17.7.1 - transitivePeerDependencies: - - supports-color - dev: true - - /@rollup/plugin-babel@5.3.1(@babel/core@7.23.5)(rollup@2.79.1): - resolution: {integrity: sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==} - engines: {node: '>= 10.0.0'} - peerDependencies: - '@babel/core': ^7.0.0 - '@types/babel__core': ^7.1.9 - rollup: ^1.20.0||^2.0.0 - peerDependenciesMeta: - '@types/babel__core': - optional: true - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-module-imports': 7.22.15 - '@rollup/pluginutils': 3.1.0(rollup@2.79.1) - rollup: 2.79.1 - dev: true - - /@rollup/plugin-node-resolve@11.2.1(rollup@2.79.1): - resolution: {integrity: sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==} - engines: {node: '>= 10.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0 - dependencies: - '@rollup/pluginutils': 3.1.0(rollup@2.79.1) - '@types/resolve': 1.17.1 - builtin-modules: 3.3.0 - deepmerge: 4.3.1 - is-module: 1.0.0 - resolve: 1.22.8 - rollup: 2.79.1 - dev: true - - /@rollup/plugin-replace@2.4.2(rollup@2.79.1): - resolution: {integrity: sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==} - peerDependencies: - rollup: ^1.20.0 || ^2.0.0 - dependencies: - '@rollup/pluginutils': 3.1.0(rollup@2.79.1) - magic-string: 0.25.9 - rollup: 2.79.1 - dev: true - - /@rollup/pluginutils@3.1.0(rollup@2.79.1): - resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==} - engines: {node: '>= 8.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0 - dependencies: - '@types/estree': 0.0.39 - estree-walker: 1.0.1 - picomatch: 2.3.1 - rollup: 2.79.1 - dev: true - - /@rollup/pluginutils@5.0.4(rollup@2.79.1): - resolution: {integrity: sha512-0KJnIoRI8A+a1dqOYLxH8vBf8bphDmty5QvIm2hqm7oFCFYKCAZWWd2hXgMibaPsNDhI0AtpYfQZJG47pt/k4g==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0 - peerDependenciesMeta: - rollup: - optional: true - dependencies: - '@types/estree': 1.0.1 - estree-walker: 2.0.2 - picomatch: 2.3.1 - rollup: 2.79.1 - dev: true - - /@sentry-internal/tracing@7.64.0: - resolution: {integrity: sha512-1XE8W6ki7hHyBvX9hfirnGkKDBKNq3bDJyXS86E0bYVDl94nvbRM9BD9DHsCFetqYkVm1yDGEK+6aUVs4CztoQ==} - engines: {node: '>=8'} - dependencies: - '@sentry/core': 7.64.0 - '@sentry/types': 7.64.0 - '@sentry/utils': 7.64.0 - tslib: 2.6.2 - dev: false - - /@sentry/browser@7.64.0: - resolution: {integrity: sha512-lB2IWUkZavEDclxfLBp554dY10ZNIEvlDZUWWathW+Ws2wRb6PNLtuPUNu12R7Q7z0xpkOLrM1kRNN0OdldgKA==} - engines: {node: '>=8'} - dependencies: - '@sentry-internal/tracing': 7.64.0 - '@sentry/core': 7.64.0 - '@sentry/replay': 7.64.0 - '@sentry/types': 7.64.0 - '@sentry/utils': 7.64.0 - tslib: 2.6.2 - dev: false - - /@sentry/bundler-plugin-core@2.7.0: - resolution: {integrity: sha512-ZxJG/DsRXJ9BMaKv+butL3TaiHsuuUy1bNkl56/FCbCt1rYuzltEPT2cBuuveieg66ZWtzerSF17QX3v6svtJQ==} - engines: {node: '>= 14'} - dependencies: - '@sentry/cli': 2.20.5 - '@sentry/node': 7.64.0 - '@sentry/utils': 7.64.0 - dotenv: 16.3.1 - find-up: 5.0.0 - glob: 9.3.2 - magic-string: 0.27.0 - unplugin: 1.0.1 - transitivePeerDependencies: - - encoding - - supports-color - dev: false - - /@sentry/cli@2.20.5: - resolution: {integrity: sha512-ZvWb86eF0QXH9C5Mbi87aUmr8SH848yEpXJmlM2AoBowpE9kKDnewCAKvyXUihojUFwCSEEjoJhrRMMgmCZqXA==} - engines: {node: '>= 10'} - hasBin: true - requiresBuild: true - dependencies: - https-proxy-agent: 5.0.1 - node-fetch: 2.7.0 - progress: 2.0.3 - proxy-from-env: 1.1.0 - which: 2.0.2 - transitivePeerDependencies: - - encoding - - supports-color - dev: false - - /@sentry/core@7.64.0: - resolution: {integrity: sha512-IzmEyl5sNG7NyEFiyFHEHC+sizsZp9MEw1+RJRLX6U5RITvcsEgcajSkHQFafaBPzRrcxZMdm47Cwhl212LXcw==} - engines: {node: '>=8'} - dependencies: - '@sentry/types': 7.64.0 - '@sentry/utils': 7.64.0 - tslib: 2.6.2 - dev: false - - /@sentry/node@7.64.0: - resolution: {integrity: sha512-wRi0uTnp1WSa83X2yLD49tV9QPzGh5e42IKdIDBiQ7lV9JhLILlyb34BZY1pq6p4dp35yDasDrP3C7ubn7wo6A==} - engines: {node: '>=8'} - dependencies: - '@sentry-internal/tracing': 7.64.0 - '@sentry/core': 7.64.0 - '@sentry/types': 7.64.0 - '@sentry/utils': 7.64.0 - cookie: 0.4.2 - https-proxy-agent: 5.0.1 - lru_map: 0.3.3 - tslib: 2.6.2 - transitivePeerDependencies: - - supports-color - dev: false - - /@sentry/react@7.64.0(react@18.2.0): - resolution: {integrity: sha512-wOyJUQi7OoT1q+F/fVVv1fzbyO4OYbTu6m1DliLOGQPGEHPBsgPc722smPIExd1/rAMK/FxOuNN5oNhubH8nhg==} - engines: {node: '>=8'} - peerDependencies: - react: 15.x || 16.x || 17.x || 18.x - dependencies: - '@sentry/browser': 7.64.0 - '@sentry/types': 7.64.0 - '@sentry/utils': 7.64.0 - hoist-non-react-statics: 3.3.2 - react: 18.2.0 - tslib: 2.6.2 - dev: false - - /@sentry/replay@7.64.0: - resolution: {integrity: sha512-alaMCZDZhaAVmEyiUnszZnvfdbiZx5MmtMTGrlDd7tYq3K5OA9prdLqqlmfIJYBfYtXF3lD0iZFphOZQD+4CIw==} - engines: {node: '>=12'} - dependencies: - '@sentry/core': 7.64.0 - '@sentry/types': 7.64.0 - '@sentry/utils': 7.64.0 - dev: false - - /@sentry/types@7.64.0: - resolution: {integrity: sha512-LqjQprWXjUFRmzIlUjyA+KL+38elgIYmAeoDrdyNVh8MK5IC1W2Lh1Q87b4yOiZeMiIhIVNBd7Ecoh2rodGrGA==} - engines: {node: '>=8'} - dev: false - - /@sentry/utils@7.64.0: - resolution: {integrity: sha512-HRlM1INzK66Gt+F4vCItiwGKAng4gqzCR4C5marsL3qv6SrKH98dQnCGYgXluSWaaa56h97FRQu7TxCk6jkSvQ==} - engines: {node: '>=8'} - dependencies: - '@sentry/types': 7.64.0 - tslib: 2.6.2 - dev: false - - /@sentry/vite-plugin@2.7.0: - resolution: {integrity: sha512-VDkKneqIV5ESg41iz0ODsTl4BXsd4C/PhLgkjES9TFzDcG9VcnbECCxosXZd7nDZB9EQZDIsKSEc29PzLl1JUQ==} - engines: {node: '>= 14'} - dependencies: - '@sentry/bundler-plugin-core': 2.7.0 - unplugin: 1.0.1 - transitivePeerDependencies: - - encoding - - supports-color - dev: false - - /@sideway/address@4.1.4: - resolution: {integrity: sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==} - dependencies: - '@hapi/hoek': 9.3.0 - dev: true - - /@sideway/formula@3.0.1: - resolution: {integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==} - dev: true - - /@sideway/pinpoint@2.0.0: - resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==} - dev: true - - /@sinclair/typebox@0.27.8: - resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} - dev: true - - /@sindresorhus/is@4.6.0: - resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} - engines: {node: '>=10'} - dev: false - - /@sinonjs/commons@1.8.6: - resolution: {integrity: sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==} - dependencies: - type-detect: 4.0.8 - dev: true - - /@sinonjs/fake-timers@8.1.0: - resolution: {integrity: sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==} - dependencies: - '@sinonjs/commons': 1.8.6 - dev: true - - /@surma/rollup-plugin-off-main-thread@2.2.3: - resolution: {integrity: sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==} - dependencies: - ejs: 3.1.9 - json5: 2.2.3 - magic-string: 0.25.9 - string.prototype.matchall: 4.0.10 - dev: true - - /@svgr/babel-plugin-add-jsx-attribute@7.0.0(@babel/core@7.22.11): - resolution: {integrity: sha512-khWbXesWIP9v8HuKCl2NU2HNAyqpSQ/vkIl36Nbn4HIwEYSRWL0H7Gs6idJdha2DkpFDWlsqMELvoCE8lfFY6Q==} - engines: {node: '>=14'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.22.11 - dev: true - - /@svgr/babel-plugin-remove-jsx-attribute@7.0.0(@babel/core@7.22.11): - resolution: {integrity: sha512-iiZaIvb3H/c7d3TH2HBeK91uI2rMhZNwnsIrvd7ZwGLkFw6mmunOCoVnjdYua662MqGFxlN9xTq4fv9hgR4VXQ==} - engines: {node: '>=14'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.22.11 - dev: true - - /@svgr/babel-plugin-remove-jsx-empty-expression@7.0.0(@babel/core@7.22.11): - resolution: {integrity: sha512-sQQmyo+qegBx8DfFc04PFmIO1FP1MHI1/QEpzcIcclo5OAISsOJPW76ZIs0bDyO/DBSJEa/tDa1W26pVtt0FRw==} - engines: {node: '>=14'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.22.11 - dev: true - - /@svgr/babel-plugin-replace-jsx-attribute-value@7.0.0(@babel/core@7.22.11): - resolution: {integrity: sha512-i6MaAqIZXDOJeikJuzocByBf8zO+meLwfQ/qMHIjCcvpnfvWf82PFvredEZElErB5glQFJa2KVKk8N2xV6tRRA==} - engines: {node: '>=14'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.22.11 - dev: true - - /@svgr/babel-plugin-svg-dynamic-title@7.0.0(@babel/core@7.22.11): - resolution: {integrity: sha512-BoVSh6ge3SLLpKC0pmmN9DFlqgFy4NxNgdZNLPNJWBUU7TQpDWeBuyVuDW88iXydb5Cv0ReC+ffa5h3VrKfk1w==} - engines: {node: '>=14'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.22.11 - dev: true - - /@svgr/babel-plugin-svg-em-dimensions@7.0.0(@babel/core@7.22.11): - resolution: {integrity: sha512-tNDcBa+hYn0gO+GkP/AuNKdVtMufVhU9fdzu+vUQsR18RIJ9RWe7h/pSBY338RO08wArntwbDk5WhQBmhf2PaA==} - engines: {node: '>=14'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.22.11 - dev: true - - /@svgr/babel-plugin-transform-react-native-svg@7.0.0(@babel/core@7.22.11): - resolution: {integrity: sha512-qw54u8ljCJYL2KtBOjI5z7Nzg8LnSvQOP5hPKj77H4VQL4+HdKbAT5pnkkZLmHKYwzsIHSYKXxHouD8zZamCFQ==} - engines: {node: '>=14'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.22.11 - dev: true - - /@svgr/babel-plugin-transform-svg-component@7.0.0(@babel/core@7.22.11): - resolution: {integrity: sha512-CcFECkDj98daOg9jE3Bh3uyD9kzevCAnZ+UtzG6+BQG/jOQ2OA3jHnX6iG4G1MCJkUQFnUvEv33NvQfqrb/F3A==} - engines: {node: '>=12'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.22.11 - dev: true - - /@svgr/babel-preset@7.0.0(@babel/core@7.22.11): - resolution: {integrity: sha512-EX/NHeFa30j5UjldQGVQikuuQNHUdGmbh9kEpBKofGUtF0GUPJ4T4rhoYiqDAOmBOxojyot36JIFiDUHUK1ilQ==} - engines: {node: '>=14'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.22.11 - '@svgr/babel-plugin-add-jsx-attribute': 7.0.0(@babel/core@7.22.11) - '@svgr/babel-plugin-remove-jsx-attribute': 7.0.0(@babel/core@7.22.11) - '@svgr/babel-plugin-remove-jsx-empty-expression': 7.0.0(@babel/core@7.22.11) - '@svgr/babel-plugin-replace-jsx-attribute-value': 7.0.0(@babel/core@7.22.11) - '@svgr/babel-plugin-svg-dynamic-title': 7.0.0(@babel/core@7.22.11) - '@svgr/babel-plugin-svg-em-dimensions': 7.0.0(@babel/core@7.22.11) - '@svgr/babel-plugin-transform-react-native-svg': 7.0.0(@babel/core@7.22.11) - '@svgr/babel-plugin-transform-svg-component': 7.0.0(@babel/core@7.22.11) - dev: true - - /@svgr/core@7.0.0: - resolution: {integrity: sha512-ztAoxkaKhRVloa3XydohgQQCb0/8x9T63yXovpmHzKMkHO6pkjdsIAWKOS4bE95P/2quVh1NtjSKlMRNzSBffw==} - engines: {node: '>=14'} - dependencies: - '@babel/core': 7.22.11 - '@svgr/babel-preset': 7.0.0(@babel/core@7.22.11) - camelcase: 6.3.0 - cosmiconfig: 8.2.0 - transitivePeerDependencies: - - supports-color - dev: true - - /@svgr/hast-util-to-babel-ast@7.0.0: - resolution: {integrity: sha512-42Ej9sDDEmsJKjrfQ1PHmiDiHagh/u9AHO9QWbeNx4KmD9yS5d1XHmXUNINfUcykAU+4431Cn+k6Vn5mWBYimQ==} - engines: {node: '>=14'} - dependencies: - '@babel/types': 7.22.11 - entities: 4.5.0 - dev: true - - /@svgr/plugin-jsx@7.0.0: - resolution: {integrity: sha512-SWlTpPQmBUtLKxXWgpv8syzqIU8XgFRvyhfkam2So8b3BE0OS0HPe5UfmlJ2KIC+a7dpuuYovPR2WAQuSyMoPw==} - engines: {node: '>=14'} - dependencies: - '@babel/core': 7.22.11 - '@svgr/babel-preset': 7.0.0(@babel/core@7.22.11) - '@svgr/hast-util-to-babel-ast': 7.0.0 - svg-parser: 2.0.4 - transitivePeerDependencies: - - supports-color - dev: true - - /@swc/core-darwin-arm64@1.3.80: - resolution: {integrity: sha512-rhoFTcQMUGfO7IkfOnopPSF6O0/aVJ58B7KueIKbvrMe6YvSfFj9QfObELFjYCcrJZTvUWBhig0QrsfPIiUphA==} - engines: {node: '>=10'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@swc/core-darwin-x64@1.3.80: - resolution: {integrity: sha512-0dOLedFpVXe+ugkKHXsqSxMKqvQYfFtibWbrZ7j8wOaErzSGPr0VpyWvepNVb9s046725kPXSw+fsGhqZR8wrw==} - engines: {node: '>=10'} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@swc/core-linux-arm-gnueabihf@1.3.80: - resolution: {integrity: sha512-QIjwP3PtDeHBDkwF6+ZZqdUsqAhORbMpxrw2jq3mHe4lQrxBttSFTq018vlMRo2mFEorOvXdadzaD9m+NymPrw==} - engines: {node: '>=10'} - cpu: [arm] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@swc/core-linux-arm64-gnu@1.3.80: - resolution: {integrity: sha512-cg8WriIueab58ZwkzXmIACnjSzFLzOBwxlC9k65gPXMNgCjab2YbqEYvAbjBqneuqaao02gW6tad2uhjgYaExw==} - engines: {node: '>=10'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@swc/core-linux-arm64-musl@1.3.80: - resolution: {integrity: sha512-AhdCQ7QKx5mWrtpaOA1mFRiWWvuiiUtspvo0QSpspDetRKTND1rlf/3UB5+gp0kCeCNUTsVmJWU7fIA9ICZtXA==} - engines: {node: '>=10'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@swc/core-linux-x64-gnu@1.3.80: - resolution: {integrity: sha512-+2e5oni1vOrLIjM5Q2/GIzK/uS2YEtuJqnjPvCK8SciRJsSl8OgVsRvyCDbmKeZNtJ2Q+o/O2AQ2w1qpAJG6jg==} - engines: {node: '>=10'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@swc/core-linux-x64-musl@1.3.80: - resolution: {integrity: sha512-8OK9IlI1zpWOm7vIp1iXmZSEzLAwFpqhsGSEhxPavpOx2m54kLFdPcw/Uv3n461f6TCtszIxkGq1kSqBUdfUBA==} - engines: {node: '>=10'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@swc/core-win32-arm64-msvc@1.3.80: - resolution: {integrity: sha512-RKhatwiAGlffnF6z2Mm3Ddid0v3KB+uf5m/Gc7N9zO/EUAV0PnHRuYuZSGyqodHmGFC+mK8YrCooFCEmHL9n+w==} - engines: {node: '>=10'} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@swc/core-win32-ia32-msvc@1.3.80: - resolution: {integrity: sha512-3jiiZzU/kaw7k4zUp1yMq1QiUe4wJVtCEXIhf+fKuBsIwm7rdvyK/+PIx5KHnZy4TGQnYczKBRhJA5nuBcrUCQ==} - engines: {node: '>=10'} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@swc/core-win32-x64-msvc@1.3.80: - resolution: {integrity: sha512-2eZtIoIWQBWqykfms92Zd37lveYOBWQTZjdooBGlsLHtcoQLkNpf1NXmR6TKY0yy8q6Yl3OhPvY+izjmO08MSg==} - engines: {node: '>=10'} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@swc/core@1.3.80: - resolution: {integrity: sha512-yX2xV5I/lYswHHR+44TPvzBgq3/Y8N1YWpTQADYuvSiX3Jxyvemk5Jpx3rRtigYb8WBkWAAf2i5d5ZJ2M7hhgw==} - engines: {node: '>=10'} - requiresBuild: true - peerDependencies: - '@swc/helpers': ^0.5.0 - peerDependenciesMeta: - '@swc/helpers': - optional: true - dependencies: - '@swc/types': 0.1.6 - optionalDependencies: - '@swc/core-darwin-arm64': 1.3.80 - '@swc/core-darwin-x64': 1.3.80 - '@swc/core-linux-arm-gnueabihf': 1.3.80 - '@swc/core-linux-arm64-gnu': 1.3.80 - '@swc/core-linux-arm64-musl': 1.3.80 - '@swc/core-linux-x64-gnu': 1.3.80 - '@swc/core-linux-x64-musl': 1.3.80 - '@swc/core-win32-arm64-msvc': 1.3.80 - '@swc/core-win32-ia32-msvc': 1.3.80 - '@swc/core-win32-x64-msvc': 1.3.80 - dev: true - - /@swc/counter@0.1.3: - resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} - dev: true - - /@swc/jest@0.2.29(@swc/core@1.3.80): - resolution: {integrity: sha512-8reh5RvHBsSikDC3WGCd5ZTd2BXKkyOdK7QwynrCH58jk2cQFhhHhFBg/jvnWZehUQe/EoOImLENc9/DwbBFow==} - engines: {npm: '>= 7.0.0'} - peerDependencies: - '@swc/core': '*' - dependencies: - '@jest/create-cache-key-function': 27.5.1 - '@swc/core': 1.3.80 - jsonc-parser: 3.2.1 - dev: true - - /@swc/types@0.1.6: - resolution: {integrity: sha512-/JLo/l2JsT/LRd80C3HfbmVpxOAJ11FO2RCEslFrgzLltoP9j8XIbsyDcfCt2WWyX+CM96rBoNM+IToAkFOugg==} - dependencies: - '@swc/counter': 0.1.3 - dev: true - - /@szmarczak/http-timer@4.0.6: - resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} - engines: {node: '>=10'} - dependencies: - defer-to-connect: 2.0.1 - dev: false - - /@tailwindcss/typography@0.5.9(tailwindcss@3.3.3): - resolution: {integrity: sha512-t8Sg3DyynFysV9f4JDOVISGsjazNb48AeIYQwcL+Bsq5uf4RYL75C1giZ43KISjeDGBaTN3Kxh7Xj/vRSMJUUg==} - peerDependencies: - tailwindcss: '>=3.0.0 || insiders' - dependencies: - lodash.castarray: 4.4.0 - lodash.isplainobject: 4.0.6 - lodash.merge: 4.6.2 - postcss-selector-parser: 6.0.10 - tailwindcss: 3.3.3 - dev: true - - /@testing-library/dom@8.20.1: - resolution: {integrity: sha512-/DiOQ5xBxgdYRC8LNk7U+RWat0S3qRLeIw3ZIkMQ9kkVlRmwD/Eg8k8CqIpD6GW7u20JIUOfMKbxtiLutpjQ4g==} - engines: {node: '>=12'} - dependencies: - '@babel/code-frame': 7.22.10 - '@babel/runtime': 7.23.5 - '@types/aria-query': 5.0.1 - aria-query: 5.1.3 - chalk: 4.1.2 - dom-accessibility-api: 0.5.16 - lz-string: 1.5.0 - pretty-format: 27.5.1 - dev: true - - /@testing-library/jest-dom@5.17.0: - resolution: {integrity: sha512-ynmNeT7asXyH3aSVv4vvX4Rb+0qjOhdNHnO/3vuZNqPmhDpV/+rCSGwQ7bLcmU2cJ4dvoheIO85LQj0IbJHEtg==} - engines: {node: '>=8', npm: '>=6', yarn: '>=1'} - dependencies: - '@adobe/css-tools': 4.3.2 - '@babel/runtime': 7.22.11 - '@types/testing-library__jest-dom': 5.14.9 - aria-query: 5.3.0 - chalk: 3.0.0 - css.escape: 1.5.1 - dom-accessibility-api: 0.5.16 - lodash: 4.17.21 - redent: 3.0.0 - dev: true - - /@testing-library/react@13.4.0(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-sXOGON+WNTh3MLE9rve97ftaZukN3oNf2KjDy7YTx6hcTO2uuLHuCGynMDhFwGw/jYf4OJ2Qk0i4i79qMNNkyw==} - engines: {node: '>=12'} - peerDependencies: - react: ^18.0.0 - react-dom: ^18.0.0 - dependencies: - '@babel/runtime': 7.22.11 - '@testing-library/dom': 8.20.1 - '@types/react-dom': 18.2.7 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: true - - /@tootallnate/once@1.1.2: - resolution: {integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==} - engines: {node: '>= 6'} - dev: true - - /@types/aria-query@5.0.1: - resolution: {integrity: sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==} - dev: true - - /@types/babel__core@7.20.1: - resolution: {integrity: sha512-aACu/U/omhdk15O4Nfb+fHgH/z3QsfQzpnvRZhYhThms83ZnAOZz7zZAWO7mn2yyNQaA4xTO8GLK3uqFU4bYYw==} - dependencies: - '@babel/parser': 7.22.11 - '@babel/types': 7.22.11 - '@types/babel__generator': 7.6.4 - '@types/babel__template': 7.4.1 - '@types/babel__traverse': 7.20.1 - dev: true - - /@types/babel__generator@7.6.4: - resolution: {integrity: sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==} - dependencies: - '@babel/types': 7.22.11 - dev: true - - /@types/babel__template@7.4.1: - resolution: {integrity: sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==} - dependencies: - '@babel/parser': 7.22.11 - '@babel/types': 7.22.11 - dev: true - - /@types/babel__traverse@7.20.1: - resolution: {integrity: sha512-MitHFXnhtgwsGZWtT68URpOvLN4EREih1u3QtQiN4VdAxWKRVvGCSvw/Qth0M0Qq3pJpnGOu5JaM/ydK7OGbqg==} - dependencies: - '@babel/types': 7.22.11 - dev: true - - /@types/cacheable-request@6.0.3: - resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==} - dependencies: - '@types/http-cache-semantics': 4.0.1 - '@types/keyv': 3.1.4 - '@types/node': 20.5.6 - '@types/responselike': 1.0.0 - dev: false - - /@types/estree@0.0.39: - resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==} - dev: true - - /@types/estree@1.0.1: - resolution: {integrity: sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==} - dev: true - - /@types/geojson@7946.0.10: - resolution: {integrity: sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA==} - dev: false - - /@types/graceful-fs@4.1.6: - resolution: {integrity: sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==} - dependencies: - '@types/node': 20.5.6 - dev: true - - /@types/hammerjs@2.0.41: - resolution: {integrity: sha512-ewXv/ceBaJprikMcxCmWU1FKyMAQ2X7a9Gtmzw8fcg2kIePI1crERDM818W+XYrxqdBBOdlf2rm137bU+BltCA==} - dev: false - - /@types/http-cache-semantics@4.0.1: - resolution: {integrity: sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==} - dev: false - - /@types/istanbul-lib-coverage@2.0.4: - resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==} - dev: true - - /@types/istanbul-lib-report@3.0.0: - resolution: {integrity: sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==} - dependencies: - '@types/istanbul-lib-coverage': 2.0.4 - dev: true - - /@types/istanbul-reports@3.0.1: - resolution: {integrity: sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==} - dependencies: - '@types/istanbul-lib-report': 3.0.0 - dev: true - - /@types/jest@29.5.4: - resolution: {integrity: sha512-PhglGmhWeD46FYOVLt3X7TiWjzwuVGW9wG/4qocPevXMjCmrIc5b6db9WjeGE4QYVpUAWMDv3v0IiBwObY289A==} - dependencies: - expect: 29.6.4 - pretty-format: 29.6.3 - dev: true - - /@types/json5@0.0.29: - resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} - dev: true - - /@types/jss@9.5.8: - resolution: {integrity: sha512-bBbHvjhm42UKki+wZpR89j73ykSXg99/bhuKuYYePtpma3ZAnmeGnl0WxXiZhPGsIfzKwCUkpPC0jlrVMBfRxA==} - dependencies: - csstype: 2.6.21 - indefinite-observable: 1.0.2 - dev: false - - /@types/keyv@3.1.4: - resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} - dependencies: - '@types/node': 20.5.6 - dev: false - - /@types/mapbox-gl@2.7.13: - resolution: {integrity: sha512-qNffhTdYkeFl8QG9Q1zPPJmcs8PvHgmLa1PcwP1rxvcfMsIgcFr/FnrCttG0ZnH7Kzdd7xfECSRNTWSr4jC3PQ==} - dependencies: - '@types/geojson': 7946.0.10 - dev: false - - /@types/minimist@1.2.2: - resolution: {integrity: sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==} - dev: false - - /@types/node@20.10.1: - resolution: {integrity: sha512-T2qwhjWwGH81vUEx4EXmBKsTJRXFXNZTL4v0gi01+zyBmCwzE6TyHszqX01m+QHTEq+EZNo13NeJIdEqf+Myrg==} - dependencies: - undici-types: 5.26.5 - dev: true - - /@types/node@20.5.6: - resolution: {integrity: sha512-Gi5wRGPbbyOTX+4Y2iULQ27oUPrefaB0PxGQJnfyWN3kvEDGM3mIB5M/gQLmitZf7A9FmLeaqxD3L1CXpm3VKQ==} - - /@types/normalize-package-data@2.4.1: - resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==} - dev: false - - /@types/offscreencanvas@2019.7.0: - resolution: {integrity: sha512-PGcyveRIpL1XIqK8eBsmRBt76eFgtzuPiSTyKHZxnGemp2yzGzWpjYKAfK3wIMiU7eH+851yEpiuP8JZerTmWg==} - dev: false - - /@types/prettier@2.7.3: - resolution: {integrity: sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==} - dev: true - - /@types/prop-types@15.7.5: - resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==} - - /@types/react-dom@18.2.7: - resolution: {integrity: sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA==} - dependencies: - '@types/react': 18.2.21 - dev: true - - /@types/react-transition-group@2.9.2: - resolution: {integrity: sha512-5Fv2DQNO+GpdPZcxp2x/OQG/H19A01WlmpjVD9cKvVFmoVLOZ9LvBgSWG6pSXIU4og5fgbvGPaCV5+VGkWAEHA==} - dependencies: - '@types/react': 18.2.21 - dev: false - - /@types/react@18.2.21: - resolution: {integrity: sha512-neFKG/sBAwGxHgXiIxnbm3/AAVQ/cMRS93hvBpg8xYRbeQSPVABp9U2bRnPf0iI4+Ucdv3plSxKK+3CW2ENJxA==} - dependencies: - '@types/prop-types': 15.7.5 - '@types/scheduler': 0.16.3 - csstype: 3.1.2 - - /@types/resolve@1.17.1: - resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==} - dependencies: - '@types/node': 20.10.1 - dev: true - - /@types/responselike@1.0.0: - resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==} - dependencies: - '@types/node': 20.5.6 - dev: false - - /@types/scheduler@0.16.3: - resolution: {integrity: sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==} - - /@types/stack-utils@2.0.1: - resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==} - dev: true - - /@types/testing-library__jest-dom@5.14.9: - resolution: {integrity: sha512-FSYhIjFlfOpGSRyVoMBMuS3ws5ehFQODymf3vlI7U1K8c7PHwWwFY7VREfmsuzHSOnoKs/9/Y983ayOs7eRzqw==} - dependencies: - '@types/jest': 29.5.4 - dev: true - - /@types/trusted-types@2.0.3: - resolution: {integrity: sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g==} - dev: true - - /@types/yargs-parser@21.0.0: - resolution: {integrity: sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==} - dev: true - - /@types/yargs@16.0.5: - resolution: {integrity: sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==} - dependencies: - '@types/yargs-parser': 21.0.0 - dev: true - - /@types/yargs@17.0.24: - resolution: {integrity: sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==} - dependencies: - '@types/yargs-parser': 21.0.0 - dev: true - - /@types/yauzl@2.10.3: - resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} - requiresBuild: true - dependencies: - '@types/node': 20.5.6 - dev: true - optional: true - - /@vitejs/plugin-react@4.0.4(vite@4.5.3): - resolution: {integrity: sha512-7wU921ABnNYkETiMaZy7XqpueMnpu5VxvVps13MjmCo+utBdD79sZzrApHawHtVX66cCJQQTXFcjH0y9dSUK8g==} - engines: {node: ^14.18.0 || >=16.0.0} - peerDependencies: - vite: ^4.2.0 - dependencies: - '@babel/core': 7.22.11 - '@babel/plugin-transform-react-jsx-self': 7.22.5(@babel/core@7.22.11) - '@babel/plugin-transform-react-jsx-source': 7.22.5(@babel/core@7.22.11) - react-refresh: 0.14.0 - vite: 4.5.3 - transitivePeerDependencies: - - supports-color - dev: true - - /abab@2.0.6: - resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} - dev: true - - /acorn-globals@6.0.0: - resolution: {integrity: sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==} - dependencies: - acorn: 7.4.1 - acorn-walk: 7.2.0 - dev: true - - /acorn-jsx@5.3.2(acorn@8.10.0): - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - dependencies: - acorn: 8.10.0 - dev: true - - /acorn-walk@7.2.0: - resolution: {integrity: sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==} - engines: {node: '>=0.4.0'} - dev: true - - /acorn@7.4.1: - resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} - engines: {node: '>=0.4.0'} - hasBin: true - dev: true - - /acorn@8.10.0: - resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==} - engines: {node: '>=0.4.0'} - hasBin: true - - /acorn@8.11.2: - resolution: {integrity: sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==} - engines: {node: '>=0.4.0'} - hasBin: true - dev: true - - /agent-base@6.0.2: - resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} - engines: {node: '>= 6.0.0'} - dependencies: - debug: 4.3.4 - transitivePeerDependencies: - - supports-color - - /ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} - dependencies: - fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - dev: true - - /ajv@8.12.0: - resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} - dependencies: - fast-deep-equal: 3.1.3 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - uri-js: 4.4.1 - dev: true - - /ansi-escapes@4.3.2: - resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} - engines: {node: '>=8'} - dependencies: - type-fest: 0.21.3 - dev: true - - /ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - dev: true - - /ansi-styles@3.2.1: - resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} - engines: {node: '>=4'} - dependencies: - color-convert: 1.9.3 - - /ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - dependencies: - color-convert: 2.0.1 - dev: true - - /ansi-styles@5.2.0: - resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} - engines: {node: '>=10'} - dev: true - - /any-promise@1.3.0: - resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} - dev: true - - /anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} - dependencies: - normalize-path: 3.0.0 - picomatch: 2.3.1 - - /ap@0.2.0: - resolution: {integrity: sha512-ImdvquIuBSVpWRWhB441UjvTcZqic1RL+lTQaUKGdGEp1aiTvt/phAvY8Vvs32qya5FJBI8U+tzNBYzFDQY/lQ==} - dev: false - - /arg@5.0.2: - resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} - dev: true - - /argparse@1.0.10: - resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} - dependencies: - sprintf-js: 1.0.3 - dev: true - - /argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - dev: true - - /aria-query@5.1.3: - resolution: {integrity: sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==} - dependencies: - deep-equal: 2.2.2 - dev: true - - /aria-query@5.3.0: - resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} - dependencies: - dequal: 2.0.3 - dev: true - - /arr-union@3.1.0: - resolution: {integrity: sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==} - engines: {node: '>=0.10.0'} - dev: true - - /array-buffer-byte-length@1.0.0: - resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==} - dependencies: - call-bind: 1.0.2 - is-array-buffer: 3.0.2 - dev: true - - /array-includes@3.1.6: - resolution: {integrity: sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.22.1 - get-intrinsic: 1.2.1 - is-string: 1.0.7 - dev: true - - /array.prototype.findlastindex@1.2.2: - resolution: {integrity: sha512-tb5thFFlUcp7NdNF6/MpDk/1r/4awWG1FIz3YqDf+/zJSTezBb+/5WViH41obXULHVpDzoiCLpJ/ZO9YbJMsdw==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.22.1 - es-shim-unscopables: 1.0.0 - get-intrinsic: 1.2.1 - dev: true - - /array.prototype.flat@1.3.1: - resolution: {integrity: sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.22.1 - es-shim-unscopables: 1.0.0 - dev: true - - /array.prototype.flatmap@1.3.1: - resolution: {integrity: sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.22.1 - es-shim-unscopables: 1.0.0 - dev: true - - /array.prototype.tosorted@1.1.1: - resolution: {integrity: sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==} - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.22.1 - es-shim-unscopables: 1.0.0 - get-intrinsic: 1.2.1 - dev: true - - /arraybuffer.prototype.slice@1.0.1: - resolution: {integrity: sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw==} - engines: {node: '>= 0.4'} - dependencies: - array-buffer-byte-length: 1.0.0 - call-bind: 1.0.2 - define-properties: 1.2.0 - get-intrinsic: 1.2.1 - is-array-buffer: 3.0.2 - is-shared-array-buffer: 1.0.2 - dev: true - - /arraybuffer.prototype.slice@1.0.2: - resolution: {integrity: sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==} - engines: {node: '>= 0.4'} - dependencies: - array-buffer-byte-length: 1.0.0 - call-bind: 1.0.5 - define-properties: 1.2.1 - es-abstract: 1.22.3 - get-intrinsic: 1.2.2 - is-array-buffer: 3.0.2 - is-shared-array-buffer: 1.0.2 - dev: true - - /arrify@1.0.1: - resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} - engines: {node: '>=0.10.0'} - dev: false - - /asap@2.0.6: - resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} - dev: false - - /async@3.2.5: - resolution: {integrity: sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==} - dev: true - - /asynciterator.prototype@1.0.0: - resolution: {integrity: sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==} - dependencies: - has-symbols: 1.0.3 - dev: true - - /asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - - /at-least-node@1.0.0: - resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} - engines: {node: '>= 4.0.0'} - dev: true - - /autoprefixer@10.4.15(postcss@8.4.28): - resolution: {integrity: sha512-KCuPB8ZCIqFdA4HwKXsvz7j6gvSDNhDP7WnUjBleRkKjPdvCmHFuQ77ocavI8FT6NdvlBnE2UFr2H4Mycn8Vew==} - engines: {node: ^10 || ^12 || >=14} - hasBin: true - peerDependencies: - postcss: ^8.1.0 - dependencies: - browserslist: 4.22.1 - caniuse-lite: 1.0.30001565 - fraction.js: 4.3.7 - normalize-range: 0.1.2 - picocolors: 1.0.0 - postcss: 8.4.28 - postcss-value-parser: 4.2.0 - dev: true - - /available-typed-arrays@1.0.5: - resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} - engines: {node: '>= 0.4'} - dev: true - - /axios@0.25.0: - resolution: {integrity: sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==} - dependencies: - follow-redirects: 1.15.6 - transitivePeerDependencies: - - debug - dev: true - - /babel-jest@27.5.1(@babel/core@7.22.11): - resolution: {integrity: sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - peerDependencies: - '@babel/core': ^7.8.0 - dependencies: - '@babel/core': 7.22.11 - '@jest/transform': 27.5.1 - '@jest/types': 27.5.1 - '@types/babel__core': 7.20.1 - babel-plugin-istanbul: 6.1.1 - babel-preset-jest: 27.5.1(@babel/core@7.22.11) - chalk: 4.1.2 - graceful-fs: 4.2.11 - slash: 3.0.0 - transitivePeerDependencies: - - supports-color - dev: true - - /babel-plugin-istanbul@6.1.1: - resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} - engines: {node: '>=8'} - dependencies: - '@babel/helper-plugin-utils': 7.22.5 - '@istanbuljs/load-nyc-config': 1.1.0 - '@istanbuljs/schema': 0.1.3 - istanbul-lib-instrument: 5.2.1 - test-exclude: 6.0.0 - transitivePeerDependencies: - - supports-color - dev: true - - /babel-plugin-jest-hoist@27.5.1: - resolution: {integrity: sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@babel/template': 7.22.5 - '@babel/types': 7.22.11 - '@types/babel__core': 7.20.1 - '@types/babel__traverse': 7.20.1 - dev: true - - /babel-plugin-polyfill-corejs2@0.4.6(@babel/core@7.23.5): - resolution: {integrity: sha512-jhHiWVZIlnPbEUKSSNb9YoWcQGdlTLq7z1GHL4AjFxaoOUMuuEVJ+Y4pAaQUGOGk93YsVCKPbqbfw3m0SM6H8Q==} - peerDependencies: - '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - dependencies: - '@babel/compat-data': 7.23.5 - '@babel/core': 7.23.5 - '@babel/helper-define-polyfill-provider': 0.4.3(@babel/core@7.23.5) - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - dev: true - - /babel-plugin-polyfill-corejs3@0.8.6(@babel/core@7.23.5): - resolution: {integrity: sha512-leDIc4l4tUgU7str5BWLS2h8q2N4Nf6lGZP6UrNDxdtfF2g69eJ5L0H7S8A5Ln/arfFAfHor5InAdZuIOwZdgQ==} - peerDependencies: - '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-define-polyfill-provider': 0.4.3(@babel/core@7.23.5) - core-js-compat: 3.33.3 - transitivePeerDependencies: - - supports-color - dev: true - - /babel-plugin-polyfill-regenerator@0.5.3(@babel/core@7.23.5): - resolution: {integrity: sha512-8sHeDOmXC8csczMrYEOf0UTNa4yE2SxV5JGeT/LP1n0OYVDUUFPxG9vdk2AlDlIit4t+Kf0xCtpgXPBwnn/9pw==} - peerDependencies: - '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - dependencies: - '@babel/core': 7.23.5 - '@babel/helper-define-polyfill-provider': 0.4.3(@babel/core@7.23.5) - transitivePeerDependencies: - - supports-color - dev: true - - /babel-preset-current-node-syntax@1.0.1(@babel/core@7.22.11): - resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.22.11 - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.22.11) - '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.22.11) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.22.11) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.22.11) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.22.11) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.22.11) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.22.11) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.22.11) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.22.11) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.22.11) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.22.11) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.22.11) - dev: true - - /babel-preset-jest@27.5.1(@babel/core@7.22.11): - resolution: {integrity: sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.22.11 - babel-plugin-jest-hoist: 27.5.1 - babel-preset-current-node-syntax: 1.0.1(@babel/core@7.22.11) - dev: true - - /babel-runtime@6.26.0: - resolution: {integrity: sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==} - dependencies: - core-js: 2.6.12 - regenerator-runtime: 0.11.1 - dev: false - - /balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - - /base-64@0.1.0: - resolution: {integrity: sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA==} - dev: false - - /base64-js@1.5.1: - resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - dev: true - - /binary-extensions@2.2.0: - resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} - engines: {node: '>=8'} - - /bl@4.1.0: - resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} - dependencies: - buffer: 5.7.1 - inherits: 2.0.4 - readable-stream: 3.6.2 - dev: true - - /brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - dev: true - - /brace-expansion@2.0.1: - resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} - dependencies: - balanced-match: 1.0.2 - - /braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} - dependencies: - fill-range: 7.1.1 - - /brcast@3.0.2: - resolution: {integrity: sha512-f5XwwFCCuvgqP2nMH/hJ74FqnGmb4X3D+NC//HphxJzzhsZvSZa+Hk/syB7j3ZHpPDLMoYU8oBgviRWfNvEfKA==} - dev: false - - /browser-process-hrtime@1.0.0: - resolution: {integrity: sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==} - dev: true - - /browserslist@4.22.1: - resolution: {integrity: sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - dependencies: - caniuse-lite: 1.0.30001565 - electron-to-chromium: 1.4.597 - node-releases: 2.0.13 - update-browserslist-db: 1.0.13(browserslist@4.22.1) - dev: true - - /bser@2.1.1: - resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} - dependencies: - node-int64: 0.4.0 - dev: true - - /buffer-crc32@0.2.13: - resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} - dev: true - - /buffer-from@1.1.2: - resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - dev: true - - /buffer@5.7.1: - resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - dev: true - - /builtin-modules@3.3.0: - resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} - engines: {node: '>=6'} - dev: true - - /cacheable-lookup@5.0.4: - resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==} - engines: {node: '>=10.6.0'} - dev: false - - /cacheable-request@7.0.4: - resolution: {integrity: sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==} - engines: {node: '>=8'} - dependencies: - clone-response: 1.0.3 - get-stream: 5.2.0 - http-cache-semantics: 4.1.1 - keyv: 4.5.3 - lowercase-keys: 2.0.0 - normalize-url: 6.1.0 - responselike: 2.0.1 - dev: false - - /call-bind@1.0.2: - resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} - dependencies: - function-bind: 1.1.1 - get-intrinsic: 1.2.1 - dev: true - - /call-bind@1.0.5: - resolution: {integrity: sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==} - dependencies: - function-bind: 1.1.2 - get-intrinsic: 1.2.2 - set-function-length: 1.1.1 - dev: true - - /callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - dev: true - - /camelcase-css@2.0.1: - resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} - engines: {node: '>= 6'} - dev: true - - /camelcase-keys@6.2.2: - resolution: {integrity: sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==} - engines: {node: '>=8'} - dependencies: - camelcase: 5.3.1 - map-obj: 4.3.0 - quick-lru: 4.0.1 - dev: false - - /camelcase@5.3.1: - resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} - engines: {node: '>=6'} - - /camelcase@6.3.0: - resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} - engines: {node: '>=10'} - dev: true - - /caniuse-lite@1.0.30001565: - resolution: {integrity: sha512-xrE//a3O7TP0vaJ8ikzkD2c2NgcVUvsEe2IvFTntV4Yd1Z9FVzh+gW+enX96L0psrbaFMcVcH2l90xNuGDWc8w==} - dev: true - - /chalk@2.4.2: - resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} - engines: {node: '>=4'} - dependencies: - ansi-styles: 3.2.1 - escape-string-regexp: 1.0.5 - supports-color: 5.5.0 - - /chalk@3.0.0: - resolution: {integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==} - engines: {node: '>=8'} - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - dev: true - - /chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - dev: true - - /change-emitter@0.1.6: - resolution: {integrity: sha512-YXzt1cQ4a2jqazhcuSWEOc1K2q8g9H6eWNsyZgi640LDzRWVQ2eDe+Y/kVdftH+vYdPF2rgDb3dLdpxE1jvAxw==} - dev: false - - /char-regex@1.0.2: - resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} - engines: {node: '>=10'} - dev: true - - /chokidar@3.5.3: - resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} - engines: {node: '>= 8.10.0'} - dependencies: - anymatch: 3.1.3 - braces: 3.0.3 - glob-parent: 5.1.2 - is-binary-path: 2.1.0 - is-glob: 4.0.3 - normalize-path: 3.0.0 - readdirp: 3.6.0 - optionalDependencies: - fsevents: 2.3.3 - - /chownr@1.1.4: - resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} - dev: true - - /chromium-bidi@0.4.7(devtools-protocol@0.0.1107588): - resolution: {integrity: sha512-6+mJuFXwTMU6I3vYLs6IL8A1DyQTPjCfIL971X0aMPVGRbGnNfl6i6Cl0NMbxi2bRYLGESt9T2ZIMRM5PAEcIQ==} - peerDependencies: - devtools-protocol: '*' - dependencies: - devtools-protocol: 0.0.1107588 - mitt: 3.0.0 - dev: true - - /ci-info@3.8.0: - resolution: {integrity: sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==} - engines: {node: '>=8'} - dev: true - - /cjs-module-lexer@1.2.3: - resolution: {integrity: sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==} - dev: true - - /classnames@2.3.2: - resolution: {integrity: sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==} - dev: false - - /cliui@7.0.4: - resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - dev: true - - /cliui@8.0.1: - resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} - engines: {node: '>=12'} - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - dev: true - - /clone-deep@0.2.4: - resolution: {integrity: sha512-we+NuQo2DHhSl+DP6jlUiAhyAjBQrYnpOk15rN6c6JSPScjiCLh8IbSU+VTcph6YS3o7mASE8a0+gbZ7ChLpgg==} - engines: {node: '>=0.10.0'} - dependencies: - for-own: 0.1.5 - is-plain-object: 2.0.4 - kind-of: 3.2.2 - lazy-cache: 1.0.4 - shallow-clone: 0.1.2 - dev: true - - /clone-response@1.0.3: - resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==} - dependencies: - mimic-response: 1.0.1 - dev: false - - /co@4.6.0: - resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} - engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} - dev: true - - /collect-v8-coverage@1.0.2: - resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} - dev: true - - /color-convert@1.9.3: - resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} - dependencies: - color-name: 1.1.3 - - /color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - dependencies: - color-name: 1.1.4 - dev: true - - /color-name@1.1.3: - resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} - - /color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - dev: true - - /combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} - dependencies: - delayed-stream: 1.0.0 - - /commander@2.20.3: - resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} - dev: true - - /commander@4.1.1: - resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} - engines: {node: '>= 6'} - dev: true - - /commander@5.1.0: - resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==} - engines: {node: '>= 6'} - dev: true - - /common-tags@1.8.2: - resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==} - engines: {node: '>=4.0.0'} - dev: true - - /concat-map@0.0.1: - resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} - dev: true - - /connected-react-router@4.5.0(react-redux@5.1.2)(react-router@5.3.4)(react@18.2.0)(redux@4.2.1): - resolution: {integrity: sha512-SBBmAZrtmw4y7Rkl2PCct8lN/DuCftl7QSAFLgFyjjuYkeJKAzAvQjzNNNE4R3j2+6a4TUiv8qselxQ4+6H5eA==} - peerDependencies: - react: ^15.5.4 || ^16.0.0 - react-redux: ^4.4.8 || ^5.0.7 - react-router: ^4.3.1 - redux: ^3.6.0 || ^4.0.0 - dependencies: - immutable: 3.8.2 - react: 18.2.0 - react-redux: 5.1.2(react@18.2.0)(redux@4.2.1) - react-router: 5.3.4(react@18.2.0) - redux: 4.2.1 - redux-seamless-immutable: 0.4.0 - seamless-immutable: 7.1.4 - dev: false - - /convert-source-map@1.9.0: - resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} - dev: true - - /convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - dev: true - - /cookie@0.4.2: - resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==} - engines: {node: '>= 0.6'} - dev: false - - /core-js-compat@3.33.3: - resolution: {integrity: sha512-cNzGqFsh3Ot+529GIXacjTJ7kegdt5fPXxCBVS1G0iaZpuo/tBz399ymceLJveQhFFZ8qThHiP3fzuoQjKN2ow==} - dependencies: - browserslist: 4.22.1 - dev: true - - /core-js@1.2.7: - resolution: {integrity: sha512-ZiPp9pZlgxpWRu0M+YWbm6+aQ84XEfH1JRXvfOc/fILWI0VKhLC2LX13X1NYq4fULzLMq7Hfh43CSo2/aIaUPA==} - deprecated: core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js. - dev: false - - /core-js@2.6.12: - resolution: {integrity: sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==} - deprecated: core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js. - requiresBuild: true - dev: false - - /cosmiconfig@8.1.3: - resolution: {integrity: sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw==} - engines: {node: '>=14'} - dependencies: - import-fresh: 3.3.0 - js-yaml: 4.1.0 - parse-json: 5.2.0 - path-type: 4.0.0 - dev: true - - /cosmiconfig@8.2.0: - resolution: {integrity: sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ==} - engines: {node: '>=14'} - dependencies: - import-fresh: 3.3.0 - js-yaml: 4.1.0 - parse-json: 5.2.0 - path-type: 4.0.0 - dev: true - - /cross-fetch@3.1.5: - resolution: {integrity: sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==} - dependencies: - node-fetch: 2.6.7 - transitivePeerDependencies: - - encoding - dev: true - - /cross-spawn@6.0.5: - resolution: {integrity: sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==} - engines: {node: '>=4.8'} - dependencies: - nice-try: 1.0.5 - path-key: 2.0.1 - semver: 5.7.2 - shebang-command: 1.2.0 - which: 1.3.1 - dev: true - - /cross-spawn@7.0.3: - resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} - engines: {node: '>= 8'} - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - dev: true - - /crypto-random-string@2.0.0: - resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} - engines: {node: '>=8'} - dev: true - - /css-vendor@0.3.8: - resolution: {integrity: sha512-Vx/Vl3zsHj32Z+WTNzGjd2iSbSIJTYHMmyGUT2nzCjj0Xk4qLfwpQ8nF6TQ5oo3Cf0s/An3DTc7LclH1BkAXbQ==} - dependencies: - is-in-browser: 1.1.3 - dev: false - - /css.escape@1.5.1: - resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==} - dev: true - - /csscolorparser@1.0.3: - resolution: {integrity: sha512-umPSgYwZkdFoUrH5hIq5kf0wPSXiro51nPw0j2K/c83KflkPSTBGMz6NJvMB+07VlL0y7VPo6QJcDjcgKTTm3w==} - dev: false - - /cssesc@3.0.0: - resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} - engines: {node: '>=4'} - hasBin: true - dev: true - - /cssom@0.3.8: - resolution: {integrity: sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==} - dev: true - - /cssom@0.4.4: - resolution: {integrity: sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==} - dev: true - - /cssstyle@2.3.0: - resolution: {integrity: sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==} - engines: {node: '>=8'} - dependencies: - cssom: 0.3.8 - dev: true - - /csstype@2.6.21: - resolution: {integrity: sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==} - dev: false - - /csstype@3.1.2: - resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} - - /cwd@0.10.0: - resolution: {integrity: sha512-YGZxdTTL9lmLkCUTpg4j0zQ7IhRB5ZmqNBbGCl3Tg6MP/d5/6sY7L5mmTjzbc6JKgVZYiqTQTNhPFsbXNGlRaA==} - engines: {node: '>=0.8'} - dependencies: - find-pkg: 0.1.2 - fs-exists-sync: 0.1.0 - dev: true - - /data-urls@2.0.0: - resolution: {integrity: sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==} - engines: {node: '>=10'} - dependencies: - abab: 2.0.6 - whatwg-mimetype: 2.3.0 - whatwg-url: 8.7.0 - dev: true - - /dayjs@1.11.9: - resolution: {integrity: sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA==} - dev: false - - /debounce@1.2.1: - resolution: {integrity: sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==} - dev: false - - /debug@3.2.7: - resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.1.3 - dev: true - - /debug@4.3.4: - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.1.2 - - /decamelize-keys@1.1.1: - resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==} - engines: {node: '>=0.10.0'} - dependencies: - decamelize: 1.2.0 - map-obj: 1.0.1 - dev: false - - /decamelize@1.2.0: - resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} - engines: {node: '>=0.10.0'} - dev: false - - /decimal.js@10.4.3: - resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} - dev: true - - /decode-uri-component@0.2.2: - resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} - engines: {node: '>=0.10'} - dev: false - - /decompress-response@6.0.0: - resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} - engines: {node: '>=10'} - dependencies: - mimic-response: 3.1.0 - dev: false - - /dedent@0.7.0: - resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==} - dev: true - - /deep-equal@2.2.2: - resolution: {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.11 - dev: true - - /deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - dev: true - - /deepmerge@2.2.1: - resolution: {integrity: sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==} - engines: {node: '>=0.10.0'} - dev: false - - /deepmerge@4.3.1: - resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} - engines: {node: '>=0.10.0'} - - /defer-to-connect@2.0.1: - resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} - engines: {node: '>=10'} - dev: false - - /define-data-property@1.1.1: - resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==} - engines: {node: '>= 0.4'} - dependencies: - get-intrinsic: 1.2.2 - gopd: 1.0.1 - has-property-descriptors: 1.0.1 - dev: true - - /define-properties@1.2.0: - resolution: {integrity: sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==} - engines: {node: '>= 0.4'} - dependencies: - has-property-descriptors: 1.0.0 - object-keys: 1.1.1 - dev: true - - /define-properties@1.2.1: - resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} - engines: {node: '>= 0.4'} - dependencies: - define-data-property: 1.1.1 - has-property-descriptors: 1.0.1 - object-keys: 1.1.1 - dev: true - - /delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} - - /dequal@2.0.3: - resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} - engines: {node: '>=6'} - dev: true - - /detect-newline@3.1.0: - resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} - engines: {node: '>=8'} - dev: true - - /devtools-protocol@0.0.1107588: - resolution: {integrity: sha512-yIR+pG9x65Xko7bErCUSQaDLrO/P1p3JUzEk7JCU4DowPcGHkTGUGQapcfcLc4qj0UaALwZ+cr0riFgiqpixcg==} - dev: true - - /didyoumean@1.2.2: - resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} - dev: true - - /diff-sequences@27.5.1: - resolution: {integrity: sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dev: true - - /diff-sequences@29.6.3: - resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dev: true - - /dlv@1.1.3: - resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} - dev: true - - /doctrine@2.1.0: - resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} - engines: {node: '>=0.10.0'} - dependencies: - esutils: 2.0.3 - dev: true - - /doctrine@3.0.0: - resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} - engines: {node: '>=6.0.0'} - dependencies: - esutils: 2.0.3 - dev: true - - /dom-accessibility-api@0.5.16: - resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} - dev: true - - /dom-helpers@3.4.0: - resolution: {integrity: sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==} - dependencies: - '@babel/runtime': 7.23.5 - dev: false - - /dom-walk@0.1.2: - resolution: {integrity: sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==} - dev: false - - /domexception@2.0.1: - resolution: {integrity: sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==} - engines: {node: '>=8'} - dependencies: - webidl-conversions: 5.0.0 - dev: true - - /dot-prop@2.1.0: - resolution: {integrity: sha512-ZrQHU2Oq0PbVb5lu5YitVJnpfC5HfWo+0lQnDK5TO4ipbzC1EiEYh/qDCu4j+7v6MDBgBfwTdFiznMSNPZXD7Q==} - engines: {node: '>=0.10.0'} - dev: false - - /dotenv@16.3.1: - resolution: {integrity: sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==} - engines: {node: '>=12'} - dev: false - - /earcut@2.2.4: - resolution: {integrity: sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==} - dev: false - - /ejs@3.1.9: - resolution: {integrity: sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==} - engines: {node: '>=0.10.0'} - hasBin: true - dependencies: - jake: 10.8.7 - dev: true - - /electron-to-chromium@1.4.597: - resolution: {integrity: sha512-0XOQNqHhg2YgRVRUrS4M4vWjFCFIP2ETXcXe/0KIQBjXE9Cpy+tgzzYfuq6HGai3hWq0YywtG+5XK8fyG08EjA==} - dev: true - - /emittery@0.8.1: - resolution: {integrity: sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==} - engines: {node: '>=10'} - dev: true - - /emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - dev: true - - /encoding@0.1.13: - resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} - dependencies: - iconv-lite: 0.6.3 - dev: false - - /end-of-stream@1.4.4: - resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} - dependencies: - once: 1.4.0 - - /entities@4.5.0: - resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} - engines: {node: '>=0.12'} - dev: true - - /env-cmd@8.0.2: - resolution: {integrity: sha512-gHX8MnQXw1iS7dc2KeJdBdxca7spIkxkNwIuORLwm8kDg6xHh5wWnv1Yv3pc64nLZR6kufQSCmwTz16sRmd/rg==} - engines: {node: '>=4.0.0'} - hasBin: true - dependencies: - cross-spawn: 6.0.5 - dev: true - - /error-ex@1.3.2: - resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} - dependencies: - is-arrayish: 0.2.1 - - /es-abstract@1.22.1: - resolution: {integrity: sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==} - engines: {node: '>= 0.4'} - dependencies: - array-buffer-byte-length: 1.0.0 - arraybuffer.prototype.slice: 1.0.1 - available-typed-arrays: 1.0.5 - call-bind: 1.0.2 - es-set-tostringtag: 2.0.1 - es-to-primitive: 1.2.1 - function.prototype.name: 1.1.5 - get-intrinsic: 1.2.1 - get-symbol-description: 1.0.0 - globalthis: 1.0.3 - gopd: 1.0.1 - has: 1.0.3 - has-property-descriptors: 1.0.0 - has-proto: 1.0.1 - has-symbols: 1.0.3 - internal-slot: 1.0.5 - is-array-buffer: 3.0.2 - is-callable: 1.2.7 - is-negative-zero: 2.0.2 - is-regex: 1.1.4 - is-shared-array-buffer: 1.0.2 - is-string: 1.0.7 - is-typed-array: 1.1.12 - is-weakref: 1.0.2 - object-inspect: 1.12.3 - object-keys: 1.1.1 - object.assign: 4.1.4 - regexp.prototype.flags: 1.5.0 - safe-array-concat: 1.0.0 - safe-regex-test: 1.0.0 - string.prototype.trim: 1.2.7 - string.prototype.trimend: 1.0.6 - string.prototype.trimstart: 1.0.6 - typed-array-buffer: 1.0.0 - typed-array-byte-length: 1.0.0 - typed-array-byte-offset: 1.0.0 - typed-array-length: 1.0.4 - unbox-primitive: 1.0.2 - which-typed-array: 1.1.11 - dev: true - - /es-abstract@1.22.3: - resolution: {integrity: sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==} - engines: {node: '>= 0.4'} - dependencies: - array-buffer-byte-length: 1.0.0 - arraybuffer.prototype.slice: 1.0.2 - available-typed-arrays: 1.0.5 - call-bind: 1.0.5 - es-set-tostringtag: 2.0.2 - es-to-primitive: 1.2.1 - function.prototype.name: 1.1.6 - get-intrinsic: 1.2.2 - get-symbol-description: 1.0.0 - globalthis: 1.0.3 - gopd: 1.0.1 - has-property-descriptors: 1.0.1 - has-proto: 1.0.1 - has-symbols: 1.0.3 - hasown: 2.0.0 - internal-slot: 1.0.6 - is-array-buffer: 3.0.2 - is-callable: 1.2.7 - is-negative-zero: 2.0.2 - is-regex: 1.1.4 - is-shared-array-buffer: 1.0.2 - is-string: 1.0.7 - is-typed-array: 1.1.12 - is-weakref: 1.0.2 - object-inspect: 1.13.1 - object-keys: 1.1.1 - object.assign: 4.1.4 - regexp.prototype.flags: 1.5.1 - safe-array-concat: 1.0.1 - safe-regex-test: 1.0.0 - string.prototype.trim: 1.2.8 - string.prototype.trimend: 1.0.7 - string.prototype.trimstart: 1.0.7 - typed-array-buffer: 1.0.0 - typed-array-byte-length: 1.0.0 - typed-array-byte-offset: 1.0.0 - typed-array-length: 1.0.4 - unbox-primitive: 1.0.2 - which-typed-array: 1.1.13 - dev: true - - /es-get-iterator@1.1.3: - resolution: {integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==} - dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 - 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 - dev: true - - /es-iterator-helpers@1.0.13: - resolution: {integrity: sha512-LK3VGwzvaPWobO8xzXXGRUOGw8Dcjyfk62CsY/wfHN75CwsJPbuypOYJxK6g5RyEL8YDjIWcl6jgd8foO6mmrA==} - dependencies: - asynciterator.prototype: 1.0.0 - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.22.1 - es-set-tostringtag: 2.0.1 - function-bind: 1.1.1 - get-intrinsic: 1.2.1 - globalthis: 1.0.3 - has-property-descriptors: 1.0.0 - has-proto: 1.0.1 - has-symbols: 1.0.3 - internal-slot: 1.0.5 - iterator.prototype: 1.1.0 - safe-array-concat: 1.0.0 - dev: true - - /es-set-tostringtag@2.0.1: - resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==} - engines: {node: '>= 0.4'} - dependencies: - get-intrinsic: 1.2.1 - has: 1.0.3 - has-tostringtag: 1.0.0 - dev: true - - /es-set-tostringtag@2.0.2: - resolution: {integrity: sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==} - engines: {node: '>= 0.4'} - dependencies: - get-intrinsic: 1.2.2 - has-tostringtag: 1.0.0 - hasown: 2.0.0 - dev: true - - /es-shim-unscopables@1.0.0: - resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==} - dependencies: - has: 1.0.3 - dev: true - - /es-to-primitive@1.2.1: - resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} - engines: {node: '>= 0.4'} - dependencies: - is-callable: 1.2.7 - is-date-object: 1.0.5 - is-symbol: 1.0.4 - dev: true - - /esbuild@0.18.20: - resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} - engines: {node: '>=12'} - hasBin: true - requiresBuild: true - optionalDependencies: - '@esbuild/android-arm': 0.18.20 - '@esbuild/android-arm64': 0.18.20 - '@esbuild/android-x64': 0.18.20 - '@esbuild/darwin-arm64': 0.18.20 - '@esbuild/darwin-x64': 0.18.20 - '@esbuild/freebsd-arm64': 0.18.20 - '@esbuild/freebsd-x64': 0.18.20 - '@esbuild/linux-arm': 0.18.20 - '@esbuild/linux-arm64': 0.18.20 - '@esbuild/linux-ia32': 0.18.20 - '@esbuild/linux-loong64': 0.18.20 - '@esbuild/linux-mips64el': 0.18.20 - '@esbuild/linux-ppc64': 0.18.20 - '@esbuild/linux-riscv64': 0.18.20 - '@esbuild/linux-s390x': 0.18.20 - '@esbuild/linux-x64': 0.18.20 - '@esbuild/netbsd-x64': 0.18.20 - '@esbuild/openbsd-x64': 0.18.20 - '@esbuild/sunos-x64': 0.18.20 - '@esbuild/win32-arm64': 0.18.20 - '@esbuild/win32-ia32': 0.18.20 - '@esbuild/win32-x64': 0.18.20 - dev: true - - /escalade@3.1.1: - resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} - engines: {node: '>=6'} - dev: true - - /escape-string-regexp@1.0.5: - resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} - engines: {node: '>=0.8.0'} - - /escape-string-regexp@2.0.0: - resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} - engines: {node: '>=8'} - dev: true - - /escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - dev: true - - /escodegen@2.1.0: - resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} - engines: {node: '>=6.0'} - hasBin: true - dependencies: - esprima: 4.0.1 - estraverse: 5.3.0 - esutils: 2.0.3 - optionalDependencies: - source-map: 0.6.1 - dev: true - - /eslint-import-resolver-node@0.3.9: - resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} - dependencies: - debug: 3.2.7 - is-core-module: 2.13.0 - resolve: 1.22.4 - transitivePeerDependencies: - - supports-color - dev: true - - /eslint-module-utils@2.8.0(eslint-import-resolver-node@0.3.9)(eslint@8.48.0): - resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: '*' - eslint-import-resolver-node: '*' - eslint-import-resolver-typescript: '*' - eslint-import-resolver-webpack: '*' - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - eslint: - optional: true - eslint-import-resolver-node: - optional: true - eslint-import-resolver-typescript: - optional: true - eslint-import-resolver-webpack: - optional: true - dependencies: - debug: 3.2.7 - eslint: 8.48.0 - eslint-import-resolver-node: 0.3.9 - transitivePeerDependencies: - - supports-color - dev: true - - /eslint-plugin-import@2.28.1(eslint@8.48.0): - resolution: {integrity: sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - dependencies: - array-includes: 3.1.6 - array.prototype.findlastindex: 1.2.2 - array.prototype.flat: 1.3.1 - array.prototype.flatmap: 1.3.1 - debug: 3.2.7 - doctrine: 2.1.0 - eslint: 8.48.0 - eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(eslint-import-resolver-node@0.3.9)(eslint@8.48.0) - has: 1.0.3 - is-core-module: 2.13.0 - is-glob: 4.0.3 - minimatch: 3.1.2 - object.fromentries: 2.0.6 - object.groupby: 1.0.0 - object.values: 1.1.6 - semver: 6.3.1 - tsconfig-paths: 3.14.2 - transitivePeerDependencies: - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - - supports-color - dev: true - - /eslint-plugin-jest-dom@5.1.0(eslint@8.48.0): - resolution: {integrity: sha512-JIXZp+E/h/aGlP/rQc4tuOejiHlZXg65qw8JAJMIJA5VsdjOkss/SYcRSqBrQuEOytEM8JvngUjcz31d1RrCrA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0, npm: '>=6', yarn: '>=1'} - peerDependencies: - '@testing-library/dom': ^8.0.0 || ^9.0.0 - eslint: ^6.8.0 || ^7.0.0 || ^8.0.0 - peerDependenciesMeta: - '@testing-library/dom': - optional: true - dependencies: - '@babel/runtime': 7.22.11 - eslint: 8.48.0 - requireindex: 1.2.0 - dev: true - - /eslint-plugin-react-hooks@4.6.0(eslint@8.48.0): - resolution: {integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==} - engines: {node: '>=10'} - peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 - dependencies: - eslint: 8.48.0 - dev: true - - /eslint-plugin-react@7.33.2(eslint@8.48.0): - resolution: {integrity: sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==} - engines: {node: '>=4'} - peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 - dependencies: - array-includes: 3.1.6 - array.prototype.flatmap: 1.3.1 - array.prototype.tosorted: 1.1.1 - doctrine: 2.1.0 - es-iterator-helpers: 1.0.13 - eslint: 8.48.0 - estraverse: 5.3.0 - jsx-ast-utils: 3.3.5 - minimatch: 3.1.2 - object.entries: 1.1.6 - object.fromentries: 2.0.6 - object.hasown: 1.1.2 - object.values: 1.1.6 - prop-types: 15.8.1 - resolve: 2.0.0-next.4 - semver: 6.3.1 - string.prototype.matchall: 4.0.8 - dev: true - - /eslint-scope@7.2.2: - resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - esrecurse: 4.3.0 - estraverse: 5.3.0 - dev: true - - /eslint-visitor-keys@3.4.3: - resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true - - /eslint@8.48.0: - resolution: {integrity: sha512-sb6DLeIuRXxeM1YljSe1KEx9/YYeZFQWcV8Rq9HfigmdDEugjLEVEa1ozDjL6YDjBpQHPJxJzze+alxi4T3OLg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - hasBin: true - dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.48.0) - '@eslint-community/regexpp': 4.8.0 - '@eslint/eslintrc': 2.1.2 - '@eslint/js': 8.48.0 - '@humanwhocodes/config-array': 0.11.10 - '@humanwhocodes/module-importer': 1.0.1 - '@nodelib/fs.walk': 1.2.8 - ajv: 6.12.6 - chalk: 4.1.2 - cross-spawn: 7.0.3 - debug: 4.3.4 - doctrine: 3.0.0 - escape-string-regexp: 4.0.0 - eslint-scope: 7.2.2 - eslint-visitor-keys: 3.4.3 - espree: 9.6.1 - esquery: 1.5.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 6.0.1 - find-up: 5.0.0 - glob-parent: 6.0.2 - globals: 13.21.0 - graphemer: 1.4.0 - ignore: 5.2.4 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - is-path-inside: 3.0.3 - js-yaml: 4.1.0 - json-stable-stringify-without-jsonify: 1.0.1 - levn: 0.4.1 - lodash.merge: 4.6.2 - minimatch: 3.1.2 - natural-compare: 1.4.0 - optionator: 0.9.3 - strip-ansi: 6.0.1 - text-table: 0.2.0 - transitivePeerDependencies: - - supports-color - dev: true - - /espree@9.6.1: - resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - acorn: 8.10.0 - acorn-jsx: 5.3.2(acorn@8.10.0) - eslint-visitor-keys: 3.4.3 - dev: true - - /esprima@4.0.1: - resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} - engines: {node: '>=4'} - hasBin: true - dev: true - - /esquery@1.5.0: - resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} - engines: {node: '>=0.10'} - dependencies: - estraverse: 5.3.0 - dev: true - - /esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} - dependencies: - estraverse: 5.3.0 - dev: true - - /estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} - dev: true - - /estree-walker@1.0.1: - resolution: {integrity: sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==} - dev: true - - /estree-walker@2.0.2: - resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} - dev: true - - /esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - dev: true - - /eventemitter3@3.1.2: - resolution: {integrity: sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==} - dev: false - - /execa@5.1.1: - resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} - engines: {node: '>=10'} - dependencies: - cross-spawn: 7.0.3 - get-stream: 6.0.1 - human-signals: 2.1.0 - is-stream: 2.0.1 - merge-stream: 2.0.0 - npm-run-path: 4.0.1 - onetime: 5.1.2 - signal-exit: 3.0.7 - strip-final-newline: 2.0.0 - dev: true - - /exit@0.1.2: - resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} - engines: {node: '>= 0.8.0'} - dev: true - - /expand-tilde@1.2.2: - resolution: {integrity: sha512-rtmc+cjLZqnu9dSYosX9EWmSJhTwpACgJQTfj4hgg2JjOD/6SIQalZrt4a3aQeh++oNxkazcaxrhPUj6+g5G/Q==} - engines: {node: '>=0.10.0'} - dependencies: - os-homedir: 1.0.2 - dev: true - - /expect-puppeteer@6.1.1: - resolution: {integrity: sha512-cnQF96qdoEcOD63j5NQMc0RtW9WRMW/WHKXEKsuDQ2tszhVH3qC7zkXXS4D0LTt9qCB3DEExioqylsQXvqPrUw==} - dev: true - - /expect-puppeteer@9.0.0: - resolution: {integrity: sha512-mxejfYy6hsCpBgaUbKGZzoAy4SgzVhPkVZHuBaJ+xbt+BryolxLzdKU4HhJYH/Ooo9AWghAh7ofAkKEZQ2XzcA==} - engines: {node: '>=16'} - dev: true - - /expect@27.5.1: - resolution: {integrity: sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@jest/types': 27.5.1 - jest-get-type: 27.5.1 - jest-matcher-utils: 27.5.1 - jest-message-util: 27.5.1 - dev: true - - /expect@29.6.4: - resolution: {integrity: sha512-F2W2UyQ8XYyftHT57dtfg8Ue3X5qLgm2sSug0ivvLRH/VKNRL/pDxg/TH7zVzbQB0tu80clNFy6LU7OS/VSEKA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/expect-utils': 29.6.4 - jest-get-type: 29.6.3 - jest-matcher-utils: 29.6.4 - jest-message-util: 29.6.3 - jest-util: 29.6.3 - dev: true - - /extract-zip@2.0.1: - resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} - engines: {node: '>= 10.17.0'} - hasBin: true - dependencies: - debug: 4.3.4 - get-stream: 5.2.0 - yauzl: 2.10.0 - optionalDependencies: - '@types/yauzl': 2.10.3 - transitivePeerDependencies: - - supports-color - dev: true - - /fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - dev: true - - /fast-glob@3.3.1: - resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} - engines: {node: '>=8.6.0'} - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.5 - dev: true - - /fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - dev: true - - /fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - dev: true - - /fastq@1.15.0: - resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} - dependencies: - reusify: 1.0.4 - dev: true - - /fb-watchman@2.0.2: - resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} - dependencies: - bser: 2.1.1 - dev: true - - /fbjs@0.8.18: - resolution: {integrity: sha512-EQaWFK+fEPSoibjNy8IxUtaFOMXcWsY0JaVrQoZR9zC8N2Ygf9iDITPWjUTVIax95b6I742JFLqASHfsag/vKA==} - dependencies: - core-js: 1.2.7 - isomorphic-fetch: 2.2.1 - loose-envify: 1.4.0 - object-assign: 4.1.1 - promise: 7.3.1 - setimmediate: 1.0.5 - ua-parser-js: 0.7.35 - dev: false - - /fd-slicer@1.1.0: - resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} - dependencies: - pend: 1.2.0 - dev: true - - /file-entry-cache@6.0.1: - resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} - engines: {node: ^10.12.0 || >=12.0.0} - dependencies: - flat-cache: 3.1.0 - dev: true - - /filelist@1.0.4: - resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} - dependencies: - minimatch: 5.1.6 - dev: true - - /fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} - dependencies: - to-regex-range: 5.0.1 - - /filter-obj@1.1.0: - resolution: {integrity: sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==} - engines: {node: '>=0.10.0'} - dev: false - - /find-file-up@0.1.3: - resolution: {integrity: sha512-mBxmNbVyjg1LQIIpgO8hN+ybWBgDQK8qjht+EbrTCGmmPV/sc7RF1i9stPTD6bpvXZywBdrwRYxhSdJv867L6A==} - engines: {node: '>=0.10.0'} - dependencies: - fs-exists-sync: 0.1.0 - resolve-dir: 0.1.1 - dev: true - - /find-pkg@0.1.2: - resolution: {integrity: sha512-0rnQWcFwZr7eO0513HahrWafsc3CTFioEB7DRiEYCUM/70QXSY8f3mCST17HXLcPvEhzH/Ty/Bxd72ZZsr/yvw==} - engines: {node: '>=0.10.0'} - dependencies: - find-file-up: 0.1.3 - dev: true - - /find-process@1.4.7: - resolution: {integrity: sha512-/U4CYp1214Xrp3u3Fqr9yNynUrr5Le4y0SsJh2lMDDSbpwYSz3M2SMWQC+wqcx79cN8PQtHQIL8KnuY9M66fdg==} - hasBin: true - dependencies: - chalk: 4.1.2 - commander: 5.1.0 - debug: 4.3.4 - transitivePeerDependencies: - - supports-color - dev: true - - /find-up@4.1.0: - resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} - engines: {node: '>=8'} - dependencies: - locate-path: 5.0.0 - path-exists: 4.0.0 - - /find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} - dependencies: - locate-path: 6.0.0 - path-exists: 4.0.0 - - /flat-cache@3.1.0: - resolution: {integrity: sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==} - engines: {node: '>=12.0.0'} - dependencies: - flatted: 3.2.7 - keyv: 4.5.3 - rimraf: 3.0.2 - dev: true - - /flatted@3.2.7: - resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} - dev: true - - /follow-redirects@1.15.6: - resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==} - engines: {node: '>=4.0'} - peerDependencies: - debug: '*' - peerDependenciesMeta: - debug: - optional: true - dev: true - - /for-each@0.3.3: - resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} - dependencies: - is-callable: 1.2.7 - dev: true - - /for-in@0.1.8: - resolution: {integrity: sha512-F0to7vbBSHP8E3l6dCjxNOLuSFAACIxFy3UehTUlG7svlXi37HHsDkyVcHo0Pq8QwrE+pXvWSVX3ZT1T9wAZ9g==} - engines: {node: '>=0.10.0'} - dev: true - - /for-in@1.0.2: - resolution: {integrity: sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==} - engines: {node: '>=0.10.0'} - dev: true - - /for-own@0.1.5: - resolution: {integrity: sha512-SKmowqGTJoPzLO1T0BBJpkfp3EMacCMOuH40hOUbrbzElVktk4DioXVM99QkLCyKoiuOmyjgcWMpVz2xjE7LZw==} - engines: {node: '>=0.10.0'} - dependencies: - for-in: 1.0.2 - dev: true - - /form-data@3.0.1: - resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==} - engines: {node: '>= 6'} - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - mime-types: 2.1.35 - - /fraction.js@4.3.7: - resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} - dev: true - - /fs-constants@1.0.0: - resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} - dev: true - - /fs-exists-sync@0.1.0: - resolution: {integrity: sha512-cR/vflFyPZtrN6b38ZyWxpWdhlXrzZEBawlpBQMq7033xVY7/kg0GDMBK5jg8lDYQckdJ5x/YC88lM3C7VMsLg==} - engines: {node: '>=0.10.0'} - dev: true - - /fs-extra@9.1.0: - resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} - engines: {node: '>=10'} - dependencies: - at-least-node: 1.0.0 - graceful-fs: 4.2.11 - jsonfile: 6.1.0 - universalify: 2.0.1 - dev: true - - /fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - - /fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - requiresBuild: true - optional: true - - /function-bind@1.1.1: - resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} - - /function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - dev: true - - /function.prototype.name@1.1.5: - resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.22.1 - functions-have-names: 1.2.3 - dev: true - - /function.prototype.name@1.1.6: - resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.5 - define-properties: 1.2.1 - es-abstract: 1.22.3 - functions-have-names: 1.2.3 - dev: true - - /functions-have-names@1.2.3: - resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} - dev: true - - /gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} - dev: true - - /geojson-vt@3.2.1: - resolution: {integrity: sha512-EvGQQi/zPrDA6zr6BnJD/YhwAkBP8nnJ9emh3EnHQKVMfg/MRVtPbMYdgVy/IaEmn4UfagD2a6fafPDL5hbtwg==} - dev: false - - /get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - dev: true - - /get-intrinsic@1.2.1: - resolution: {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 - dev: true - - /get-intrinsic@1.2.2: - resolution: {integrity: sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==} - dependencies: - function-bind: 1.1.2 - has-proto: 1.0.1 - has-symbols: 1.0.3 - hasown: 2.0.0 - dev: true - - /get-node-dimensions@1.2.1: - resolution: {integrity: sha512-2MSPMu7S1iOTL+BOa6K1S62hB2zUAYNF/lV0gSVlOaacd087lc6nR1H1r0e3B1CerTo+RceOmi1iJW+vp21xcQ==} - dev: false - - /get-own-enumerable-property-symbols@3.0.2: - resolution: {integrity: sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==} - dev: true - - /get-package-type@0.1.0: - resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} - engines: {node: '>=8.0.0'} - dev: true - - /get-stream@5.2.0: - resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} - engines: {node: '>=8'} - dependencies: - pump: 3.0.0 - - /get-stream@6.0.1: - resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} - engines: {node: '>=10'} - - /get-symbol-description@1.0.0: - resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 - dev: true - - /gl-matrix@3.4.3: - resolution: {integrity: sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==} - dev: false - - /glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} - dependencies: - is-glob: 4.0.3 - - /glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} - dependencies: - is-glob: 4.0.3 - dev: true - - /glob@7.1.6: - resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==} - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - dev: true - - /glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - dev: true - - /glob@9.3.2: - resolution: {integrity: sha512-BTv/JhKXFEHsErMte/AnfiSv8yYOLLiyH2lTg8vn02O21zWFgHPTfxtgn1QRe7NRgggUhC8hacR2Re94svHqeA==} - engines: {node: '>=16 || 14 >=14.17'} - dependencies: - fs.realpath: 1.0.0 - minimatch: 7.4.6 - minipass: 4.2.8 - path-scurry: 1.10.1 - dev: false - - /global-modules@0.2.3: - resolution: {integrity: sha512-JeXuCbvYzYXcwE6acL9V2bAOeSIGl4dD+iwLY9iUx2VBJJ80R18HCn+JCwHM9Oegdfya3lEkGCdaRkSyc10hDA==} - engines: {node: '>=0.10.0'} - dependencies: - global-prefix: 0.1.5 - is-windows: 0.2.0 - dev: true - - /global-prefix@0.1.5: - resolution: {integrity: sha512-gOPiyxcD9dJGCEArAhF4Hd0BAqvAe/JzERP7tYumE4yIkmIedPUVXcJFWbV3/p/ovIIvKjkrTk+f1UVkq7vvbw==} - engines: {node: '>=0.10.0'} - dependencies: - homedir-polyfill: 1.0.3 - ini: 1.3.8 - is-windows: 0.2.0 - which: 1.3.1 - dev: true - - /global@4.4.0: - resolution: {integrity: sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==} - dependencies: - min-document: 2.19.0 - process: 0.11.10 - dev: false - - /globals@11.12.0: - resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} - engines: {node: '>=4'} - dev: true - - /globals@13.21.0: - resolution: {integrity: sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==} - engines: {node: '>=8'} - dependencies: - type-fest: 0.20.2 - dev: true - - /globalthis@1.0.3: - resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} - engines: {node: '>= 0.4'} - dependencies: - define-properties: 1.2.0 - dev: true - - /gopd@1.0.1: - resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} - dependencies: - get-intrinsic: 1.2.1 - dev: true - - /got@11.8.6: - resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==} - engines: {node: '>=10.19.0'} - dependencies: - '@sindresorhus/is': 4.6.0 - '@szmarczak/http-timer': 4.0.6 - '@types/cacheable-request': 6.0.3 - '@types/responselike': 1.0.0 - cacheable-lookup: 5.0.4 - cacheable-request: 7.0.4 - decompress-response: 6.0.0 - http2-wrapper: 1.0.3 - lowercase-keys: 2.0.0 - p-cancelable: 2.1.1 - responselike: 2.0.1 - dev: false - - /graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - dev: true - - /graphemer@1.4.0: - resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - dev: true - - /grid-index@1.1.0: - resolution: {integrity: sha512-HZRwumpOGUrHyxO5bqKZL0B0GlUpwtCAzZ42sgxUPniu33R1LSFH5yrIcBCHjkctCAh3mtWKcKd9J4vDDdeVHA==} - dev: false - - /hammerjs@2.0.8: - resolution: {integrity: sha512-tSQXBXS/MWQOn/RKckawJ61vvsDpCom87JgxiYdGwHdOa0ht0vzUWDlfioofFCRU0L+6NGDt6XzbgoJvZkMeRQ==} - engines: {node: '>=0.8.0'} - dev: false - - /hard-rejection@2.1.0: - resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==} - engines: {node: '>=6'} - dev: false - - /harmony-reflect@1.6.2: - resolution: {integrity: sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g==} - dev: true - - /has-bigints@1.0.2: - resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} - dev: true - - /has-flag@3.0.0: - resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} - engines: {node: '>=4'} - - /has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - dev: true - - /has-property-descriptors@1.0.0: - resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} - dependencies: - get-intrinsic: 1.2.1 - dev: true - - /has-property-descriptors@1.0.1: - resolution: {integrity: sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==} - dependencies: - get-intrinsic: 1.2.2 - dev: true - - /has-proto@1.0.1: - resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} - engines: {node: '>= 0.4'} - dev: true - - /has-symbols@1.0.3: - resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} - engines: {node: '>= 0.4'} - dev: true - - /has-tostringtag@1.0.0: - resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} - engines: {node: '>= 0.4'} - dependencies: - has-symbols: 1.0.3 - dev: true - - /has@1.0.3: - resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} - engines: {node: '>= 0.4.0'} - dependencies: - function-bind: 1.1.1 - - /hasown@2.0.0: - resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==} - engines: {node: '>= 0.4'} - dependencies: - function-bind: 1.1.2 - dev: true - - /history@4.10.1: - resolution: {integrity: sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==} - dependencies: - '@babel/runtime': 7.22.11 - loose-envify: 1.4.0 - resolve-pathname: 3.0.0 - tiny-invariant: 1.3.1 - tiny-warning: 1.0.3 - value-equal: 1.0.1 - dev: false - - /hoist-non-react-statics@2.5.5: - resolution: {integrity: sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw==} - dev: false - - /hoist-non-react-statics@3.3.2: - resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} - dependencies: - react-is: 16.13.1 - dev: false - - /homedir-polyfill@1.0.3: - resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==} - engines: {node: '>=0.10.0'} - dependencies: - parse-passwd: 1.0.0 - dev: true - - /hosted-git-info@2.8.9: - resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} - dev: false - - /html-encoding-sniffer@2.0.1: - resolution: {integrity: sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==} - engines: {node: '>=10'} - dependencies: - whatwg-encoding: 1.0.5 - dev: true - - /html-escaper@2.0.2: - resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} - dev: true - - /http-cache-semantics@4.1.1: - resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} - dev: false - - /http-proxy-agent@4.0.1: - resolution: {integrity: sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==} - engines: {node: '>= 6'} - dependencies: - '@tootallnate/once': 1.1.2 - agent-base: 6.0.2 - debug: 4.3.4 - transitivePeerDependencies: - - supports-color - dev: true - - /http2-wrapper@1.0.3: - resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==} - engines: {node: '>=10.19.0'} - dependencies: - quick-lru: 5.1.1 - resolve-alpn: 1.2.1 - dev: false - - /https-proxy-agent@5.0.1: - resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} - engines: {node: '>= 6'} - dependencies: - agent-base: 6.0.2 - debug: 4.3.4 - transitivePeerDependencies: - - supports-color - - /human-signals@2.1.0: - resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} - engines: {node: '>=10.17.0'} - dev: true - - /hyphenate-style-name@1.0.4: - resolution: {integrity: sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==} - dev: false - - /iconv-lite@0.4.24: - resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} - engines: {node: '>=0.10.0'} - dependencies: - safer-buffer: 2.1.2 - dev: true - - /iconv-lite@0.6.3: - resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} - engines: {node: '>=0.10.0'} - dependencies: - safer-buffer: 2.1.2 - dev: false - - /idb@7.1.1: - resolution: {integrity: sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==} - dev: true - - /identity-obj-proxy@3.0.0: - resolution: {integrity: sha512-00n6YnVHKrinT9t0d9+5yZC6UBNJANpYEQvL2LlX6Ab9lnmxzIRcEmTPuyGScvl1+jKuCICX1Z0Ab1pPKKdikA==} - engines: {node: '>=4'} - dependencies: - harmony-reflect: 1.6.2 - dev: true - - /ieee754@1.2.1: - resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - - /ignore@5.2.4: - resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} - engines: {node: '>= 4'} - dev: true - - /immediate@3.0.6: - resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} - dev: false - - /immutable@3.8.2: - resolution: {integrity: sha512-15gZoQ38eYjEjxkorfbcgBKBL6R7T459OuK+CpcWt7O3KF4uPCx2tD0uFETlUDIyo+1789crbMhTvQBSR5yBMg==} - engines: {node: '>=0.10.0'} - dev: false - - /import-fresh@3.3.0: - resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} - engines: {node: '>=6'} - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 - dev: true - - /import-local@3.1.0: - resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==} - engines: {node: '>=8'} - hasBin: true - dependencies: - pkg-dir: 4.2.0 - resolve-cwd: 3.0.0 - dev: true - - /imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - dev: true - - /indefinite-observable@1.0.2: - resolution: {integrity: sha512-Mps0898zEduHyPhb7UCgNmfzlqNZknVmaFz5qzr0mm04YQ5FGLhAyK/dJ+NaRxGyR6juQXIxh5Ev0xx+qq0nYA==} - dependencies: - symbol-observable: 1.2.0 - dev: false - - /indent-string@4.0.0: - resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} - engines: {node: '>=8'} - - /inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - dev: true - - /inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - dev: true - - /ini@1.3.8: - resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - dev: true - - /internal-slot@1.0.5: - resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==} - engines: {node: '>= 0.4'} - dependencies: - get-intrinsic: 1.2.1 - has: 1.0.3 - side-channel: 1.0.4 - dev: true - - /internal-slot@1.0.6: - resolution: {integrity: sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==} - engines: {node: '>= 0.4'} - dependencies: - get-intrinsic: 1.2.2 - hasown: 2.0.0 - side-channel: 1.0.4 - dev: true - - /invariant@2.2.4: - resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} - dependencies: - loose-envify: 1.4.0 - dev: false - - /is-arguments@1.1.1: - resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - has-tostringtag: 1.0.0 - dev: true - - /is-array-buffer@3.0.2: - resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} - dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 - is-typed-array: 1.1.12 - dev: true - - /is-arrayish@0.2.1: - resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - - /is-async-function@2.0.0: - resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} - engines: {node: '>= 0.4'} - dependencies: - has-tostringtag: 1.0.0 - dev: true - - /is-bigint@1.0.4: - resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} - dependencies: - has-bigints: 1.0.2 - dev: true - - /is-binary-path@2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} - engines: {node: '>=8'} - dependencies: - binary-extensions: 2.2.0 - - /is-boolean-object@1.1.2: - resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - has-tostringtag: 1.0.0 - dev: true - - /is-buffer@1.1.6: - resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} - dev: true - - /is-callable@1.2.7: - resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} - engines: {node: '>= 0.4'} - dev: true - - /is-core-module@2.13.0: - resolution: {integrity: sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==} - dependencies: - has: 1.0.3 - - /is-core-module@2.13.1: - resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} - dependencies: - hasown: 2.0.0 - dev: true - - /is-date-object@1.0.5: - resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} - engines: {node: '>= 0.4'} - dependencies: - has-tostringtag: 1.0.0 - dev: true - - /is-extendable@0.1.1: - resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} - engines: {node: '>=0.10.0'} - dev: true - - /is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - - /is-finalizationregistry@1.0.2: - resolution: {integrity: sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==} - dependencies: - call-bind: 1.0.2 - dev: true - - /is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - dev: true - - /is-function@1.0.2: - resolution: {integrity: sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==} - dev: false - - /is-generator-fn@2.1.0: - resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} - engines: {node: '>=6'} - dev: true - - /is-generator-function@1.0.10: - resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} - engines: {node: '>= 0.4'} - dependencies: - has-tostringtag: 1.0.0 - dev: true - - /is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - dependencies: - is-extglob: 2.1.1 - - /is-in-browser@1.1.3: - resolution: {integrity: sha512-FeXIBgG/CPGd/WUxuEyvgGTEfwiG9Z4EKGxjNMRqviiIIfsmgrpnHLffEDdwUHqNva1VEW91o3xBT/m8Elgl9g==} - dev: false - - /is-map@2.0.2: - resolution: {integrity: sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==} - dev: true - - /is-module@1.0.0: - resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} - dev: true - - /is-negative-zero@2.0.2: - resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} - engines: {node: '>= 0.4'} - dev: true - - /is-number-object@1.0.7: - resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} - engines: {node: '>= 0.4'} - dependencies: - has-tostringtag: 1.0.0 - dev: true - - /is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - - /is-obj@1.0.1: - resolution: {integrity: sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==} - engines: {node: '>=0.10.0'} - dev: true - - /is-object@1.0.2: - resolution: {integrity: sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==} - dev: false - - /is-path-inside@3.0.3: - resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} - engines: {node: '>=8'} - dev: true - - /is-plain-obj@1.1.0: - resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==} - engines: {node: '>=0.10.0'} - dev: false - - /is-plain-object@2.0.4: - resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} - engines: {node: '>=0.10.0'} - dependencies: - isobject: 3.0.1 - - /is-potential-custom-element-name@1.0.1: - resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} - dev: true - - /is-regex@1.1.4: - resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - has-tostringtag: 1.0.0 - dev: true - - /is-regexp@1.0.0: - resolution: {integrity: sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==} - engines: {node: '>=0.10.0'} - dev: true - - /is-set@2.0.2: - resolution: {integrity: sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==} - dev: true - - /is-shared-array-buffer@1.0.2: - resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} - dependencies: - call-bind: 1.0.2 - dev: true - - /is-stream@1.1.0: - resolution: {integrity: sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==} - engines: {node: '>=0.10.0'} - dev: false - - /is-stream@2.0.1: - resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} - engines: {node: '>=8'} - dev: true - - /is-string@1.0.7: - resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} - engines: {node: '>= 0.4'} - dependencies: - has-tostringtag: 1.0.0 - dev: true - - /is-symbol@1.0.4: - resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} - engines: {node: '>= 0.4'} - dependencies: - has-symbols: 1.0.3 - dev: true - - /is-typed-array@1.1.12: - resolution: {integrity: sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==} - engines: {node: '>= 0.4'} - dependencies: - which-typed-array: 1.1.11 - dev: true - - /is-typedarray@1.0.0: - resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} - dev: true - - /is-weakmap@2.0.1: - resolution: {integrity: sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==} - dev: true - - /is-weakref@1.0.2: - resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} - dependencies: - call-bind: 1.0.2 - dev: true - - /is-weakset@2.0.2: - resolution: {integrity: sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==} - dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 - dev: true - - /is-windows@0.2.0: - resolution: {integrity: sha512-n67eJYmXbniZB7RF4I/FTjK1s6RPOCTxhYrVYLRaCt3lF0mpWZPKr3T2LSZAqyjQsxR2qMmGYXXzK0YWwcPM1Q==} - engines: {node: '>=0.10.0'} - dev: true - - /isarray@0.0.1: - resolution: {integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==} - dev: false - - /isarray@2.0.5: - resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} - dev: true - - /isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - - /isobject@3.0.1: - resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} - engines: {node: '>=0.10.0'} - - /isomorphic-fetch@2.2.1: - resolution: {integrity: sha512-9c4TNAKYXM5PRyVcwUZrF3W09nQ+sO7+jydgs4ZGW9dhsLG2VOlISJABombdQqQRXCwuYG3sYV/puGf5rp0qmA==} - dependencies: - node-fetch: 1.7.3 - whatwg-fetch: 3.6.17 - dev: false - - /istanbul-lib-coverage@3.2.0: - resolution: {integrity: sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==} - engines: {node: '>=8'} - dev: true - - /istanbul-lib-instrument@5.2.1: - resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} - engines: {node: '>=8'} - dependencies: - '@babel/core': 7.22.11 - '@babel/parser': 7.22.11 - '@istanbuljs/schema': 0.1.3 - istanbul-lib-coverage: 3.2.0 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - dev: true - - /istanbul-lib-report@3.0.1: - resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} - engines: {node: '>=10'} - dependencies: - istanbul-lib-coverage: 3.2.0 - make-dir: 4.0.0 - supports-color: 7.2.0 - dev: true - - /istanbul-lib-source-maps@4.0.1: - resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} - engines: {node: '>=10'} - dependencies: - debug: 4.3.4 - istanbul-lib-coverage: 3.2.0 - source-map: 0.6.1 - transitivePeerDependencies: - - supports-color - dev: true - - /istanbul-reports@3.1.6: - resolution: {integrity: sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==} - engines: {node: '>=8'} - dependencies: - html-escaper: 2.0.2 - istanbul-lib-report: 3.0.1 - dev: true - - /iterator.prototype@1.1.0: - resolution: {integrity: sha512-rjuhAk1AJ1fssphHD0IFV6TWL40CwRZ53FrztKx43yk2v6rguBYsY4Bj1VU4HmoMmKwZUlx7mfnhDf9cOp4YTw==} - dependencies: - define-properties: 1.2.0 - get-intrinsic: 1.2.1 - has-symbols: 1.0.3 - has-tostringtag: 1.0.0 - reflect.getprototypeof: 1.0.3 - dev: true - - /jake@10.8.7: - resolution: {integrity: sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==} - engines: {node: '>=10'} - hasBin: true - dependencies: - async: 3.2.5 - chalk: 4.1.2 - filelist: 1.0.4 - minimatch: 3.1.2 - dev: true - - /jest-chain-transform@0.0.5(@jest/transform@27.5.1): - resolution: {integrity: sha512-5lmLEPg2Ygm5m+KqXx6pFAPTHATxLoL472r0Shv1261jMWr83EwucDfsnVFWhjCBdNxCH4fM/HXWGdrTQC0NcA==} - peerDependencies: - '@jest/transform': ^27.0.6 - dependencies: - '@jest/transform': 27.5.1 - dev: true - - /jest-changed-files@27.5.1: - resolution: {integrity: sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@jest/types': 27.5.1 - execa: 5.1.1 - throat: 6.0.2 - dev: true - - /jest-circus@27.5.1: - resolution: {integrity: sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@jest/environment': 27.5.1 - '@jest/test-result': 27.5.1 - '@jest/types': 27.5.1 - '@types/node': 20.5.6 - chalk: 4.1.2 - co: 4.6.0 - dedent: 0.7.0 - expect: 27.5.1 - is-generator-fn: 2.1.0 - jest-each: 27.5.1 - jest-matcher-utils: 27.5.1 - jest-message-util: 27.5.1 - jest-runtime: 27.5.1 - jest-snapshot: 27.5.1 - jest-util: 27.5.1 - pretty-format: 27.5.1 - slash: 3.0.0 - stack-utils: 2.0.6 - throat: 6.0.2 - transitivePeerDependencies: - - supports-color - dev: true - - /jest-cli@27.5.1: - resolution: {integrity: sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - hasBin: true - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - dependencies: - '@jest/core': 27.5.1 - '@jest/test-result': 27.5.1 - '@jest/types': 27.5.1 - chalk: 4.1.2 - exit: 0.1.2 - graceful-fs: 4.2.11 - import-local: 3.1.0 - jest-config: 27.5.1 - jest-util: 27.5.1 - jest-validate: 27.5.1 - prompts: 2.4.2 - yargs: 16.2.0 - transitivePeerDependencies: - - bufferutil - - canvas - - supports-color - - ts-node - - utf-8-validate - dev: true - - /jest-config@27.5.1: - resolution: {integrity: sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - peerDependencies: - ts-node: '>=9.0.0' - peerDependenciesMeta: - ts-node: - optional: true - dependencies: - '@babel/core': 7.22.11 - '@jest/test-sequencer': 27.5.1 - '@jest/types': 27.5.1 - babel-jest: 27.5.1(@babel/core@7.22.11) - chalk: 4.1.2 - ci-info: 3.8.0 - deepmerge: 4.3.1 - glob: 7.2.3 - graceful-fs: 4.2.11 - jest-circus: 27.5.1 - jest-environment-jsdom: 27.5.1 - jest-environment-node: 27.5.1 - jest-get-type: 27.5.1 - jest-jasmine2: 27.5.1 - jest-regex-util: 27.5.1 - jest-resolve: 27.5.1 - jest-runner: 27.5.1 - jest-util: 27.5.1 - jest-validate: 27.5.1 - micromatch: 4.0.5 - parse-json: 5.2.0 - pretty-format: 27.5.1 - slash: 3.0.0 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - bufferutil - - canvas - - supports-color - - utf-8-validate - dev: true - - /jest-dev-server@6.2.0: - resolution: {integrity: sha512-ZWh8CuvxwjhYfvw4tGeftziqIvw/26R6AG3OTgNTQeXul8aZz48RQjDpnlDwnWX53jxJJl9fcigqIdSU5lYZuw==} - dependencies: - chalk: 4.1.2 - cwd: 0.10.0 - find-process: 1.4.7 - prompts: 2.4.2 - spawnd: 6.2.0 - tree-kill: 1.2.2 - wait-on: 6.0.1 - transitivePeerDependencies: - - debug - - supports-color - dev: true - - /jest-diff@27.5.1: - resolution: {integrity: sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - chalk: 4.1.2 - diff-sequences: 27.5.1 - jest-get-type: 27.5.1 - pretty-format: 27.5.1 - dev: true - - /jest-diff@29.6.4: - resolution: {integrity: sha512-9F48UxR9e4XOEZvoUXEHSWY4qC4zERJaOfrbBg9JpbJOO43R1vN76REt/aMGZoY6GD5g84nnJiBIVlscegefpw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - chalk: 4.1.2 - diff-sequences: 29.6.3 - jest-get-type: 29.6.3 - pretty-format: 29.6.3 - dev: true - - /jest-docblock@27.5.1: - resolution: {integrity: sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - detect-newline: 3.1.0 - dev: true - - /jest-each@27.5.1: - resolution: {integrity: sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@jest/types': 27.5.1 - chalk: 4.1.2 - jest-get-type: 27.5.1 - jest-util: 27.5.1 - pretty-format: 27.5.1 - dev: true - - /jest-environment-jsdom@27.5.1: - resolution: {integrity: sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@jest/environment': 27.5.1 - '@jest/fake-timers': 27.5.1 - '@jest/types': 27.5.1 - '@types/node': 20.5.6 - jest-mock: 27.5.1 - jest-util: 27.5.1 - jsdom: 16.7.0 - transitivePeerDependencies: - - bufferutil - - canvas - - supports-color - - utf-8-validate - dev: true - - /jest-environment-node@27.5.1: - resolution: {integrity: sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@jest/environment': 27.5.1 - '@jest/fake-timers': 27.5.1 - '@jest/types': 27.5.1 - '@types/node': 20.5.6 - jest-mock: 27.5.1 - jest-util: 27.5.1 - dev: true - - /jest-environment-puppeteer@6.2.0: - resolution: {integrity: sha512-a/oSu6dO9D+XoDDe3ZY/0Sk79Jl2FcJl7Q0D+3x22l1eWNOYe4ikXnPGhtmNZ3mJIpuAVIX6LytA8EraOk/aqQ==} - dependencies: - chalk: 4.1.2 - cwd: 0.10.0 - jest-dev-server: 6.2.0 - jest-environment-node: 27.5.1 - merge-deep: 3.0.3 - transitivePeerDependencies: - - debug - - supports-color - dev: true - - /jest-get-type@27.5.1: - resolution: {integrity: sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dev: true - - /jest-get-type@29.6.3: - resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dev: true - - /jest-haste-map@27.5.1: - resolution: {integrity: sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@jest/types': 27.5.1 - '@types/graceful-fs': 4.1.6 - '@types/node': 20.5.6 - anymatch: 3.1.3 - fb-watchman: 2.0.2 - graceful-fs: 4.2.11 - jest-regex-util: 27.5.1 - jest-serializer: 27.5.1 - jest-util: 27.5.1 - jest-worker: 27.5.1 - micromatch: 4.0.5 - walker: 1.0.8 - optionalDependencies: - fsevents: 2.3.3 - dev: true - - /jest-jasmine2@27.5.1: - resolution: {integrity: sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@jest/environment': 27.5.1 - '@jest/source-map': 27.5.1 - '@jest/test-result': 27.5.1 - '@jest/types': 27.5.1 - '@types/node': 20.5.6 - chalk: 4.1.2 - co: 4.6.0 - expect: 27.5.1 - is-generator-fn: 2.1.0 - jest-each: 27.5.1 - jest-matcher-utils: 27.5.1 - jest-message-util: 27.5.1 - jest-runtime: 27.5.1 - jest-snapshot: 27.5.1 - jest-util: 27.5.1 - pretty-format: 27.5.1 - throat: 6.0.2 - transitivePeerDependencies: - - supports-color - dev: true - - /jest-leak-detector@27.5.1: - resolution: {integrity: sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - jest-get-type: 27.5.1 - pretty-format: 27.5.1 - dev: true - - /jest-matcher-utils@27.5.1: - resolution: {integrity: sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - chalk: 4.1.2 - jest-diff: 27.5.1 - jest-get-type: 27.5.1 - pretty-format: 27.5.1 - dev: true - - /jest-matcher-utils@29.6.4: - resolution: {integrity: sha512-KSzwyzGvK4HcfnserYqJHYi7sZVqdREJ9DMPAKVbS98JsIAvumihaNUbjrWw0St7p9IY7A9UskCW5MYlGmBQFQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - chalk: 4.1.2 - jest-diff: 29.6.4 - jest-get-type: 29.6.3 - pretty-format: 29.6.3 - dev: true - - /jest-message-util@27.5.1: - resolution: {integrity: sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@babel/code-frame': 7.22.10 - '@jest/types': 27.5.1 - '@types/stack-utils': 2.0.1 - chalk: 4.1.2 - graceful-fs: 4.2.11 - micromatch: 4.0.5 - pretty-format: 27.5.1 - slash: 3.0.0 - stack-utils: 2.0.6 - dev: true - - /jest-message-util@29.6.3: - resolution: {integrity: sha512-FtzaEEHzjDpQp51HX4UMkPZjy46ati4T5pEMyM6Ik48ztu4T9LQplZ6OsimHx7EuM9dfEh5HJa6D3trEftu3dA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@babel/code-frame': 7.22.10 - '@jest/types': 29.6.3 - '@types/stack-utils': 2.0.1 - chalk: 4.1.2 - graceful-fs: 4.2.11 - micromatch: 4.0.5 - pretty-format: 29.6.3 - slash: 3.0.0 - stack-utils: 2.0.6 - dev: true - - /jest-mock@27.5.1: - resolution: {integrity: sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@jest/types': 27.5.1 - '@types/node': 20.5.6 - dev: true - - /jest-pnp-resolver@1.2.3(jest-resolve@27.5.1): - resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} - engines: {node: '>=6'} - peerDependencies: - jest-resolve: '*' - peerDependenciesMeta: - jest-resolve: - optional: true - dependencies: - jest-resolve: 27.5.1 - dev: true - - /jest-puppeteer@6.2.0(puppeteer@19.11.1): - resolution: {integrity: sha512-4Ynkgcf9FkHlTNEpdsojGLb3KtsToWqjO6SCigxb9Qj3HzIqhzJzNbDJ/XhiciNDpqDe6KHW9sZ6fjHphNLr6g==} - peerDependencies: - puppeteer: '>= 1.5.0' - dependencies: - expect-puppeteer: 6.1.1 - jest-environment-puppeteer: 6.2.0 - puppeteer: 19.11.1 - transitivePeerDependencies: - - debug - - supports-color - dev: true - - /jest-regex-util@27.5.1: - resolution: {integrity: sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dev: true - - /jest-resolve-dependencies@27.5.1: - resolution: {integrity: sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@jest/types': 27.5.1 - jest-regex-util: 27.5.1 - jest-snapshot: 27.5.1 - transitivePeerDependencies: - - supports-color - dev: true - - /jest-resolve@27.5.1: - resolution: {integrity: sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@jest/types': 27.5.1 - chalk: 4.1.2 - graceful-fs: 4.2.11 - jest-haste-map: 27.5.1 - jest-pnp-resolver: 1.2.3(jest-resolve@27.5.1) - jest-util: 27.5.1 - jest-validate: 27.5.1 - resolve: 1.22.4 - resolve.exports: 1.1.1 - slash: 3.0.0 - dev: true - - /jest-runner@27.5.1: - resolution: {integrity: sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@jest/console': 27.5.1 - '@jest/environment': 27.5.1 - '@jest/test-result': 27.5.1 - '@jest/transform': 27.5.1 - '@jest/types': 27.5.1 - '@types/node': 20.5.6 - chalk: 4.1.2 - emittery: 0.8.1 - graceful-fs: 4.2.11 - jest-docblock: 27.5.1 - jest-environment-jsdom: 27.5.1 - jest-environment-node: 27.5.1 - jest-haste-map: 27.5.1 - jest-leak-detector: 27.5.1 - jest-message-util: 27.5.1 - jest-resolve: 27.5.1 - jest-runtime: 27.5.1 - jest-util: 27.5.1 - jest-worker: 27.5.1 - source-map-support: 0.5.21 - throat: 6.0.2 - transitivePeerDependencies: - - bufferutil - - canvas - - supports-color - - utf-8-validate - dev: true - - /jest-runtime@27.5.1: - resolution: {integrity: sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@jest/environment': 27.5.1 - '@jest/fake-timers': 27.5.1 - '@jest/globals': 27.5.1 - '@jest/source-map': 27.5.1 - '@jest/test-result': 27.5.1 - '@jest/transform': 27.5.1 - '@jest/types': 27.5.1 - chalk: 4.1.2 - cjs-module-lexer: 1.2.3 - collect-v8-coverage: 1.0.2 - execa: 5.1.1 - glob: 7.2.3 - graceful-fs: 4.2.11 - jest-haste-map: 27.5.1 - jest-message-util: 27.5.1 - jest-mock: 27.5.1 - jest-regex-util: 27.5.1 - jest-resolve: 27.5.1 - jest-snapshot: 27.5.1 - jest-util: 27.5.1 - slash: 3.0.0 - strip-bom: 4.0.0 - transitivePeerDependencies: - - supports-color - dev: true - - /jest-serializer@27.5.1: - resolution: {integrity: sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@types/node': 20.5.6 - graceful-fs: 4.2.11 - dev: true - - /jest-snapshot@27.5.1: - resolution: {integrity: sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@babel/core': 7.22.11 - '@babel/generator': 7.22.10 - '@babel/plugin-syntax-typescript': 7.22.5(@babel/core@7.22.11) - '@babel/traverse': 7.22.11 - '@babel/types': 7.22.11 - '@jest/transform': 27.5.1 - '@jest/types': 27.5.1 - '@types/babel__traverse': 7.20.1 - '@types/prettier': 2.7.3 - babel-preset-current-node-syntax: 1.0.1(@babel/core@7.22.11) - chalk: 4.1.2 - expect: 27.5.1 - graceful-fs: 4.2.11 - jest-diff: 27.5.1 - jest-get-type: 27.5.1 - jest-haste-map: 27.5.1 - jest-matcher-utils: 27.5.1 - jest-message-util: 27.5.1 - jest-util: 27.5.1 - natural-compare: 1.4.0 - pretty-format: 27.5.1 - semver: 7.5.4 - transitivePeerDependencies: - - supports-color - dev: true - - /jest-util@27.5.1: - resolution: {integrity: sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@jest/types': 27.5.1 - '@types/node': 20.5.6 - chalk: 4.1.2 - ci-info: 3.8.0 - graceful-fs: 4.2.11 - picomatch: 2.3.1 - dev: true - - /jest-util@29.6.3: - resolution: {integrity: sha512-QUjna/xSy4B32fzcKTSz1w7YYzgiHrjjJjevdRf61HYk998R5vVMMNmrHESYZVDS5DSWs+1srPLPKxXPkeSDOA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/types': 29.6.3 - '@types/node': 20.5.6 - chalk: 4.1.2 - ci-info: 3.8.0 - graceful-fs: 4.2.11 - picomatch: 2.3.1 - dev: true - - /jest-validate@27.5.1: - resolution: {integrity: sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@jest/types': 27.5.1 - camelcase: 6.3.0 - chalk: 4.1.2 - jest-get-type: 27.5.1 - leven: 3.1.0 - pretty-format: 27.5.1 - dev: true - - /jest-watcher@27.5.1: - resolution: {integrity: sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@jest/test-result': 27.5.1 - '@jest/types': 27.5.1 - '@types/node': 20.5.6 - ansi-escapes: 4.3.2 - chalk: 4.1.2 - jest-util: 27.5.1 - string-length: 4.0.2 - dev: true - - /jest-worker@26.6.2: - resolution: {integrity: sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==} - engines: {node: '>= 10.13.0'} - dependencies: - '@types/node': 20.10.1 - merge-stream: 2.0.0 - supports-color: 7.2.0 - dev: true - - /jest-worker@27.5.1: - resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} - engines: {node: '>= 10.13.0'} - dependencies: - '@types/node': 20.5.6 - merge-stream: 2.0.0 - supports-color: 8.1.1 - dev: true - - /jest@27.5.1: - resolution: {integrity: sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - hasBin: true - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - dependencies: - '@jest/core': 27.5.1 - import-local: 3.1.0 - jest-cli: 27.5.1 - transitivePeerDependencies: - - bufferutil - - canvas - - supports-color - - ts-node - - utf-8-validate - dev: true - - /jiti@1.19.3: - resolution: {integrity: sha512-5eEbBDQT/jF1xg6l36P+mWGGoH9Spuy0PCdSr2dtWRDGC6ph/w9ZCL4lmESW8f8F7MwT3XKescfP0wnZWAKL9w==} - hasBin: true - dev: true - - /joi@17.9.2: - resolution: {integrity: sha512-Itk/r+V4Dx0V3c7RLFdRh12IOjySm2/WGPMubBT92cQvRfYZhPM2W0hZlctjj72iES8jsRCwp7S/cRmWBnJ4nw==} - dependencies: - '@hapi/hoek': 9.3.0 - '@hapi/topo': 5.1.0 - '@sideway/address': 4.1.4 - '@sideway/formula': 3.0.1 - '@sideway/pinpoint': 2.0.0 - dev: true - - /js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - - /js-yaml@3.14.1: - resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} - hasBin: true - dependencies: - argparse: 1.0.10 - esprima: 4.0.1 - dev: true - - /js-yaml@4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} - hasBin: true - dependencies: - argparse: 2.0.1 - dev: true - - /jsdom@16.7.0: - resolution: {integrity: sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==} - engines: {node: '>=10'} - peerDependencies: - canvas: ^2.5.0 - peerDependenciesMeta: - canvas: - optional: true - dependencies: - abab: 2.0.6 - acorn: 8.10.0 - acorn-globals: 6.0.0 - cssom: 0.4.4 - cssstyle: 2.3.0 - data-urls: 2.0.0 - decimal.js: 10.4.3 - domexception: 2.0.1 - escodegen: 2.1.0 - form-data: 3.0.1 - html-encoding-sniffer: 2.0.1 - http-proxy-agent: 4.0.1 - https-proxy-agent: 5.0.1 - is-potential-custom-element-name: 1.0.1 - nwsapi: 2.2.7 - parse5: 6.0.1 - saxes: 5.0.1 - symbol-tree: 3.2.4 - tough-cookie: 4.1.3 - 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.7.0 - ws: 7.5.9 - xml-name-validator: 3.0.0 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - dev: true - - /jsesc@0.5.0: - resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==} - hasBin: true - dev: true - - /jsesc@2.5.2: - resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} - engines: {node: '>=4'} - hasBin: true - dev: true - - /json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - - /json-parse-even-better-errors@2.3.1: - resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - - /json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - dev: true - - /json-schema-traverse@1.0.0: - resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - dev: true - - /json-schema@0.4.0: - resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} - dev: true - - /json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - dev: true - - /json5@1.0.2: - resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} - hasBin: true - dependencies: - minimist: 1.2.8 - dev: true - - /json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - dev: true - - /jsonc-parser@3.2.1: - resolution: {integrity: sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==} - dev: true - - /jsonfile@6.1.0: - resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} - dependencies: - universalify: 2.0.1 - optionalDependencies: - graceful-fs: 4.2.11 - dev: true - - /jsonpointer@5.0.1: - resolution: {integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==} - engines: {node: '>=0.10.0'} - dev: true - - /jss-camel-case@6.1.0(jss@9.8.7): - resolution: {integrity: sha512-HPF2Q7wmNW1t79mCqSeU2vdd/vFFGpkazwvfHMOhPlMgXrJDzdj9viA2SaHk9ZbD5pfL63a8ylp4++irYbbzMQ==} - peerDependencies: - jss: ^9.7.0 - dependencies: - hyphenate-style-name: 1.0.4 - jss: 9.8.7 - dev: false - - /jss-compose@5.0.0(jss@9.8.7): - resolution: {integrity: sha512-YofRYuiA0+VbeOw0VjgkyO380sA4+TWDrW52nSluD9n+1FWOlDzNbgpZ/Sb3Y46+DcAbOS21W5jo6SAqUEiuwA==} - peerDependencies: - jss: ^9.0.0 - dependencies: - jss: 9.8.7 - warning: 3.0.0 - dev: false - - /jss-default-unit@8.0.2(jss@9.8.7): - resolution: {integrity: sha512-WxNHrF/18CdoAGw2H0FqOEvJdREXVXLazn7PQYU7V6/BWkCV0GkmWsppNiExdw8dP4TU1ma1dT9zBNJ95feLmg==} - peerDependencies: - jss: ^9.4.0 - dependencies: - jss: 9.8.7 - dev: false - - /jss-expand@5.3.0(jss@9.8.7): - resolution: {integrity: sha512-NiM4TbDVE0ykXSAw6dfFmB1LIqXP/jdd0ZMnlvlGgEMkMt+weJIl8Ynq1DsuBY9WwkNyzWktdqcEW2VN0RAtQg==} - peerDependencies: - jss: ^9.4.0 - dependencies: - jss: 9.8.7 - dev: false - - /jss-extend@6.2.0(jss@9.8.7): - resolution: {integrity: sha512-YszrmcB6o9HOsKPszK7NeDBNNjVyiW864jfoiHoMlgMIg2qlxKw70axZHqgczXHDcoyi/0/ikP1XaHDPRvYtEA==} - peerDependencies: - jss: ^9.7.0 - dependencies: - jss: 9.8.7 - warning: 3.0.0 - dev: false - - /jss-global@3.0.0(jss@9.8.7): - resolution: {integrity: sha512-wxYn7vL+TImyQYGAfdplg7yaxnPQ9RaXY/cIA8hawaVnmmWxDHzBK32u1y+RAvWboa3lW83ya3nVZ/C+jyjZ5Q==} - peerDependencies: - jss: ^9.0.0 - dependencies: - jss: 9.8.7 - dev: false - - /jss-nested@6.0.1(jss@9.8.7): - resolution: {integrity: sha512-rn964TralHOZxoyEgeq3hXY8hyuCElnvQoVrQwKHVmu55VRDd6IqExAx9be5HgK0yN/+hQdgAXQl/GUrBbbSTA==} - peerDependencies: - jss: ^9.0.0 - dependencies: - jss: 9.8.7 - warning: 3.0.0 - dev: false - - /jss-preset-default@4.5.0(jss@9.8.7): - resolution: {integrity: sha512-qZbpRVtHT7hBPpZEBPFfafZKWmq3tA/An5RNqywDsZQGrlinIF/mGD9lmj6jGqu8GrED2SMHZ3pPKLmjCZoiaQ==} - peerDependencies: - jss: ^9.7.0 - dependencies: - jss: 9.8.7 - jss-camel-case: 6.1.0(jss@9.8.7) - jss-compose: 5.0.0(jss@9.8.7) - jss-default-unit: 8.0.2(jss@9.8.7) - jss-expand: 5.3.0(jss@9.8.7) - jss-extend: 6.2.0(jss@9.8.7) - jss-global: 3.0.0(jss@9.8.7) - jss-nested: 6.0.1(jss@9.8.7) - jss-props-sort: 6.0.0(jss@9.8.7) - jss-template: 1.0.1(jss@9.8.7) - jss-vendor-prefixer: 7.0.0(jss@9.8.7) - dev: false - - /jss-props-sort@6.0.0(jss@9.8.7): - resolution: {integrity: sha512-E89UDcrphmI0LzmvYk25Hp4aE5ZBsXqMWlkFXS0EtPkunJkRr+WXdCNYbXbksIPnKlBenGB9OxzQY+mVc70S+g==} - peerDependencies: - jss: ^9.0.0 - dependencies: - jss: 9.8.7 - dev: false - - /jss-template@1.0.1(jss@9.8.7): - resolution: {integrity: sha512-m5BqEWha17fmIVXm1z8xbJhY6GFJxNB9H68GVnCWPyGYfxiAgY9WTQyvDAVj+pYRgrXSOfN5V1T4+SzN1sJTeg==} - peerDependencies: - jss: ^9.0.0 - dependencies: - jss: 9.8.7 - warning: 3.0.0 - dev: false - - /jss-vendor-prefixer@7.0.0(jss@9.8.7): - resolution: {integrity: sha512-Agd+FKmvsI0HLcYXkvy8GYOw3AAASBUpsmIRvVQheps+JWaN892uFOInTr0DRydwaD91vSSUCU4NssschvF7MA==} - peerDependencies: - jss: ^9.0.0 - dependencies: - css-vendor: 0.3.8 - jss: 9.8.7 - dev: false - - /jss@9.8.7: - resolution: {integrity: sha512-awj3XRZYxbrmmrx9LUSj5pXSUfm12m8xzi/VKeqI1ZwWBtQ0kVPTs3vYs32t4rFw83CgFDukA8wKzOE9sMQnoQ==} - engines: {node: '>=4'} - requiresBuild: true - dependencies: - is-in-browser: 1.1.3 - symbol-observable: 1.2.0 - warning: 3.0.0 - dev: false - - /jsx-ast-utils@3.3.5: - resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} - engines: {node: '>=4.0'} - dependencies: - array-includes: 3.1.6 - array.prototype.flat: 1.3.1 - object.assign: 4.1.4 - object.values: 1.1.6 - dev: true - - /jwt-decode@3.1.2: - resolution: {integrity: sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==} - dev: false - - /kdbush@3.0.0: - resolution: {integrity: sha512-hRkd6/XW4HTsA9vjVpY9tuXJYLSlelnkTmVFu4M9/7MIYQtFcHpbugAU7UbOfjOiVSVYl2fqgBuJ32JUmRo5Ew==} - dev: false - - /keycode@2.2.1: - resolution: {integrity: sha512-Rdgz9Hl9Iv4QKi8b0OlCRQEzp4AgVxyCtz5S/+VIHezDmrDhkp2N2TqBWOLz0/gbeREXOOiI9/4b8BY9uw2vFg==} - dev: false - - /keyv@4.5.3: - resolution: {integrity: sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==} - dependencies: - json-buffer: 3.0.1 - - /kind-of@2.0.1: - resolution: {integrity: sha512-0u8i1NZ/mg0b+W3MGGw5I7+6Eib2nx72S/QvXa0hYjEkjTknYmEYQJwGu3mLC0BrhtJjtQafTkyRUQ75Kx0LVg==} - engines: {node: '>=0.10.0'} - dependencies: - is-buffer: 1.1.6 - dev: true - - /kind-of@3.2.2: - resolution: {integrity: sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==} - engines: {node: '>=0.10.0'} - dependencies: - is-buffer: 1.1.6 - dev: true - - /kind-of@6.0.3: - resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} - engines: {node: '>=0.10.0'} - dev: false - - /kleur@3.0.3: - resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} - engines: {node: '>=6'} - dev: true - - /lazy-cache@0.2.7: - resolution: {integrity: sha512-gkX52wvU/R8DVMMt78ATVPFMJqfW8FPz1GZ1sVHBVQHmu/WvhIWE4cE1GBzhJNFicDeYhnwp6Rl35BcAIM3YOQ==} - engines: {node: '>=0.10.0'} - dev: true - - /lazy-cache@1.0.4: - resolution: {integrity: sha512-RE2g0b5VGZsOCFOCgP7omTRYFqydmZkBwl5oNnQ1lDYC57uyO9KqNnNVxT7COSHTxrRCWVcAVOcbjk+tvh/rgQ==} - engines: {node: '>=0.10.0'} - dev: true - - /leven@3.1.0: - resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} - engines: {node: '>=6'} - dev: true - - /levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} - dependencies: - prelude-ls: 1.2.1 - type-check: 0.4.0 - dev: true - - /lie@3.1.1: - resolution: {integrity: sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==} - dependencies: - immediate: 3.0.6 - dev: false - - /lilconfig@2.1.0: - resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} - engines: {node: '>=10'} - dev: true - - /lines-and-columns@1.2.4: - resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - - /load-script@1.0.0: - resolution: {integrity: sha512-kPEjMFtZvwL9TaZo0uZ2ml+Ye9HUMmPwbYRJ324qF9tqMejwykJ5ggTyvzmrbBeapCAbk98BSbTeovHEEP1uCA==} - dev: false - - /localforage@1.10.0: - resolution: {integrity: sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==} - dependencies: - lie: 3.1.1 - dev: false - - /locate-path@5.0.0: - resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} - engines: {node: '>=8'} - dependencies: - p-locate: 4.1.0 - - /locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} - dependencies: - p-locate: 5.0.0 - - /lodash.castarray@4.4.0: - resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==} - dev: true - - /lodash.debounce@4.0.8: - resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} - dev: true - - /lodash.isplainobject@4.0.6: - resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} - dev: true - - /lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - dev: true - - /lodash.sortby@4.7.0: - resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} - dev: true - - /lodash@4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - dev: true - - /loose-envify@1.4.0: - resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} - hasBin: true - dependencies: - js-tokens: 4.0.0 - - /lowercase-keys@2.0.0: - resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} - engines: {node: '>=8'} - dev: false - - /lru-cache@10.0.1: - resolution: {integrity: sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==} - engines: {node: 14 || >=16.14} - dev: false - - /lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - dependencies: - yallist: 3.1.1 - dev: true - - /lru-cache@6.0.0: - resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} - engines: {node: '>=10'} - dependencies: - yallist: 4.0.0 - dev: true - - /lru_map@0.3.3: - resolution: {integrity: sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==} - dev: false - - /lz-string@1.5.0: - resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} - hasBin: true - dev: true - - /magic-string@0.25.9: - resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} - dependencies: - sourcemap-codec: 1.4.8 - dev: true - - /magic-string@0.27.0: - resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==} - engines: {node: '>=12'} - dependencies: - '@jridgewell/sourcemap-codec': 1.4.15 - dev: false - - /make-dir@4.0.0: - resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} - engines: {node: '>=10'} - dependencies: - semver: 7.5.4 - dev: true - - /makeerror@1.0.12: - resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} - dependencies: - tmpl: 1.0.5 - dev: true - - /map-obj@1.0.1: - resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==} - engines: {node: '>=0.10.0'} - dev: false - - /map-obj@4.3.0: - resolution: {integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==} - engines: {node: '>=8'} - dev: false - - /mapbox-gl@1.13.3: - resolution: {integrity: sha512-p8lJFEiqmEQlyv+DQxFAOG/XPWN0Wp7j/Psq93Zywz7qt9CcUKFYDBOoOEKzqe6gudHVJY8/Bhqw6VDpX2lSBg==} - engines: {node: '>=6.4.0'} - dependencies: - '@mapbox/geojson-rewind': 0.5.2 - '@mapbox/geojson-types': 1.0.2 - '@mapbox/jsonlint-lines-primitives': 2.0.2 - '@mapbox/mapbox-gl-supported': 1.5.0(mapbox-gl@1.13.3) - '@mapbox/point-geometry': 0.1.0 - '@mapbox/tiny-sdf': 1.2.5 - '@mapbox/unitbezier': 0.0.0 - '@mapbox/vector-tile': 1.3.1 - '@mapbox/whoots-js': 3.1.0 - csscolorparser: 1.0.3 - earcut: 2.2.4 - geojson-vt: 3.2.1 - gl-matrix: 3.4.3 - grid-index: 1.1.0 - murmurhash-js: 1.0.0 - pbf: 3.2.1 - potpack: 1.0.2 - quickselect: 2.0.0 - rw: 1.3.3 - supercluster: 7.1.5 - tinyqueue: 2.0.3 - vt-pbf: 3.1.3 - dev: false - - /memoize-one@5.2.1: - resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==} - dev: false - - /meow@6.1.1: - resolution: {integrity: sha512-3YffViIt2QWgTy6Pale5QpopX/IvU3LPL03jOTqp6pGj3VjesdO/U8CuHMKpnQr4shCNCM5fd5XFFvIIl6JBHg==} - engines: {node: '>=8'} - dependencies: - '@types/minimist': 1.2.2 - camelcase-keys: 6.2.2 - decamelize-keys: 1.1.1 - hard-rejection: 2.1.0 - minimist-options: 4.1.0 - normalize-package-data: 2.5.0 - read-pkg-up: 7.0.1 - redent: 3.0.0 - trim-newlines: 3.0.1 - type-fest: 0.13.1 - yargs-parser: 18.1.3 - dev: false - - /merge-deep@3.0.3: - resolution: {integrity: sha512-qtmzAS6t6grwEkNrunqTBdn0qKwFgNWvlxUbAV8es9M7Ot1EbyApytCnvE0jALPa46ZpKDUo527kKiaWplmlFA==} - engines: {node: '>=0.10.0'} - dependencies: - arr-union: 3.1.0 - clone-deep: 0.2.4 - kind-of: 3.2.2 - dev: true - - /merge-stream@2.0.0: - resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - dev: true - - /merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} - dev: true - - /micromatch@4.0.5: - resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} - engines: {node: '>=8.6'} - dependencies: - braces: 3.0.3 - picomatch: 2.3.1 - dev: true - - /mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} - - /mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} - dependencies: - mime-db: 1.52.0 - - /mimic-fn@2.1.0: - resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} - engines: {node: '>=6'} - dev: true - - /mimic-response@1.0.1: - resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} - engines: {node: '>=4'} - dev: false - - /mimic-response@3.1.0: - resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} - engines: {node: '>=10'} - dev: false - - /min-document@2.19.0: - resolution: {integrity: sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==} - dependencies: - dom-walk: 0.1.2 - dev: false - - /min-indent@1.0.1: - resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} - engines: {node: '>=4'} - - /minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - dependencies: - brace-expansion: 1.1.11 - dev: true - - /minimatch@5.1.6: - resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} - engines: {node: '>=10'} - dependencies: - brace-expansion: 2.0.1 - dev: true - - /minimatch@7.4.6: - resolution: {integrity: sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==} - engines: {node: '>=10'} - dependencies: - brace-expansion: 2.0.1 - dev: false - - /minimist-options@4.1.0: - resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==} - engines: {node: '>= 6'} - dependencies: - arrify: 1.0.1 - is-plain-obj: 1.1.0 - kind-of: 6.0.3 - dev: false - - /minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - - /minipass@4.2.8: - resolution: {integrity: sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==} - engines: {node: '>=8'} - dev: false - - /minipass@7.0.3: - resolution: {integrity: sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==} - engines: {node: '>=16 || 14 >=14.17'} - dev: false - - /mitt@3.0.0: - resolution: {integrity: sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ==} - dev: true - - /mixin-object@2.0.1: - resolution: {integrity: sha512-ALGF1Jt9ouehcaXaHhn6t1yGWRqGaHkPFndtFVHfZXOvkIZ/yoGaSi0AHVTafb3ZBGg4dr/bDwnaEKqCXzchMA==} - engines: {node: '>=0.10.0'} - dependencies: - for-in: 0.1.8 - is-extendable: 0.1.1 - dev: true - - /mjolnir.js@2.7.1: - resolution: {integrity: sha512-72BeUWgTv2cj5aZQKpwL8caNUFhXZ9bDm1hxpNj70XJQ62IBnTZmtv/WPxJvtaVNhzNo+D2U8O6ryNI0zImYcw==} - engines: {node: '>= 4', npm: '>= 3'} - dependencies: - '@types/hammerjs': 2.0.41 - hammerjs: 2.0.8 - dev: false - - /mkdirp-classic@0.5.3: - resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} - dev: true - - /ms@2.1.2: - resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - - /ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - dev: true - - /murmurhash-js@1.0.0: - resolution: {integrity: sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==} - dev: false - - /mz@2.7.0: - resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} - dependencies: - any-promise: 1.3.0 - object-assign: 4.1.1 - thenify-all: 1.6.0 - dev: true - - /nanoid@3.3.6: - resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - dev: true - - /natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - dev: true - - /nice-try@1.0.5: - resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==} - dev: true - - /node-fetch@1.7.3: - resolution: {integrity: sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==} - dependencies: - encoding: 0.1.13 - is-stream: 1.1.0 - dev: false - - /node-fetch@2.6.7: - resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==} - engines: {node: 4.x || >=6.0.0} - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - dependencies: - whatwg-url: 5.0.0 - dev: true - - /node-fetch@2.7.0: - resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} - engines: {node: 4.x || >=6.0.0} - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - dependencies: - whatwg-url: 5.0.0 - dev: false - - /node-int64@0.4.0: - resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} - dev: true - - /node-releases@2.0.13: - resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==} - dev: true - - /normalize-package-data@2.5.0: - resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} - dependencies: - hosted-git-info: 2.8.9 - resolve: 1.22.4 - semver: 5.7.2 - validate-npm-package-license: 3.0.4 - dev: false - - /normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} - - /normalize-range@0.1.2: - resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} - engines: {node: '>=0.10.0'} - dev: true - - /normalize-scroll-left@0.1.2: - resolution: {integrity: sha512-F9YMRls0zCF6BFIE2YnXDRpHPpfd91nOIaNdDgrx5YMoPLo8Wqj+6jNXHQsYBavJeXP4ww8HCt0xQAKc5qk2Fg==} - dev: false - - /normalize-url@6.1.0: - resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} - engines: {node: '>=10'} - dev: false - - /npm-run-path@4.0.1: - resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} - engines: {node: '>=8'} - dependencies: - path-key: 3.1.1 - dev: true - - /nwsapi@2.2.7: - resolution: {integrity: sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==} - dev: true - - /object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} - - /object-hash@3.0.0: - resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} - engines: {node: '>= 6'} - dev: true - - /object-inspect@1.12.3: - resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==} - dev: true - - /object-inspect@1.13.1: - resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} - dev: true - - /object-is@1.1.5: - resolution: {integrity: sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - dev: true - - /object-keys@1.1.1: - resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} - engines: {node: '>= 0.4'} - dev: true - - /object.assign@4.1.4: - resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - has-symbols: 1.0.3 - object-keys: 1.1.1 - dev: true - - /object.entries@1.1.6: - resolution: {integrity: sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.22.1 - dev: true - - /object.fromentries@2.0.6: - resolution: {integrity: sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.22.1 - dev: true - - /object.groupby@1.0.0: - resolution: {integrity: sha512-70MWG6NfRH9GnbZOikuhPPYzpUpof9iW2J9E4dW7FXTqPNb6rllE6u39SKwwiNh8lCwX3DDb5OgcKGiEBrTTyw==} - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.22.1 - get-intrinsic: 1.2.1 - dev: true - - /object.hasown@1.1.2: - resolution: {integrity: sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==} - dependencies: - define-properties: 1.2.0 - es-abstract: 1.22.1 - dev: true - - /object.values@1.1.6: - resolution: {integrity: sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.22.1 - dev: true - - /obstruction@2.1.0: - resolution: {integrity: sha512-Xwuug8ol5Te5tCdQfCDztF1wbTz0vGfX8uxjHu5FTR53p6Yb3d6WAeMrUtHq/+bsWmThWJLqEUY1VbVUIJm2fg==} - engines: {node: '>=0.10.0'} - dependencies: - ap: 0.2.0 - dot-prop: 2.1.0 - is-object: 1.0.2 - isarray: 0.0.1 - map-obj: 1.0.1 - dev: false - - /once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - dependencies: - wrappy: 1.0.2 - - /onetime@5.1.2: - resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} - engines: {node: '>=6'} - dependencies: - mimic-fn: 2.1.0 - dev: true - - /optionator@0.9.3: - resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} - engines: {node: '>= 0.8.0'} - dependencies: - '@aashutoshrathi/word-wrap': 1.2.6 - deep-is: 0.1.4 - fast-levenshtein: 2.0.6 - levn: 0.4.1 - prelude-ls: 1.2.1 - type-check: 0.4.0 - dev: true - - /os-homedir@1.0.2: - resolution: {integrity: sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==} - engines: {node: '>=0.10.0'} - dev: true - - /p-cancelable@2.1.1: - resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} - engines: {node: '>=8'} - dev: false - - /p-limit@2.3.0: - resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} - engines: {node: '>=6'} - dependencies: - p-try: 2.2.0 - - /p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} - dependencies: - yocto-queue: 0.1.0 - - /p-locate@4.1.0: - resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} - engines: {node: '>=8'} - dependencies: - p-limit: 2.3.0 - - /p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} - dependencies: - p-limit: 3.1.0 - - /p-try@2.2.0: - resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} - engines: {node: '>=6'} - - /parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} - dependencies: - callsites: 3.1.0 - dev: true - - /parse-json@5.2.0: - resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} - engines: {node: '>=8'} - dependencies: - '@babel/code-frame': 7.22.10 - error-ex: 1.3.2 - json-parse-even-better-errors: 2.3.1 - lines-and-columns: 1.2.4 - - /parse-passwd@1.0.0: - resolution: {integrity: sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==} - engines: {node: '>=0.10.0'} - dev: true - - /parse5@6.0.1: - resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} - dev: true - - /path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - - /path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - dev: true - - /path-key@2.0.1: - resolution: {integrity: sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==} - engines: {node: '>=4'} - dev: true - - /path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - dev: true - - /path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - - /path-scurry@1.10.1: - resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==} - engines: {node: '>=16 || 14 >=14.17'} - dependencies: - lru-cache: 10.0.1 - minipass: 7.0.3 - dev: false - - /path-to-regexp@1.8.0: - resolution: {integrity: sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==} - dependencies: - isarray: 0.0.1 - dev: false - - /path-type@4.0.0: - resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} - engines: {node: '>=8'} - dev: true - - /pbf@3.2.1: - resolution: {integrity: sha512-ClrV7pNOn7rtmoQVF4TS1vyU0WhYRnP92fzbfF75jAIwpnzdJXf8iTd4CMEqO4yUenH6NDqLiwjqlh6QgZzgLQ==} - hasBin: true - dependencies: - ieee754: 1.2.1 - resolve-protobuf-schema: 2.1.0 - dev: false - - /pend@1.2.0: - resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} - dev: true - - /performance-now@2.1.0: - resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} - dev: false - - /picocolors@1.0.0: - resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} - dev: true - - /picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} - - /pify@2.3.0: - resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} - engines: {node: '>=0.10.0'} - dev: true - - /pirates@4.0.6: - resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} - engines: {node: '>= 6'} - dev: true - - /pkg-dir@4.2.0: - resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} - engines: {node: '>=8'} - dependencies: - find-up: 4.1.0 - dev: true - - /popper.js@1.16.1: - resolution: {integrity: sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==} - deprecated: You can find the new Popper v2 at @popperjs/core, this package is dedicated to the legacy v1 - dev: false - - /postcss-import@15.1.0(postcss@8.4.28): - resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} - engines: {node: '>=14.0.0'} - peerDependencies: - postcss: ^8.0.0 - dependencies: - postcss: 8.4.28 - postcss-value-parser: 4.2.0 - read-cache: 1.0.0 - resolve: 1.22.4 - dev: true - - /postcss-js@4.0.1(postcss@8.4.28): - resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} - engines: {node: ^12 || ^14 || >= 16} - peerDependencies: - postcss: ^8.4.21 - dependencies: - camelcase-css: 2.0.1 - postcss: 8.4.28 - dev: true - - /postcss-load-config@4.0.1(postcss@8.4.28): - resolution: {integrity: sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==} - engines: {node: '>= 14'} - peerDependencies: - postcss: '>=8.0.9' - ts-node: '>=9.0.0' - peerDependenciesMeta: - postcss: - optional: true - ts-node: - optional: true - dependencies: - lilconfig: 2.1.0 - postcss: 8.4.28 - yaml: 2.3.1 - dev: true - - /postcss-nested@6.0.1(postcss@8.4.28): - resolution: {integrity: sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==} - engines: {node: '>=12.0'} - peerDependencies: - postcss: ^8.2.14 - dependencies: - postcss: 8.4.28 - postcss-selector-parser: 6.0.13 - dev: true - - /postcss-selector-parser@6.0.10: - resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==} - engines: {node: '>=4'} - dependencies: - cssesc: 3.0.0 - util-deprecate: 1.0.2 - dev: true - - /postcss-selector-parser@6.0.13: - resolution: {integrity: sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==} - engines: {node: '>=4'} - dependencies: - cssesc: 3.0.0 - util-deprecate: 1.0.2 - dev: true - - /postcss-value-parser@4.2.0: - resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - dev: true - - /postcss@8.4.28: - resolution: {integrity: sha512-Z7V5j0cq8oEKyejIKfpD8b4eBy9cwW2JWPk0+fB1HOAMsfHbnAXLLS+PfVWlzMSLQaWttKDt607I0XHmpE67Vw==} - engines: {node: ^10 || ^12 || >=14} - dependencies: - nanoid: 3.3.6 - picocolors: 1.0.0 - source-map-js: 1.0.2 - dev: true - - /potpack@1.0.2: - resolution: {integrity: sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==} - dev: false - - /prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} - dev: true - - /pretty-bytes@5.6.0: - resolution: {integrity: sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==} - engines: {node: '>=6'} - dev: true - - /pretty-bytes@6.1.1: - resolution: {integrity: sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==} - engines: {node: ^14.13.1 || >=16.0.0} - dev: true - - /pretty-format@27.5.1: - resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - ansi-regex: 5.0.1 - ansi-styles: 5.2.0 - react-is: 17.0.2 - dev: true - - /pretty-format@29.6.3: - resolution: {integrity: sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/schemas': 29.6.3 - ansi-styles: 5.2.0 - react-is: 18.2.0 - dev: true - - /process@0.11.10: - resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} - engines: {node: '>= 0.6.0'} - dev: false - - /progress@2.0.3: - resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} - engines: {node: '>=0.4.0'} - - /promise@7.3.1: - resolution: {integrity: sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==} - dependencies: - asap: 2.0.6 - dev: false - - /prompts@2.4.2: - resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} - engines: {node: '>= 6'} - dependencies: - kleur: 3.0.3 - sisteransi: 1.0.5 - dev: true - - /prop-types@15.8.1: - resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} - dependencies: - loose-envify: 1.4.0 - object-assign: 4.1.1 - react-is: 16.13.1 - - /protocol-buffers-schema@3.6.0: - resolution: {integrity: sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==} - dev: false - - /proxy-from-env@1.1.0: - resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - - /psl@1.9.0: - resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} - dev: true - - /pump@3.0.0: - resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} - dependencies: - end-of-stream: 1.4.4 - once: 1.4.0 - - /punycode@2.3.0: - resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} - engines: {node: '>=6'} - dev: true - - /punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - dev: true - - /puppeteer-core@19.11.1: - resolution: {integrity: sha512-qcuC2Uf0Fwdj9wNtaTZ2OvYRraXpAK+puwwVW8ofOhOgLPZyz1c68tsorfIZyCUOpyBisjr+xByu7BMbEYMepA==} - engines: {node: '>=14.14.0'} - peerDependencies: - typescript: '>= 4.7.4' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@puppeteer/browsers': 0.5.0 - chromium-bidi: 0.4.7(devtools-protocol@0.0.1107588) - cross-fetch: 3.1.5 - debug: 4.3.4 - devtools-protocol: 0.0.1107588 - extract-zip: 2.0.1 - https-proxy-agent: 5.0.1 - proxy-from-env: 1.1.0 - tar-fs: 2.1.1 - unbzip2-stream: 1.4.3 - ws: 8.13.0 - transitivePeerDependencies: - - bufferutil - - encoding - - supports-color - - utf-8-validate - dev: true - - /puppeteer@19.11.1: - resolution: {integrity: sha512-39olGaX2djYUdhaQQHDZ0T0GwEp+5f9UB9HmEP0qHfdQHIq0xGQZuAZ5TLnJIc/88SrPLpEflPC+xUqOTv3c5g==} - requiresBuild: true - dependencies: - '@puppeteer/browsers': 0.5.0 - cosmiconfig: 8.1.3 - https-proxy-agent: 5.0.1 - progress: 2.0.3 - proxy-from-env: 1.1.0 - puppeteer-core: 19.11.1 - transitivePeerDependencies: - - bufferutil - - encoding - - supports-color - - typescript - - utf-8-validate - dev: true - - /qr-scanner@1.4.2: - resolution: {integrity: sha512-kV1yQUe2FENvn59tMZW6mOVfpq9mGxGf8l6+EGaXUOd4RBOLg7tRC83OrirM5AtDvZRpdjdlXURsHreAOSPOUw==} - dependencies: - '@types/offscreencanvas': 2019.7.0 - dev: false - - /query-string@6.14.1: - resolution: {integrity: sha512-XDxAeVmpfu1/6IjyT/gXHOl+S0vQ9owggJ30hhWKdHAsNPOcasn5o9BW0eejZqL2e4vMjhAxoW3jVHcD6mbcYw==} - engines: {node: '>=6'} - dependencies: - decode-uri-component: 0.2.2 - filter-obj: 1.1.0 - split-on-first: 1.1.0 - strict-uri-encode: 2.0.0 - dev: false - - /query-string@7.1.3: - resolution: {integrity: sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==} - engines: {node: '>=6'} - dependencies: - decode-uri-component: 0.2.2 - filter-obj: 1.1.0 - split-on-first: 1.1.0 - strict-uri-encode: 2.0.0 - dev: false - - /querystringify@2.2.0: - resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} - - /queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - dev: true - - /quick-lru@4.0.1: - resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==} - engines: {node: '>=8'} - dev: false - - /quick-lru@5.1.1: - resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} - engines: {node: '>=10'} - dev: false - - /quickselect@2.0.0: - resolution: {integrity: sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==} - dev: false - - /raf@3.4.1: - resolution: {integrity: sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==} - dependencies: - performance-now: 2.1.0 - dev: false - - /randombytes@2.1.0: - resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} - dependencies: - safe-buffer: 5.2.1 - dev: true - - /react-dom@18.2.0(react@18.2.0): - resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} - peerDependencies: - react: ^18.2.0 - dependencies: - loose-envify: 1.4.0 - react: 18.2.0 - scheduler: 0.23.0 - - /react-event-listener@0.6.6(react@18.2.0): - resolution: {integrity: sha512-+hCNqfy7o9wvO6UgjqFmBzARJS7qrNoda0VqzvOuioEpoEXKutiKuv92dSz6kP7rYLmyHPyYNLesi5t/aH1gfw==} - peerDependencies: - react: ^16.3.0 - dependencies: - '@babel/runtime': 7.23.5 - prop-types: 15.8.1 - react: 18.2.0 - warning: 4.0.3 - dev: false - - /react-fast-compare@3.2.2: - resolution: {integrity: sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==} - dev: false - - /react-is@16.13.1: - resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} - - /react-is@17.0.2: - resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} - dev: true - - /react-is@18.2.0: - resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} - dev: true - - /react-jss@8.6.1(react@18.2.0): - resolution: {integrity: sha512-SH6XrJDJkAphp602J14JTy3puB2Zxz1FkM3bKVE8wON+va99jnUTKWnzGECb3NfIn9JPR5vHykge7K3/A747xQ==} - engines: {node: '>=4'} - peerDependencies: - react: '>=0.13' - dependencies: - hoist-non-react-statics: 2.5.5 - jss: 9.8.7 - jss-preset-default: 4.5.0(jss@9.8.7) - prop-types: 15.8.1 - react: 18.2.0 - theming: 1.3.0(react@18.2.0) - dev: false - - /react-lifecycles-compat@3.0.4: - resolution: {integrity: sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==} - dev: false - - /react-map-gl@5.3.21(react@18.2.0): - resolution: {integrity: sha512-hNVYiPBjgfVIcDV70OU9QnzvNCI1NhLm5OHjyY1rKPOKqzV4m9jjuXEKUaWC72vqIHk1Dzb+gG78xWOpqVi6uw==} - engines: {node: '>= 4', npm: '>= 3'} - peerDependencies: - react: '>=16.3.0' - dependencies: - '@babel/runtime': 7.22.11 - '@types/geojson': 7946.0.10 - '@types/mapbox-gl': 2.7.13 - mapbox-gl: 1.13.3 - mjolnir.js: 2.7.1 - prop-types: 15.8.1 - react: 18.2.0 - resize-observer-polyfill: 1.5.1 - viewport-mercator-project: 7.0.4 - dev: false - - /react-measure@2.5.2(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-M+rpbTLWJ3FD6FXvYV6YEGvQ5tMayQ3fGrZhRPHrE9bVlBYfDCLuDcgNttYfk8IqfOI03jz6cbpqMRTUclQnaA==} - peerDependencies: - react: '>0.13.0' - react-dom: '>0.13.0' - dependencies: - '@babel/runtime': 7.22.11 - get-node-dimensions: 1.2.1 - prop-types: 15.8.1 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - resize-observer-polyfill: 1.5.1 - dev: false - - /react-player@2.12.0(react@18.2.0): - resolution: {integrity: sha512-rymLRz/2GJJD+Wc01S7S+i9pGMFYnNmQibR2gVE3KmHJCBNN8BhPAlOPTGZtn1uKpJ6p4RPLlzPQ1OLreXd8gw==} - peerDependencies: - react: '>=16.6.0' - dependencies: - deepmerge: 4.3.1 - load-script: 1.0.0 - memoize-one: 5.2.1 - prop-types: 15.8.1 - react: 18.2.0 - react-fast-compare: 3.2.2 - dev: false - - /react-redux@5.1.2(react@18.2.0)(redux@4.2.1): - resolution: {integrity: sha512-Ns1G0XXc8hDyH/OcBHOxNgQx9ayH3SPxBnFCOidGKSle8pKihysQw2rG/PmciUQRoclhVBO8HMhiRmGXnDja9Q==} - peerDependencies: - react: ^0.14.0 || ^15.0.0-0 || ^16.0.0-0 - redux: ^2.0.0 || ^3.0.0 || ^4.0.0-0 - dependencies: - '@babel/runtime': 7.22.11 - hoist-non-react-statics: 3.3.2 - invariant: 2.2.4 - loose-envify: 1.4.0 - prop-types: 15.8.1 - react: 18.2.0 - react-is: 16.13.1 - react-lifecycles-compat: 3.0.4 - redux: 4.2.1 - dev: false - - /react-refresh@0.14.0: - resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==} - engines: {node: '>=0.10.0'} - dev: true - - /react-router-dom@5.3.4(react@18.2.0): - resolution: {integrity: sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ==} - peerDependencies: - react: '>=15' - dependencies: - '@babel/runtime': 7.22.11 - history: 4.10.1 - loose-envify: 1.4.0 - prop-types: 15.8.1 - react: 18.2.0 - react-router: 5.3.4(react@18.2.0) - tiny-invariant: 1.3.1 - tiny-warning: 1.0.3 - dev: false - - /react-router-redux@4.0.8: - resolution: {integrity: sha512-lzlK+S6jZnn17BZbzBe6F8ok3YAhGAUlyWgRu3cz5mT199gKxfem5lNu3qcgzRiVhNEOFVG0/pdT+1t4aWhoQw==} - dev: false - - /react-router@5.3.4(react@18.2.0): - resolution: {integrity: sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==} - peerDependencies: - react: '>=15' - dependencies: - '@babel/runtime': 7.22.11 - history: 4.10.1 - hoist-non-react-statics: 3.3.2 - loose-envify: 1.4.0 - path-to-regexp: 1.8.0 - prop-types: 15.8.1 - react: 18.2.0 - react-is: 16.13.1 - tiny-invariant: 1.3.1 - tiny-warning: 1.0.3 - dev: false - - /react-shallow-renderer@16.15.0(react@18.2.0): - resolution: {integrity: sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==} - peerDependencies: - react: ^16.0.0 || ^17.0.0 || ^18.0.0 - dependencies: - object-assign: 4.1.1 - react: 18.2.0 - react-is: 18.2.0 - dev: true - - /react-test-renderer@18.2.0(react@18.2.0): - resolution: {integrity: sha512-JWD+aQ0lh2gvh4NM3bBM42Kx+XybOxCpgYK7F8ugAlpaTSnWsX+39Z4XkOykGZAHrjwwTZT3x3KxswVWxHPUqA==} - peerDependencies: - react: ^18.2.0 - dependencies: - react: 18.2.0 - react-is: 18.2.0 - react-shallow-renderer: 16.15.0(react@18.2.0) - scheduler: 0.23.0 - dev: true - - /react-transition-group@2.9.0(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==} - peerDependencies: - react: '>=15.0.0' - react-dom: '>=15.0.0' - dependencies: - dom-helpers: 3.4.0 - loose-envify: 1.4.0 - prop-types: 15.8.1 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - react-lifecycles-compat: 3.0.4 - dev: false - - /react@18.2.0: - resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} - engines: {node: '>=0.10.0'} - dependencies: - loose-envify: 1.4.0 - - /read-cache@1.0.0: - resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} - dependencies: - pify: 2.3.0 - dev: true - - /read-pkg-up@7.0.1: - resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} - engines: {node: '>=8'} - dependencies: - find-up: 4.1.0 - read-pkg: 5.2.0 - type-fest: 0.8.1 - dev: false - - /read-pkg@5.2.0: - resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==} - engines: {node: '>=8'} - dependencies: - '@types/normalize-package-data': 2.4.1 - normalize-package-data: 2.5.0 - parse-json: 5.2.0 - type-fest: 0.6.0 - dev: false - - /readable-stream@3.6.2: - resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} - engines: {node: '>= 6'} - dependencies: - inherits: 2.0.4 - string_decoder: 1.3.0 - util-deprecate: 1.0.2 - dev: true - - /readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} - dependencies: - picomatch: 2.3.1 - - /recompose@0.27.1(react@18.2.0): - resolution: {integrity: sha512-p7xsyi/rfNjHfdP7vPU02uSFa+Q1eHhjKrvO+3+kRP4Ortj+MxEmpmd+UQtBGM2D2iNAjzNI5rCyBKp9Ob5McA==} - peerDependencies: - react: ^0.14.0 || ^15.0.0 || ^16.0.0 - dependencies: - babel-runtime: 6.26.0 - change-emitter: 0.1.6 - fbjs: 0.8.18 - hoist-non-react-statics: 2.5.5 - react: 18.2.0 - react-lifecycles-compat: 3.0.4 - symbol-observable: 1.2.0 - dev: false - - /recompose@0.28.2(react@18.2.0): - resolution: {integrity: sha512-baVNKQBQAAAuLRnv6Cb/6/j59a1BVj6c6Pags1KXVyRB0yPfQVUZtuAUnqHDBXoR8iXPrLGWE4RNtCQ/AaRP3g==} - peerDependencies: - react: ^0.14.0 || ^15.0.0 || ^16.0.0 - dependencies: - '@babel/runtime': 7.0.0-beta.56 - change-emitter: 0.1.6 - fbjs: 0.8.18 - hoist-non-react-statics: 2.5.5 - react: 18.2.0 - react-lifecycles-compat: 3.0.4 - symbol-observable: 1.2.0 - dev: false - - /redent@3.0.0: - resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} - engines: {node: '>=8'} - dependencies: - indent-string: 4.0.0 - strip-indent: 3.0.0 - - /reduce-reducers@1.0.4: - resolution: {integrity: sha512-Mb2WZ2bJF597exiqX7owBzrqJ74DHLK3yOQjCyPAaNifRncE8OD0wFIuoMhXxTnHK07+8zZ2SJEKy/qtiyR7vw==} - dev: false - - /redux-seamless-immutable@0.4.0: - resolution: {integrity: sha512-/oS3fhrize9D3RSHemgJxVllohybRrad5IjccotFy8Ni4IKAPTtX1mqszpiCIl12+7v0dNqBpq6ES6R236AliQ==} - dependencies: - react-router-redux: 4.0.8 - seamless-immutable: 7.1.4 - dev: false - - /redux-thunk@2.4.2(redux@4.2.1): - resolution: {integrity: sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==} - peerDependencies: - redux: ^4 - dependencies: - redux: 4.2.1 - dev: false - - /redux@4.2.1: - resolution: {integrity: sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==} - dependencies: - '@babel/runtime': 7.22.11 - dev: false - - /reflect.getprototypeof@1.0.3: - resolution: {integrity: sha512-TTAOZpkJ2YLxl7mVHWrNo3iDMEkYlva/kgFcXndqMgbo/AZUmmavEkdXV+hXtE4P8xdyEKRzalaFqZVuwIk/Nw==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.22.1 - get-intrinsic: 1.2.1 - globalthis: 1.0.3 - which-builtin-type: 1.1.3 - dev: true - - /regenerate-unicode-properties@10.1.1: - resolution: {integrity: sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==} - engines: {node: '>=4'} - dependencies: - regenerate: 1.4.2 - dev: true - - /regenerate@1.4.2: - resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==} - dev: true - - /regenerator-runtime@0.11.1: - resolution: {integrity: sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==} - dev: false - - /regenerator-runtime@0.12.1: - resolution: {integrity: sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==} - dev: false - - /regenerator-runtime@0.14.0: - resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==} - - /regenerator-transform@0.15.2: - resolution: {integrity: sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==} - dependencies: - '@babel/runtime': 7.23.5 - dev: true - - /regexp.prototype.flags@1.5.0: - resolution: {integrity: sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - functions-have-names: 1.2.3 - dev: true - - /regexp.prototype.flags@1.5.1: - resolution: {integrity: sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.5 - define-properties: 1.2.1 - set-function-name: 2.0.1 - dev: true - - /regexpu-core@5.3.2: - resolution: {integrity: sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==} - engines: {node: '>=4'} - dependencies: - '@babel/regjsgen': 0.8.0 - regenerate: 1.4.2 - regenerate-unicode-properties: 10.1.1 - regjsparser: 0.9.1 - unicode-match-property-ecmascript: 2.0.0 - unicode-match-property-value-ecmascript: 2.1.0 - dev: true - - /regjsparser@0.9.1: - resolution: {integrity: sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==} - hasBin: true - dependencies: - jsesc: 0.5.0 - dev: true - - /require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} - dev: true - - /require-from-string@2.0.2: - resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} - engines: {node: '>=0.10.0'} - dev: true - - /requireindex@1.2.0: - resolution: {integrity: sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==} - engines: {node: '>=0.10.5'} - dev: true - - /requires-port@1.0.0: - resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} - dev: true - - /resize-observer-polyfill@1.5.1: - resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==} - dev: false - - /resolve-alpn@1.2.1: - resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} - dev: false - - /resolve-cwd@3.0.0: - resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} - engines: {node: '>=8'} - dependencies: - resolve-from: 5.0.0 - dev: true - - /resolve-dir@0.1.1: - resolution: {integrity: sha512-QxMPqI6le2u0dCLyiGzgy92kjkkL6zO0XyvHzjdTNH3zM6e5Hz3BwG6+aEyNgiQ5Xz6PwTwgQEj3U50dByPKIA==} - engines: {node: '>=0.10.0'} - dependencies: - expand-tilde: 1.2.2 - global-modules: 0.2.3 - dev: true - - /resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} - dev: true - - /resolve-from@5.0.0: - resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} - engines: {node: '>=8'} - dev: true - - /resolve-pathname@3.0.0: - resolution: {integrity: sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==} - dev: false - - /resolve-protobuf-schema@2.1.0: - resolution: {integrity: sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==} - dependencies: - protocol-buffers-schema: 3.6.0 - dev: false - - /resolve.exports@1.1.1: - resolution: {integrity: sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ==} - engines: {node: '>=10'} - dev: true - - /resolve@1.22.4: - resolution: {integrity: sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==} - hasBin: true - dependencies: - is-core-module: 2.13.0 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - - /resolve@1.22.8: - resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} - hasBin: true - dependencies: - is-core-module: 2.13.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - dev: true - - /resolve@2.0.0-next.4: - resolution: {integrity: sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==} - hasBin: true - dependencies: - is-core-module: 2.13.0 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - dev: true - - /responselike@2.0.1: - resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==} - dependencies: - lowercase-keys: 2.0.0 - dev: false - - /reusify@1.0.4: - resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - dev: true - - /rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - hasBin: true - dependencies: - glob: 7.2.3 - dev: true - - /rollup-plugin-terser@7.0.2(rollup@2.79.1): - resolution: {integrity: sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==} - deprecated: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-terser - peerDependencies: - rollup: ^2.0.0 - dependencies: - '@babel/code-frame': 7.23.5 - jest-worker: 26.6.2 - rollup: 2.79.1 - serialize-javascript: 4.0.0 - terser: 5.24.0 - dev: true - - /rollup@2.79.1: - resolution: {integrity: sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==} - engines: {node: '>=10.0.0'} - hasBin: true - optionalDependencies: - fsevents: 2.3.3 - dev: true - - /rollup@3.28.1: - resolution: {integrity: sha512-R9OMQmIHJm9znrU3m3cpE8uhN0fGdXiawME7aZIpQqvpS/85+Vt1Hq1/yVIcYfOmaQiHjvXkQAoJukvLpau6Yw==} - engines: {node: '>=14.18.0', npm: '>=8.0.0'} - hasBin: true - optionalDependencies: - fsevents: 2.3.3 - dev: true - - /run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - dependencies: - queue-microtask: 1.2.3 - dev: true - - /rw@1.3.3: - resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} - dev: false - - /rxjs@7.8.1: - resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} - dependencies: - tslib: 2.6.2 - dev: true - - /safe-array-concat@1.0.0: - resolution: {integrity: sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==} - engines: {node: '>=0.4'} - dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 - has-symbols: 1.0.3 - isarray: 2.0.5 - dev: true - - /safe-array-concat@1.0.1: - resolution: {integrity: sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==} - engines: {node: '>=0.4'} - dependencies: - call-bind: 1.0.5 - get-intrinsic: 1.2.2 - has-symbols: 1.0.3 - isarray: 2.0.5 - dev: true - - /safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - dev: true - - /safe-regex-test@1.0.0: - resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} - dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 - is-regex: 1.1.4 - dev: true - - /safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - - /saxes@5.0.1: - resolution: {integrity: sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==} - engines: {node: '>=10'} - dependencies: - xmlchars: 2.2.0 - dev: true - - /scheduler@0.23.0: - resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} - dependencies: - loose-envify: 1.4.0 - - /seamless-immutable@7.1.4: - resolution: {integrity: sha512-XiUO1QP4ki4E2PHegiGAlu6r82o5A+6tRh7IkGGTVg/h+UoeX4nFBeCGPOhb4CYjvkqsfm/TUtvOMYC1xmV30A==} - dev: false - - /semver@5.7.2: - resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} - hasBin: true - - /semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - dev: true - - /semver@7.5.4: - resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} - engines: {node: '>=10'} - hasBin: true - dependencies: - lru-cache: 6.0.0 - dev: true - - /serialize-javascript@4.0.0: - resolution: {integrity: sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==} - dependencies: - randombytes: 2.1.0 - dev: true - - /set-function-length@1.1.1: - resolution: {integrity: sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==} - engines: {node: '>= 0.4'} - dependencies: - define-data-property: 1.1.1 - get-intrinsic: 1.2.2 - gopd: 1.0.1 - has-property-descriptors: 1.0.1 - dev: true - - /set-function-name@2.0.1: - resolution: {integrity: sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==} - engines: {node: '>= 0.4'} - dependencies: - define-data-property: 1.1.1 - functions-have-names: 1.2.3 - has-property-descriptors: 1.0.1 - dev: true - - /setimmediate@1.0.5: - resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} - dev: false - - /shallow-clone@0.1.2: - resolution: {integrity: sha512-J1zdXCky5GmNnuauESROVu31MQSnLoYvlyEn6j2Ztk6Q5EHFIhxkMhYcv6vuDzl2XEzoRr856QwzMgWM/TmZgw==} - engines: {node: '>=0.10.0'} - dependencies: - is-extendable: 0.1.1 - kind-of: 2.0.1 - lazy-cache: 0.2.7 - mixin-object: 2.0.1 - dev: true - - /shebang-command@1.2.0: - resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==} - engines: {node: '>=0.10.0'} - dependencies: - shebang-regex: 1.0.0 - dev: true - - /shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - dependencies: - shebang-regex: 3.0.0 - dev: true - - /shebang-regex@1.0.0: - resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==} - engines: {node: '>=0.10.0'} - dev: true - - /shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - dev: true - - /side-channel@1.0.4: - resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} - dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 - object-inspect: 1.12.3 - dev: true - - /signal-exit@3.0.7: - resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - dev: true - - /sisteransi@1.0.5: - resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} - dev: true - - /slash@3.0.0: - resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} - engines: {node: '>=8'} - dev: true - - /source-map-js@1.0.2: - resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} - engines: {node: '>=0.10.0'} - dev: true - - /source-map-support@0.5.21: - resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} - dependencies: - buffer-from: 1.1.2 - source-map: 0.6.1 - dev: true - - /source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} - dev: true - - /source-map@0.7.4: - resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} - engines: {node: '>= 8'} - dev: true - - /source-map@0.8.0-beta.0: - resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} - engines: {node: '>= 8'} - deprecated: The work that was done in this beta branch won't be included in future versions - dependencies: - whatwg-url: 7.1.0 - dev: true - - /sourcemap-codec@1.4.8: - resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} - deprecated: Please use @jridgewell/sourcemap-codec instead - dev: true - - /spawnd@6.2.0: - resolution: {integrity: sha512-qX/I4lQy4KgVEcNle0kuc4FxFWHISzBhZW1YemPfwmrmQjyZmfTK/OhBKkhrD2ooAaFZEm1maEBLE6/6enwt+g==} - dependencies: - exit: 0.1.2 - signal-exit: 3.0.7 - tree-kill: 1.2.2 - dev: true - - /spdx-correct@3.2.0: - resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} - dependencies: - spdx-expression-parse: 3.0.1 - spdx-license-ids: 3.0.13 - dev: false - - /spdx-exceptions@2.3.0: - resolution: {integrity: sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==} - dev: false - - /spdx-expression-parse@3.0.1: - resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} - dependencies: - spdx-exceptions: 2.3.0 - spdx-license-ids: 3.0.13 - dev: false - - /spdx-license-ids@3.0.13: - resolution: {integrity: sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==} - dev: false - - /split-on-first@1.1.0: - resolution: {integrity: sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==} - engines: {node: '>=6'} - dev: false - - /sprintf-js@1.0.3: - resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - dev: true - - /stack-utils@2.0.6: - resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} - engines: {node: '>=10'} - dependencies: - escape-string-regexp: 2.0.0 - dev: true - - /stop-iteration-iterator@1.0.0: - resolution: {integrity: sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==} - engines: {node: '>= 0.4'} - dependencies: - internal-slot: 1.0.5 - dev: true - - /strict-uri-encode@2.0.0: - resolution: {integrity: sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==} - engines: {node: '>=4'} - dev: false - - /string-length@4.0.2: - resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} - engines: {node: '>=10'} - dependencies: - char-regex: 1.0.2 - strip-ansi: 6.0.1 - dev: true - - /string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} - dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 - dev: true - - /string.prototype.matchall@4.0.10: - resolution: {integrity: sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==} - dependencies: - call-bind: 1.0.5 - define-properties: 1.2.1 - es-abstract: 1.22.3 - get-intrinsic: 1.2.2 - has-symbols: 1.0.3 - internal-slot: 1.0.6 - regexp.prototype.flags: 1.5.1 - set-function-name: 2.0.1 - side-channel: 1.0.4 - dev: true - - /string.prototype.matchall@4.0.8: - resolution: {integrity: sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==} - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.22.1 - get-intrinsic: 1.2.1 - has-symbols: 1.0.3 - internal-slot: 1.0.5 - regexp.prototype.flags: 1.5.0 - side-channel: 1.0.4 - dev: true - - /string.prototype.trim@1.2.7: - resolution: {integrity: sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.22.1 - dev: true - - /string.prototype.trim@1.2.8: - resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.5 - define-properties: 1.2.1 - es-abstract: 1.22.3 - dev: true - - /string.prototype.trimend@1.0.6: - resolution: {integrity: sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==} - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.22.1 - dev: true - - /string.prototype.trimend@1.0.7: - resolution: {integrity: sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==} - dependencies: - call-bind: 1.0.5 - define-properties: 1.2.1 - es-abstract: 1.22.3 - dev: true - - /string.prototype.trimstart@1.0.6: - resolution: {integrity: sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==} - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.22.1 - dev: true - - /string.prototype.trimstart@1.0.7: - resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==} - dependencies: - call-bind: 1.0.5 - define-properties: 1.2.1 - es-abstract: 1.22.3 - dev: true - - /string_decoder@1.3.0: - resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} - dependencies: - safe-buffer: 5.2.1 - dev: true - - /stringify-object@3.3.0: - resolution: {integrity: sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==} - engines: {node: '>=4'} - dependencies: - get-own-enumerable-property-symbols: 3.0.2 - is-obj: 1.0.1 - is-regexp: 1.0.0 - dev: true - - /strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - dependencies: - ansi-regex: 5.0.1 - dev: true - - /strip-bom@3.0.0: - resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} - engines: {node: '>=4'} - dev: true - - /strip-bom@4.0.0: - resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} - engines: {node: '>=8'} - dev: true - - /strip-comments@2.0.1: - resolution: {integrity: sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==} - engines: {node: '>=10'} - dev: true - - /strip-final-newline@2.0.0: - resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} - engines: {node: '>=6'} - dev: true - - /strip-indent@3.0.0: - resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} - engines: {node: '>=8'} - dependencies: - min-indent: 1.0.1 - - /strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - dev: true - - /sucrase@3.34.0: - resolution: {integrity: sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw==} - engines: {node: '>=8'} - hasBin: true - dependencies: - '@jridgewell/gen-mapping': 0.3.3 - commander: 4.1.1 - glob: 7.1.6 - lines-and-columns: 1.2.4 - mz: 2.7.0 - pirates: 4.0.6 - ts-interface-checker: 0.1.13 - dev: true - - /supercluster@7.1.5: - resolution: {integrity: sha512-EulshI3pGUM66o6ZdH3ReiFcvHpM3vAigyK+vcxdjpJyEbIIrtbmBdY23mGgnI24uXiGFvrGq9Gkum/8U7vJWg==} - dependencies: - kdbush: 3.0.0 - dev: false - - /supports-color@5.5.0: - resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} - engines: {node: '>=4'} - dependencies: - has-flag: 3.0.0 - - /supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - dependencies: - has-flag: 4.0.0 - dev: true - - /supports-color@8.1.1: - resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} - engines: {node: '>=10'} - dependencies: - has-flag: 4.0.0 - dev: true - - /supports-hyperlinks@2.3.0: - resolution: {integrity: sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==} - engines: {node: '>=8'} - dependencies: - has-flag: 4.0.0 - supports-color: 7.2.0 - dev: true - - /supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - - /svg-parser@2.0.4: - resolution: {integrity: sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==} - dev: true - - /symbol-observable@1.2.0: - resolution: {integrity: sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==} - engines: {node: '>=0.10.0'} - dev: false - - /symbol-tree@3.2.4: - resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} - dev: true - - /tailwindcss@3.3.3: - resolution: {integrity: sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w==} - engines: {node: '>=14.0.0'} - hasBin: true - dependencies: - '@alloc/quick-lru': 5.2.0 - arg: 5.0.2 - chokidar: 3.5.3 - didyoumean: 1.2.2 - dlv: 1.1.3 - fast-glob: 3.3.1 - glob-parent: 6.0.2 - is-glob: 4.0.3 - jiti: 1.19.3 - lilconfig: 2.1.0 - micromatch: 4.0.5 - normalize-path: 3.0.0 - object-hash: 3.0.0 - picocolors: 1.0.0 - postcss: 8.4.28 - postcss-import: 15.1.0(postcss@8.4.28) - postcss-js: 4.0.1(postcss@8.4.28) - postcss-load-config: 4.0.1(postcss@8.4.28) - postcss-nested: 6.0.1(postcss@8.4.28) - postcss-selector-parser: 6.0.13 - resolve: 1.22.4 - sucrase: 3.34.0 - transitivePeerDependencies: - - ts-node - dev: true - - /tar-fs@2.1.1: - resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==} - dependencies: - chownr: 1.1.4 - mkdirp-classic: 0.5.3 - pump: 3.0.0 - tar-stream: 2.2.0 - dev: true - - /tar-stream@2.2.0: - resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} - engines: {node: '>=6'} - dependencies: - bl: 4.1.0 - end-of-stream: 1.4.4 - fs-constants: 1.0.0 - inherits: 2.0.4 - readable-stream: 3.6.2 - dev: true - - /temp-dir@2.0.0: - resolution: {integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==} - engines: {node: '>=8'} - dev: true - - /tempy@0.6.0: - resolution: {integrity: sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==} - engines: {node: '>=10'} - dependencies: - is-stream: 2.0.1 - temp-dir: 2.0.0 - type-fest: 0.16.0 - unique-string: 2.0.0 - dev: true - - /terminal-link@2.1.1: - resolution: {integrity: sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==} - engines: {node: '>=8'} - dependencies: - ansi-escapes: 4.3.2 - supports-hyperlinks: 2.3.0 - dev: true - - /terser@5.24.0: - resolution: {integrity: sha512-ZpGR4Hy3+wBEzVEnHvstMvqpD/nABNelQn/z2r0fjVWGQsN3bpOLzQlqDxmb4CDZnXq5lpjnQ+mHQLAOpfM5iw==} - engines: {node: '>=10'} - hasBin: true - dependencies: - '@jridgewell/source-map': 0.3.5 - acorn: 8.11.2 - commander: 2.20.3 - source-map-support: 0.5.21 - dev: true - - /test-exclude@6.0.0: - resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} - engines: {node: '>=8'} - dependencies: - '@istanbuljs/schema': 0.1.3 - glob: 7.2.3 - minimatch: 3.1.2 - dev: true - - /text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - dev: true - - /theming@1.3.0(react@18.2.0): - resolution: {integrity: sha512-ya5Ef7XDGbTPBv5ENTwrwkPUexrlPeiAg/EI9kdlUAZhNlRbCdhMKRgjNX1IcmsmiPcqDQZE6BpSaH+cr31FKw==} - peerDependencies: - react: '>=0.15' - dependencies: - brcast: 3.0.2 - is-function: 1.0.2 - is-plain-object: 2.0.4 - prop-types: 15.8.1 - react: 18.2.0 - dev: false - - /thenify-all@1.6.0: - resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} - engines: {node: '>=0.8'} - dependencies: - thenify: 3.3.1 - dev: true - - /thenify@3.3.1: - resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} - dependencies: - any-promise: 1.3.0 - dev: true - - /throat@6.0.2: - resolution: {integrity: sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ==} - dev: true - - /through@2.3.8: - resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} - dev: true - - /tiny-invariant@1.3.1: - resolution: {integrity: sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==} - dev: false - - /tiny-warning@1.0.3: - resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==} - dev: false - - /tinyqueue@2.0.3: - resolution: {integrity: sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==} - dev: false - - /tmpl@1.0.5: - resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} - dev: true - - /to-fast-properties@2.0.0: - resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} - engines: {node: '>=4'} - dev: true - - /to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - dependencies: - is-number: 7.0.0 - - /tough-cookie@4.1.3: - resolution: {integrity: sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==} - engines: {node: '>=6'} - dependencies: - psl: 1.9.0 - punycode: 2.3.0 - universalify: 0.2.0 - url-parse: 1.5.10 - dev: true - - /tr46@0.0.3: - resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - - /tr46@1.0.1: - resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} - dependencies: - punycode: 2.3.1 - dev: true - - /tr46@2.1.0: - resolution: {integrity: sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==} - engines: {node: '>=8'} - dependencies: - punycode: 2.3.0 - dev: true - - /tree-kill@1.2.2: - resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} - hasBin: true - dev: true - - /trim-newlines@3.0.1: - resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==} - engines: {node: '>=8'} - dev: false - - /ts-interface-checker@0.1.13: - resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} - dev: true - - /tsconfig-paths@3.14.2: - resolution: {integrity: sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==} - dependencies: - '@types/json5': 0.0.29 - json5: 1.0.2 - minimist: 1.2.8 - strip-bom: 3.0.0 - dev: true - - /tslib@2.6.2: - resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} - - /type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} - dependencies: - prelude-ls: 1.2.1 - dev: true - - /type-detect@4.0.8: - resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} - engines: {node: '>=4'} - dev: true - - /type-fest@0.13.1: - resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} - engines: {node: '>=10'} - dev: false - - /type-fest@0.16.0: - resolution: {integrity: sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==} - engines: {node: '>=10'} - dev: true - - /type-fest@0.20.2: - resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} - engines: {node: '>=10'} - dev: true - - /type-fest@0.21.3: - resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} - engines: {node: '>=10'} - dev: true - - /type-fest@0.6.0: - resolution: {integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==} - engines: {node: '>=8'} - dev: false - - /type-fest@0.8.1: - resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} - engines: {node: '>=8'} - dev: false - - /typed-array-buffer@1.0.0: - resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 - is-typed-array: 1.1.12 - dev: true - - /typed-array-byte-length@1.0.0: - resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - for-each: 0.3.3 - has-proto: 1.0.1 - is-typed-array: 1.1.12 - dev: true - - /typed-array-byte-offset@1.0.0: - resolution: {integrity: sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==} - engines: {node: '>= 0.4'} - dependencies: - available-typed-arrays: 1.0.5 - call-bind: 1.0.2 - for-each: 0.3.3 - has-proto: 1.0.1 - is-typed-array: 1.1.12 - dev: true - - /typed-array-length@1.0.4: - resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} - dependencies: - call-bind: 1.0.2 - for-each: 0.3.3 - is-typed-array: 1.1.12 - dev: true - - /typedarray-to-buffer@3.1.5: - resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} - dependencies: - is-typedarray: 1.0.0 - dev: true - - /ua-parser-js@0.7.35: - resolution: {integrity: sha512-veRf7dawaj9xaWEu9HoTVn5Pggtc/qj+kqTOFvNiN1l0YdxwC1kvel57UCjThjGa3BHBihE8/UJAHI+uQHmd/g==} - dev: false - - /unbox-primitive@1.0.2: - resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} - dependencies: - call-bind: 1.0.2 - has-bigints: 1.0.2 - has-symbols: 1.0.3 - which-boxed-primitive: 1.0.2 - dev: true - - /unbzip2-stream@1.4.3: - resolution: {integrity: sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==} - dependencies: - buffer: 5.7.1 - through: 2.3.8 - dev: true - - /undici-types@5.26.5: - resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - dev: true - - /unicode-canonical-property-names-ecmascript@2.0.0: - resolution: {integrity: sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==} - engines: {node: '>=4'} - dev: true - - /unicode-match-property-ecmascript@2.0.0: - resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==} - engines: {node: '>=4'} - dependencies: - unicode-canonical-property-names-ecmascript: 2.0.0 - unicode-property-aliases-ecmascript: 2.1.0 - dev: true - - /unicode-match-property-value-ecmascript@2.1.0: - resolution: {integrity: sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==} - engines: {node: '>=4'} - dev: true - - /unicode-property-aliases-ecmascript@2.1.0: - resolution: {integrity: sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==} - engines: {node: '>=4'} - dev: true - - /unique-string@2.0.0: - resolution: {integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==} - engines: {node: '>=8'} - dependencies: - crypto-random-string: 2.0.0 - dev: true - - /universalify@0.2.0: - resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} - engines: {node: '>= 4.0.0'} - dev: true - - /universalify@2.0.1: - resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} - engines: {node: '>= 10.0.0'} - dev: true - - /unplugin@1.0.1: - resolution: {integrity: sha512-aqrHaVBWW1JVKBHmGo33T5TxeL0qWzfvjWokObHA9bYmN7eNDkwOxmLjhioHl9878qDFMAaT51XNroRyuz7WxA==} - dependencies: - acorn: 8.10.0 - chokidar: 3.5.3 - webpack-sources: 3.2.3 - webpack-virtual-modules: 0.5.0 - dev: false - - /upath@1.2.0: - resolution: {integrity: sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==} - engines: {node: '>=4'} - dev: true - - /update-browserslist-db@1.0.13(browserslist@4.22.1): - resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - dependencies: - browserslist: 4.22.1 - escalade: 3.1.1 - picocolors: 1.0.0 - dev: true - - /uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - dependencies: - punycode: 2.3.0 - dev: true - - /url-parse@1.5.10: - resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} - dependencies: - querystringify: 2.2.0 - requires-port: 1.0.0 - dev: true - - /util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - dev: true - - /v8-to-istanbul@8.1.1: - resolution: {integrity: sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==} - engines: {node: '>=10.12.0'} - dependencies: - '@types/istanbul-lib-coverage': 2.0.4 - convert-source-map: 1.9.0 - source-map: 0.7.4 - dev: true - - /validate-npm-package-license@3.0.4: - resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} - dependencies: - spdx-correct: 3.2.0 - spdx-expression-parse: 3.0.1 - dev: false - - /value-equal@1.0.1: - resolution: {integrity: sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==} - dev: false - - /viewport-mercator-project@7.0.4: - resolution: {integrity: sha512-0jzpL6pIMocCKWg1C3mqi/N4UPgZC3FzwghEm1H+XsUo8hNZAyJc3QR7YqC816ibOR8aWT5pCsV+gCu8/BMJgg==} - dependencies: - '@math.gl/web-mercator': 3.6.3 - dev: false - - /vite-plugin-pwa@0.16.4(vite@4.5.3)(workbox-build@7.0.0)(workbox-window@7.0.0): - resolution: {integrity: sha512-lmwHFIs9zI2H9bXJld/zVTbCqCQHZ9WrpyDMqosICDV0FVnCJwniX1NMDB79HGTIZzOQkY4gSZaVTJTw6maz/Q==} - engines: {node: '>=16.0.0'} - peerDependencies: - vite: ^3.1.0 || ^4.0.0 - workbox-build: ^7.0.0 - workbox-window: ^7.0.0 - dependencies: - debug: 4.3.4 - fast-glob: 3.3.1 - pretty-bytes: 6.1.1 - vite: 4.5.3 - workbox-build: 7.0.0 - workbox-window: 7.0.0 - transitivePeerDependencies: - - supports-color - dev: true - - /vite-plugin-svgr@3.2.0(rollup@2.79.1)(vite@4.5.3): - resolution: {integrity: sha512-Uvq6niTvhqJU6ga78qLKBFJSDvxWhOnyfQSoKpDPMAGxJPo5S3+9hyjExE5YDj6Lpa4uaLkGc1cBgxXov+LjSw==} - peerDependencies: - vite: ^2.6.0 || 3 || 4 - dependencies: - '@rollup/pluginutils': 5.0.4(rollup@2.79.1) - '@svgr/core': 7.0.0 - '@svgr/plugin-jsx': 7.0.0 - vite: 4.5.3 - transitivePeerDependencies: - - rollup - - supports-color - dev: true - - /vite@4.5.3: - resolution: {integrity: sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg==} - engines: {node: ^14.18.0 || >=16.0.0} - hasBin: true - peerDependencies: - '@types/node': '>= 14' - less: '*' - lightningcss: ^1.21.0 - sass: '*' - stylus: '*' - sugarss: '*' - terser: ^5.4.0 - peerDependenciesMeta: - '@types/node': - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - dependencies: - esbuild: 0.18.20 - postcss: 8.4.28 - rollup: 3.28.1 - optionalDependencies: - fsevents: 2.3.3 - dev: true - - /vt-pbf@3.1.3: - resolution: {integrity: sha512-2LzDFzt0mZKZ9IpVF2r69G9bXaP2Q2sArJCmcCgvfTdCCZzSyz4aCLoQyUilu37Ll56tCblIZrXFIjNUpGIlmA==} - dependencies: - '@mapbox/point-geometry': 0.1.0 - '@mapbox/vector-tile': 1.3.1 - pbf: 3.2.1 - dev: false - - /w3c-hr-time@1.0.2: - resolution: {integrity: sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==} - deprecated: Use your platform's native performance.now() and performance.timeOrigin. - dependencies: - browser-process-hrtime: 1.0.0 - dev: true - - /w3c-xmlserializer@2.0.0: - resolution: {integrity: sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==} - engines: {node: '>=10'} - dependencies: - xml-name-validator: 3.0.0 - dev: true - - /wait-on@6.0.1: - resolution: {integrity: sha512-zht+KASY3usTY5u2LgaNqn/Cd8MukxLGjdcZxT2ns5QzDmTFc4XoWBgC+C/na+sMRZTuVygQoMYwdcVjHnYIVw==} - engines: {node: '>=10.0.0'} - hasBin: true - dependencies: - axios: 0.25.0 - joi: 17.9.2 - lodash: 4.17.21 - minimist: 1.2.8 - rxjs: 7.8.1 - transitivePeerDependencies: - - debug - dev: true - - /walker@1.0.8: - resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} - dependencies: - makeerror: 1.0.12 - dev: true - - /warning@3.0.0: - resolution: {integrity: sha512-jMBt6pUrKn5I+OGgtQ4YZLdhIeJmObddh6CsibPxyQ5yPZm1XExSyzC1LCNX7BzhxWgiHmizBWJTHJIjMjTQYQ==} - dependencies: - loose-envify: 1.4.0 - dev: false - - /warning@4.0.3: - resolution: {integrity: sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==} - dependencies: - loose-envify: 1.4.0 - dev: false - - /web-vitals@3.4.0: - resolution: {integrity: sha512-n9fZ5/bG1oeDkyxLWyep0eahrNcPDF6bFqoyispt7xkW0xhDzpUBTgyDKqWDi1twT0MgH4HvvqzpUyh0ZxZV4A==} - dev: false - - /webidl-conversions@3.0.1: - resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - - /webidl-conversions@4.0.2: - resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} - dev: true - - /webidl-conversions@5.0.0: - resolution: {integrity: sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==} - engines: {node: '>=8'} - dev: true - - /webidl-conversions@6.1.0: - resolution: {integrity: sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==} - engines: {node: '>=10.4'} - dev: true - - /webpack-sources@3.2.3: - resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==} - engines: {node: '>=10.13.0'} - dev: false - - /webpack-virtual-modules@0.5.0: - resolution: {integrity: sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==} - dev: false - - /whatwg-encoding@1.0.5: - resolution: {integrity: sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==} - dependencies: - iconv-lite: 0.4.24 - dev: true - - /whatwg-fetch@3.6.17: - resolution: {integrity: sha512-c4ghIvG6th0eudYwKZY5keb81wtFz9/WeAHAoy8+r18kcWlitUIrmGFQ2rWEl4UCKUilD3zCLHOIPheHx5ypRQ==} - - /whatwg-mimetype@2.3.0: - resolution: {integrity: sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==} - dev: true - - /whatwg-url@5.0.0: - resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} - dependencies: - tr46: 0.0.3 - webidl-conversions: 3.0.1 - - /whatwg-url@7.1.0: - resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} - dependencies: - lodash.sortby: 4.7.0 - tr46: 1.0.1 - webidl-conversions: 4.0.2 - dev: true - - /whatwg-url@8.7.0: - resolution: {integrity: sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==} - engines: {node: '>=10'} - dependencies: - lodash: 4.17.21 - tr46: 2.1.0 - webidl-conversions: 6.1.0 - dev: true - - /which-boxed-primitive@1.0.2: - resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} - dependencies: - is-bigint: 1.0.4 - is-boolean-object: 1.1.2 - is-number-object: 1.0.7 - is-string: 1.0.7 - is-symbol: 1.0.4 - dev: true - - /which-builtin-type@1.1.3: - resolution: {integrity: sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==} - engines: {node: '>= 0.4'} - dependencies: - function.prototype.name: 1.1.5 - has-tostringtag: 1.0.0 - is-async-function: 2.0.0 - is-date-object: 1.0.5 - is-finalizationregistry: 1.0.2 - is-generator-function: 1.0.10 - is-regex: 1.1.4 - is-weakref: 1.0.2 - isarray: 2.0.5 - which-boxed-primitive: 1.0.2 - which-collection: 1.0.1 - which-typed-array: 1.1.11 - dev: true - - /which-collection@1.0.1: - resolution: {integrity: sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==} - dependencies: - is-map: 2.0.2 - is-set: 2.0.2 - is-weakmap: 2.0.1 - is-weakset: 2.0.2 - dev: true - - /which-typed-array@1.1.11: - resolution: {integrity: sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==} - engines: {node: '>= 0.4'} - 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 - dev: true - - /which-typed-array@1.1.13: - resolution: {integrity: sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==} - engines: {node: '>= 0.4'} - dependencies: - available-typed-arrays: 1.0.5 - call-bind: 1.0.5 - for-each: 0.3.3 - gopd: 1.0.1 - has-tostringtag: 1.0.0 - dev: true - - /which@1.3.1: - resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} - hasBin: true - dependencies: - isexe: 2.0.0 - dev: true - - /which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - dependencies: - isexe: 2.0.0 - - /workbox-background-sync@7.0.0: - resolution: {integrity: sha512-S+m1+84gjdueM+jIKZ+I0Lx0BDHkk5Nu6a3kTVxP4fdj3gKouRNmhO8H290ybnJTOPfBDtTMXSQA/QLTvr7PeA==} - dependencies: - idb: 7.1.1 - workbox-core: 7.0.0 - dev: true - - /workbox-broadcast-update@7.0.0: - resolution: {integrity: sha512-oUuh4jzZrLySOo0tC0WoKiSg90bVAcnE98uW7F8GFiSOXnhogfNDGZelPJa+6KpGBO5+Qelv04Hqx2UD+BJqNQ==} - dependencies: - workbox-core: 7.0.0 - dev: true - - /workbox-build@7.0.0: - resolution: {integrity: sha512-CttE7WCYW9sZC+nUYhQg3WzzGPr4IHmrPnjKiu3AMXsiNQKx+l4hHl63WTrnicLmKEKHScWDH8xsGBdrYgtBzg==} - engines: {node: '>=16.0.0'} - dependencies: - '@apideck/better-ajv-errors': 0.3.6(ajv@8.12.0) - '@babel/core': 7.23.5 - '@babel/preset-env': 7.23.5(@babel/core@7.23.5) - '@babel/runtime': 7.23.5 - '@rollup/plugin-babel': 5.3.1(@babel/core@7.23.5)(rollup@2.79.1) - '@rollup/plugin-node-resolve': 11.2.1(rollup@2.79.1) - '@rollup/plugin-replace': 2.4.2(rollup@2.79.1) - '@surma/rollup-plugin-off-main-thread': 2.2.3 - ajv: 8.12.0 - common-tags: 1.8.2 - fast-json-stable-stringify: 2.1.0 - fs-extra: 9.1.0 - glob: 7.2.3 - lodash: 4.17.21 - pretty-bytes: 5.6.0 - rollup: 2.79.1 - rollup-plugin-terser: 7.0.2(rollup@2.79.1) - source-map: 0.8.0-beta.0 - stringify-object: 3.3.0 - strip-comments: 2.0.1 - tempy: 0.6.0 - upath: 1.2.0 - workbox-background-sync: 7.0.0 - workbox-broadcast-update: 7.0.0 - workbox-cacheable-response: 7.0.0 - workbox-core: 7.0.0 - workbox-expiration: 7.0.0 - workbox-google-analytics: 7.0.0 - workbox-navigation-preload: 7.0.0 - workbox-precaching: 7.0.0 - workbox-range-requests: 7.0.0 - workbox-recipes: 7.0.0 - workbox-routing: 7.0.0 - workbox-strategies: 7.0.0 - workbox-streams: 7.0.0 - workbox-sw: 7.0.0 - workbox-window: 7.0.0 - transitivePeerDependencies: - - '@types/babel__core' - - supports-color - dev: true - - /workbox-cacheable-response@7.0.0: - resolution: {integrity: sha512-0lrtyGHn/LH8kKAJVOQfSu3/80WDc9Ma8ng0p2i/5HuUndGttH+mGMSvOskjOdFImLs2XZIimErp7tSOPmu/6g==} - dependencies: - workbox-core: 7.0.0 - dev: true - - /workbox-core@7.0.0: - resolution: {integrity: sha512-81JkAAZtfVP8darBpfRTovHg8DGAVrKFgHpOArZbdFd78VqHr5Iw65f2guwjE2NlCFbPFDoez3D3/6ZvhI/rwQ==} - dev: true - - /workbox-expiration@7.0.0: - resolution: {integrity: sha512-MLK+fogW+pC3IWU9SFE+FRStvDVutwJMR5if1g7oBJx3qwmO69BNoJQVaMXq41R0gg3MzxVfwOGKx3i9P6sOLQ==} - dependencies: - idb: 7.1.1 - workbox-core: 7.0.0 - dev: true - - /workbox-google-analytics@7.0.0: - resolution: {integrity: sha512-MEYM1JTn/qiC3DbpvP2BVhyIH+dV/5BjHk756u9VbwuAhu0QHyKscTnisQuz21lfRpOwiS9z4XdqeVAKol0bzg==} - deprecated: It is not compatible with newer versions of GA starting with v4, as long as you are using GAv3 it should be ok, but the package is not longer being maintained - dependencies: - workbox-background-sync: 7.0.0 - workbox-core: 7.0.0 - workbox-routing: 7.0.0 - workbox-strategies: 7.0.0 - dev: true - - /workbox-navigation-preload@7.0.0: - resolution: {integrity: sha512-juWCSrxo/fiMz3RsvDspeSLGmbgC0U9tKqcUPZBCf35s64wlaLXyn2KdHHXVQrb2cqF7I0Hc9siQalainmnXJA==} - dependencies: - workbox-core: 7.0.0 - dev: true - - /workbox-precaching@7.0.0: - resolution: {integrity: sha512-EC0vol623LJqTJo1mkhD9DZmMP604vHqni3EohhQVwhJlTgyKyOkMrZNy5/QHfOby+39xqC01gv4LjOm4HSfnA==} - dependencies: - workbox-core: 7.0.0 - workbox-routing: 7.0.0 - workbox-strategies: 7.0.0 - dev: true - - /workbox-range-requests@7.0.0: - resolution: {integrity: sha512-SxAzoVl9j/zRU9OT5+IQs7pbJBOUOlriB8Gn9YMvi38BNZRbM+RvkujHMo8FOe9IWrqqwYgDFBfv6sk76I1yaQ==} - dependencies: - workbox-core: 7.0.0 - dev: true - - /workbox-recipes@7.0.0: - resolution: {integrity: sha512-DntcK9wuG3rYQOONWC0PejxYYIDHyWWZB/ueTbOUDQgefaeIj1kJ7pdP3LZV2lfrj8XXXBWt+JDRSw1lLLOnww==} - dependencies: - workbox-cacheable-response: 7.0.0 - workbox-core: 7.0.0 - workbox-expiration: 7.0.0 - workbox-precaching: 7.0.0 - workbox-routing: 7.0.0 - workbox-strategies: 7.0.0 - dev: true - - /workbox-routing@7.0.0: - resolution: {integrity: sha512-8YxLr3xvqidnbVeGyRGkaV4YdlKkn5qZ1LfEePW3dq+ydE73hUUJJuLmGEykW3fMX8x8mNdL0XrWgotcuZjIvA==} - dependencies: - workbox-core: 7.0.0 - dev: true - - /workbox-strategies@7.0.0: - resolution: {integrity: sha512-dg3qJU7tR/Gcd/XXOOo7x9QoCI9nk74JopaJaYAQ+ugLi57gPsXycVdBnYbayVj34m6Y8ppPwIuecrzkpBVwbA==} - dependencies: - workbox-core: 7.0.0 - dev: true - - /workbox-streams@7.0.0: - resolution: {integrity: sha512-moVsh+5to//l6IERWceYKGiftc+prNnqOp2sgALJJFbnNVpTXzKISlTIsrWY+ogMqt+x1oMazIdHj25kBSq/HQ==} - dependencies: - workbox-core: 7.0.0 - workbox-routing: 7.0.0 - dev: true - - /workbox-sw@7.0.0: - resolution: {integrity: sha512-SWfEouQfjRiZ7GNABzHUKUyj8pCoe+RwjfOIajcx6J5mtgKkN+t8UToHnpaJL5UVVOf5YhJh+OHhbVNIHe+LVA==} - dev: true - - /workbox-window@7.0.0: - resolution: {integrity: sha512-j7P/bsAWE/a7sxqTzXo3P2ALb1reTfZdvVp6OJ/uLr/C2kZAMvjeWGm8V4htQhor7DOvYg0sSbFN2+flT5U0qA==} - dependencies: - '@types/trusted-types': 2.0.3 - workbox-core: 7.0.0 - dev: true - - /wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - dev: true - - /wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - - /write-file-atomic@3.0.3: - resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==} - dependencies: - imurmurhash: 0.1.4 - is-typedarray: 1.0.0 - signal-exit: 3.0.7 - typedarray-to-buffer: 3.1.5 - dev: true - - /ws@7.5.9: - resolution: {integrity: sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==} - engines: {node: '>=8.3.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ^5.0.2 - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - dev: true - - /ws@8.13.0: - resolution: {integrity: sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - dev: true - - /xml-name-validator@3.0.0: - resolution: {integrity: sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==} - dev: true - - /xmlchars@2.2.0: - resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} - dev: true - - /xtend@4.0.2: - resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} - engines: {node: '>=0.4'} - dev: false - - /y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - dev: true - - /yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - dev: true - - /yallist@4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - dev: true - - /yaml@2.3.1: - resolution: {integrity: sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==} - engines: {node: '>= 14'} - dev: true - - /yargs-parser@18.1.3: - resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} - engines: {node: '>=6'} - dependencies: - camelcase: 5.3.1 - decamelize: 1.2.0 - dev: false - - /yargs-parser@20.2.9: - resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} - engines: {node: '>=10'} - dev: true - - /yargs-parser@21.1.1: - resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} - engines: {node: '>=12'} - dev: true - - /yargs@16.2.0: - resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} - engines: {node: '>=10'} - dependencies: - cliui: 7.0.4 - escalade: 3.1.1 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 20.2.9 - dev: true - - /yargs@17.7.1: - resolution: {integrity: sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==} - engines: {node: '>=12'} - dependencies: - cliui: 8.0.1 - escalade: 3.1.1 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 21.1.1 - dev: true - - /yauzl@2.10.0: - resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} - dependencies: - buffer-crc32: 0.2.13 - fd-slicer: 1.1.0 - dev: true - - /yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - - github.com/commaai/comma-api/6325ff32b82aeddb2edc10a6175717349b7f75c5: - resolution: {tarball: https://codeload.github.com/commaai/comma-api/tar.gz/6325ff32b82aeddb2edc10a6175717349b7f75c5} - name: '@commaai/api' - version: 3.2.0 - dependencies: - '@babel/runtime': 7.23.5 - query-string: 7.1.3 - dev: false diff --git a/src/components/utils/BackgroundImage.jsx b/src/components/utils/BackgroundImage.jsx deleted file mode 100644 index cafe2527..00000000 --- a/src/components/utils/BackgroundImage.jsx +++ /dev/null @@ -1,100 +0,0 @@ -import React, { createRef, useEffect } from 'react'; -import { withStyles } from '@material-ui/core/styles'; - -const styles = () => ({ - root: { - position: 'relative', - width: '100%', - height: '100%', - overflow: 'hidden', - }, - placeholder: { - position: 'absolute', - zIndex: 1, - top: 0, - right: 0, - bottom: 0, - left: 0, - backgroundPosition: 'center', - backgroundSize: 'cover', - opacity: 0, - transition: 'opacity 0.3s ease', - }, - hdImage: { - position: 'absolute', - zIndex: 2, - top: 0, - right: 0, - bottom: 0, - left: 0, - // TODO: add attributes - // backgroundPosition: 'center', - // backgroundSize: 'cover', - backgroundSize: 'contain', - backgroundRepeat: 'no-repeat', - backgroundPosition: 'center', - opacity: 0, - transition: 'opacity 0.3s ease', - }, - overlay: { - position: 'absolute', - zIndex: 3, - top: 0, - right: 0, - bottom: 0, - left: 0, - opacity: 0, - transition: 'opacity 0.3s ease', - }, - fadeIn: { - opacity: 1, - }, -}); - -/* eslint-disable react/jsx-props-no-spreading */ -const BackgroundImage = (props) => { - const hdImageRef = createRef(); - const placeholderRef = createRef(); - const overlayRef = createRef(); - const { placeholder, classes, className, src, children, overlay, ...rest } = props; - - useEffect(() => { - const newImage = document.createElement('img'); - const hdImageEl = hdImageRef.current; - const placeholderEl = placeholderRef.current; - const overlayEl = overlayRef.current; - newImage.src = src; - newImage.onload = () => { - hdImageEl.setAttribute('style', `background-image: url(${src})`); - hdImageEl.classList.add(classes.fadeIn); - overlayEl.classList.add(classes.fadeIn); - }; - newImage.onerror = () => { - placeholderEl.classList.add(classes.fadeIn); - overlayEl.classList.add(classes.fadeIn); - }; - - return () => { - newImage.remove(); - }; - }, []); - - return ( -

@@ -83,11 +77,11 @@ class DriveView extends Component { } } -const stateToProps = Obstruction({ - dongleId: 'dongleId', - routes: 'routes', - zoom: 'zoom', - currentRoute: 'currentRoute', +const stateToProps = (state) => ({ + dongleId: state.dongleId, + routes: state.routes, + zoom: selectRouteZoom(state), + currentRoute: selectCurrentRoute(state), }); -export default connect(stateToProps)(DriveView); \ No newline at end of file +export default connect(stateToProps)(DriveView); diff --git a/src/components/Files/UploadQueue.jsx b/src/components/Files/UploadQueue.jsx index 15043f43..85c501fa 100644 --- a/src/components/Files/UploadQueue.jsx +++ b/src/components/Files/UploadQueue.jsx @@ -1,6 +1,5 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; -import Obstruction from 'obstruction'; import { withStyles, @@ -296,9 +295,9 @@ class UploadQueue extends Component { } } -const stateToProps = Obstruction({ - filesUploading: 'filesUploading', - filesUploadingMeta: 'filesUploadingMeta', +const stateToProps = (state) => ({ + filesUploading: state.filesUploading, + filesUploadingMeta: state.filesUploadingMeta, }); export default connect(stateToProps)(withStyles(styles)(UploadQueue)); diff --git a/src/components/Navigation/index.jsx b/src/components/Navigation/index.jsx index b11a1127..60739b7f 100644 --- a/src/components/Navigation/index.jsx +++ b/src/components/Navigation/index.jsx @@ -8,7 +8,7 @@ import { Clear } from '@material-ui/icons'; import dayjs from 'dayjs'; import { athena as Athena, devices as Devices } from '@commaai/api'; -import { primeNav } from '../../actions'; +import { navigate } from '../../navigation'; import { DEFAULT_LOCATION, MAPBOX_STYLE, MAPBOX_TOKEN, networkPositioning, reverseLookup } from '../../utils/geocode'; import Colors from '../../colors'; import { PinCarIcon } from '../../icons'; @@ -692,7 +692,7 @@ class Navigation extends Component {
  -
@@ -155,11 +140,6 @@ class TimeSelect extends Component { ); - } -} - -const stateToProps = (state) => ({ - filter: state.filter, -}); +}; -export default connect(stateToProps)(withStyles(styles)(TimeSelect)); +export default withStyles(styles)(TimeSelect); diff --git a/src/components/VisibilityHandler/index.jsx b/src/components/VisibilityHandler/index.jsx index 5f58226c..ca161607 100644 --- a/src/components/VisibilityHandler/index.jsx +++ b/src/components/VisibilityHandler/index.jsx @@ -1,90 +1,81 @@ -import { Component } from 'react'; -import { connect } from 'react-redux'; +import { useEffect, useRef, useCallback } from 'react'; +import { useSelector } from 'react-redux'; import debounce from 'debounce'; -class VisibilityHandler extends Component { - constructor(props) { - super(props); +const VisibilityHandler = (props) => { + const { onInit, onInterval, onVisible, minInterval, resetOnHidden, onDongleId } = props; + const dongleId = useSelector((state) => state.dongleId); - this.prevVisibleCall = 0; - this.intervalHandle = null; - this.handleVisibilityChange = this.handleVisibilityChange.bind(this); - this.handleFocus = this.handleFocus.bind(this); - this.handleBlur = this.handleBlur.bind(this); - this.onVisibilityEvent = debounce(this.onVisibilityEvent.bind(this), 1000, true); - } + const prevVisibleCall = useRef(0); + const intervalHandle = useRef(null); - componentDidMount() { - document.addEventListener('visibilitychange', this.handleVisibilityChange); - document.addEventListener('focus', this.handleFocus); - document.addEventListener('blur', this.handleBlur); - this.prevVisibleCall = Date.now() / 1000; - - const { onInit, onInterval, onVisible } = this.props; - if (onInit) { + const onVisibilityEvent = useCallback((visible) => { + const newDate = Date.now() / 1000; + const dt = newDate - prevVisibleCall.current; + if (visible && (!minInterval || dt > minInterval)) { + prevVisibleCall.current = newDate; onVisible(); } - if (onInterval) { - this.intervalHandle = setInterval(this.handleVisibilityChange, onInterval * 1000); - } - } - componentDidUpdate(prevProps) { - const { dongleId, onDongleId, onVisible } = this.props; - if (onDongleId && prevProps.dongleId !== dongleId) { - this.prevVisibleCall = Date.now() / 1000; - onVisible(); + if (!visible && resetOnHidden) { + prevVisibleCall.current = newDate; } - } + }, [minInterval, onVisible, resetOnHidden]); - componentWillUnmount() { - document.removeEventListener('visibilitychange', this.handleVisibilityChange); - document.removeEventListener('focus', this.handleFocus); - document.removeEventListener('blur', this.handleBlur); - if (this.intervalHandle) { - clearInterval(this.intervalHandle); - this.intervalHandle = null; - } - } + const debouncedVisibilityEvent = useRef(debounce(onVisibilityEvent, 1000, true)); - handleFocus() { - this.onVisibilityEvent(true); - } + const handleFocus = useCallback(() => { + debouncedVisibilityEvent.current(true); + }, []); - handleBlur() { - this.onVisibilityEvent(false); - } + const handleBlur = useCallback(() => { + debouncedVisibilityEvent.current(false); + }, []); - handleVisibilityChange() { + const handleVisibilityChange = useCallback(() => { if (document.visibilityState === 'visible') { - this.onVisibilityEvent(true); + debouncedVisibilityEvent.current(true); } else if (document.visibilityState === 'hidden') { - this.onVisibilityEvent(false); + debouncedVisibilityEvent.current(false); } - } + }, []); - onVisibilityEvent(visible) { - const { minInterval, onVisible, resetOnHidden } = this.props; + // Mount effect + useEffect(() => { + document.addEventListener('visibilitychange', handleVisibilityChange); + document.addEventListener('focus', handleFocus); + document.addEventListener('blur', handleBlur); + prevVisibleCall.current = Date.now() / 1000; - const newDate = Date.now() / 1000; - const dt = newDate - this.prevVisibleCall; - if (visible && (!minInterval || dt > minInterval)) { - this.prevVisibleCall = newDate; + if (onInit) { onVisible(); } - - if (!visible && resetOnHidden) { - this.prevVisibleCall = newDate; + if (onInterval) { + intervalHandle.current = setInterval(handleVisibilityChange, onInterval * 1000); } - } - render() { - return null; - } -} + return () => { + document.removeEventListener('visibilitychange', handleVisibilityChange); + document.removeEventListener('focus', handleFocus); + document.removeEventListener('blur', handleBlur); + if (intervalHandle.current) { + clearInterval(intervalHandle.current); + intervalHandle.current = null; + } + }; + }, [onInit, onInterval, onVisible, handleVisibilityChange, handleFocus, handleBlur]); + + // DongleId change effect + const prevDongleId = useRef(dongleId); + useEffect(() => { + if (onDongleId && prevDongleId.current !== dongleId) { + prevVisibleCall.current = Date.now() / 1000; + onVisible(); + } + prevDongleId.current = dongleId; + }, [dongleId, onDongleId, onVisible]); -const stateToProps = (state) => ({ - dongleId: state.dongleId, -}); + return null; +}; -export default connect(stateToProps)(VisibilityHandler); +export default VisibilityHandler; From f312c706829e8deea74698ed8d3b49478cc8849c Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 2 Nov 2025 16:49:59 -0800 Subject: [PATCH 12/26] go go go --- src/components/DriveMap/index.jsx | 421 +++++++++++++------------- src/components/TimeDisplay/index.jsx | 292 ++++++++---------- src/components/Timeline/index.jsx | 431 +++++++++++++-------------- 3 files changed, 540 insertions(+), 604 deletions(-) diff --git a/src/components/DriveMap/index.jsx b/src/components/DriveMap/index.jsx index dc08de56..cff78af3 100644 --- a/src/components/DriveMap/index.jsx +++ b/src/components/DriveMap/index.jsx @@ -1,6 +1,6 @@ -import React, { Component } from 'react'; -import { connect } from 'react-redux'; - +import React, { useState, useEffect, useRef } from 'react'; +import { useSelector, useDispatch } from 'react-redux'; + import { selectCurrentRoute } from '../../selectors/route'; import ReactMapGL, { LinearInterpolator } from 'react-map-gl'; @@ -11,103 +11,126 @@ import { DEFAULT_LOCATION, MAPBOX_STYLE, MAPBOX_TOKEN } from '../../utils/geocod const INTERACTION_TIMEOUT = 5000; -class DriveMap extends Component { - constructor(props) { - super(props); - - this.state = { - viewport: { - ...DEFAULT_LOCATION, - zoom: 14, - }, - driveCoordsMin: null, - driveCoordsMax: null, - }; - - this.onRef = this.onRef.bind(this); - this.onViewportChange = this.onViewportChange.bind(this); - this.initMap = this.initMap.bind(this); - this.populateMap = this.populateMap.bind(this); - this.posAtOffset = this.posAtOffset.bind(this); - this.setPath = this.setPath.bind(this); - this.updateMarkerPos = this.updateMarkerPos.bind(this); - this.onInteraction = this.onInteraction.bind(this); - - this.shouldFlyTo = false; - this.isInteracting = false; - this.isInteractingTimeout = null; - this.lastMapPos = [0, 0]; - } - - componentDidMount() { - this.mounted = true; - this.componentDidUpdate({}, {}); - this.updateMarkerPos(); - } - - componentDidUpdate(prevProps) { - const { dispatch, currentRoute, startTime } = this.props; - - const prevRoute = prevProps.currentRoute?.fullname || null; - const route = currentRoute?.fullname || null; - if (prevRoute !== route) { - this.setPath([]); - if (route) { - dispatch(fetchDriveCoords(currentRoute)); - } +const DriveMap = () => { + const dispatch = useDispatch(); + const currentRoute = useSelector((state) => selectCurrentRoute(state)); + const startTime = useSelector((state) => state.startTime); + + const [viewport, setViewport] = useState({ + ...DEFAULT_LOCATION, + zoom: 14, + }); + const [driveCoordsMin, setDriveCoordsMin] = useState(null); + const [driveCoordsMax, setDriveCoordsMax] = useState(null); + + const mapRef = useRef(null); + const mapInitializedRef = useRef(false); // Track if map.on('load') has been set up + const mapLoadedRef = useRef(false); // Track if map has fully loaded + const shouldFlyToRef = useRef(false); + const isInteractingRef = useRef(false); + const isInteractingTimeoutRef = useRef(null); + const lastMapPosRef = useRef([0, 0]); + const animationFrameId = useRef(null); + const currentRouteRef = useRef(currentRoute); + const driveCoordsMinRef = useRef(driveCoordsMin); + const driveCoordsMaxRef = useRef(driveCoordsMax); + + // Keep refs in sync with state + useEffect(() => { + currentRouteRef.current = currentRoute; + driveCoordsMinRef.current = driveCoordsMin; + driveCoordsMaxRef.current = driveCoordsMax; + }, [currentRoute, driveCoordsMin, driveCoordsMax]); + + const posAtOffset = (offset, route, minCoord, maxCoord) => { + if (!route?.driveCoords) { + return null; } - if (prevProps.startTime && prevProps.startTime !== startTime) { - this.shouldFlyTo = true; + const offsetSeconds = Math.floor(offset / 1e3); + const offsetFractionalPart = (offset % 1e3) / 1000.0; + const coordIdx = Math.max(minCoord, Math.min( + offsetSeconds, + maxCoord, + )); + const nextCoordIdx = Math.max(minCoord, Math.min( + offsetSeconds + 1, + maxCoord, + )); + + if (!route.driveCoords[coordIdx]) { + return null; } - if (currentRoute && prevProps.currentRoute && currentRoute.driveCoords - && prevProps.currentRoute.driveCoords !== currentRoute.driveCoords) { - this.shouldFlyTo = false; - const keys = Object.keys(currentRoute.driveCoords); - this.setState({ - driveCoordsMin: Math.min(...keys), - driveCoordsMax: Math.max(...keys), - }); - this.populateMap(); + const [floorLng, floorLat] = route.driveCoords[coordIdx]; + if (!route.driveCoords[nextCoordIdx]) { + return [floorLng, floorLat]; } - } - componentWillUnmount() { - this.mounted = false; - } + const [ceilLng, ceilLat] = route.driveCoords[nextCoordIdx]; + return [ + floorLng + ((ceilLng - floorLng) * offsetFractionalPart), + floorLat + ((ceilLat - floorLat) * offsetFractionalPart), + ]; + }; - onInteraction(ev) { - if (ev.isDragging || ev.isRotating || ev.isZooming) { - this.shouldFlyTo = true; - this.isInteracting = true; + const setPath = (coords) => { + const map = mapRef.current && mapRef.current.getMap(); - if (this.isInteractingTimeout !== null) { - clearTimeout(this.isInteractingTimeout); + if (map) { + const source = map.getSource('route'); + if (source) { + source.setData({ + type: 'Feature', + properties: {}, + geometry: { + type: 'LineString', + coordinates: coords, + }, + }); } - this.isInteractingTimeout = setTimeout(() => { - this.isInteracting = false; - }, INTERACTION_TIMEOUT); } - } + }; - updateMarkerPos() { - if (!this.mounted) { + const populateMap = (route) => { + if (!mapRef.current || !mapLoadedRef.current || !route || !route.driveCoords) { return; } - const markerSource = this.map && this.map.getMap().getSource('seekPoint'); + setPath(Object.values(route.driveCoords)); + }; + + const moveViewportTo = (pos) => { + const newViewport = { + longitude: pos[0], + latitude: pos[1], + }; + if (shouldFlyToRef.current) { + newViewport.transitionDuration = 200; + newViewport.transitionInterpolator = new LinearInterpolator(); + shouldFlyToRef.current = false; + } + + setViewport((prevState) => ({ + ...prevState, + ...newViewport, + })); + }; + + const updateMarkerPos = () => { + const markerSource = mapRef.current && mapRef.current.getMap().getSource('seekPoint'); if (markerSource) { - if (this.props.currentRoute && this.props.currentRoute.driveCoords) { - const pos = this.posAtOffset(currentOffset()); - if (pos && pos.some((coordinate, index) => coordinate != this.lastMapPos[index])) { - this.lastMapPos = pos; + const route = currentRouteRef.current; + if (route && route.driveCoords) { + const pos = posAtOffset(currentOffset(), route, driveCoordsMinRef.current, driveCoordsMaxRef.current); + if (pos && pos.some((coordinate, index) => coordinate != lastMapPosRef.current[index])) { + lastMapPosRef.current = pos; markerSource.setData({ type: 'Point', coordinates: pos, }); - if (!this.isInteracting) { - this.moveViewportTo(pos); + if (!isInteractingRef.current) { + moveViewportTo(pos); } } } else if (markerSource._data && markerSource._data.coordinates.length > 0) { @@ -118,107 +141,50 @@ class DriveMap extends Component { } } - requestAnimationFrame(this.updateMarkerPos); - } - - moveViewportTo(pos) { - const viewport = { - longitude: pos[0], - latitude: pos[1], - }; - if (this.shouldFlyTo) { - viewport.transitionDuration = 200; - viewport.transitionInterpolator = new LinearInterpolator(); - this.shouldFlyTo = false; - } - - this.setState((prevState) => ({ - viewport: { - ...prevState.viewport, - ...viewport, - }, - })); - } + animationFrameId.current = requestAnimationFrame(updateMarkerPos); + }; - async populateMap() { - const { currentRoute } = this.props; + const onInteraction = (ev) => { + if (ev.isDragging || ev.isRotating || ev.isZooming) { + shouldFlyToRef.current = true; + isInteractingRef.current = true; - if (!this.map || !currentRoute || !currentRoute.driveCoords) { - return; + if (isInteractingTimeoutRef.current !== null) { + clearTimeout(isInteractingTimeoutRef.current); + } + isInteractingTimeoutRef.current = setTimeout(() => { + isInteractingRef.current = false; + }, INTERACTION_TIMEOUT); } + }; - this.setPath(Object.values(currentRoute.driveCoords)); - } - - onRef(el) { + const onRef = (el) => { if (el) { el.addEventListener('touchstart', (ev) => ev.stopPropagation()); } - } - - onViewportChange(viewport) { - this.setState({ viewport }); - } - - setPath(coords) { - const map = this.map && this.map.getMap(); - - if (map) { - map.getSource('route').setData({ - type: 'Feature', - properties: {}, - geometry: { - type: 'LineString', - coordinates: coords, - }, - }); - } - } - - posAtOffset(offset) { - const { currentRoute } = this.props; - if (!currentRoute.driveCoords) { - return null; - } - - const offsetSeconds = Math.floor(offset / 1e3); - const offsetFractionalPart = (offset % 1e3) / 1000.0; - const coordIdx = Math.max(this.state.driveCoordsMin, Math.min( - offsetSeconds, - this.state.driveCoordsMax, - )); - const nextCoordIdx = Math.max(this.state.driveCoordsMin, Math.min( - offsetSeconds + 1, - this.state.driveCoordsMax, - )); - - if (!currentRoute.driveCoords[coordIdx]) { - return null; - } - - const [floorLng, floorLat] = currentRoute.driveCoords[coordIdx]; - if (!currentRoute.driveCoords[nextCoordIdx]) { - return [floorLng, floorLat]; - } + }; - const [ceilLng, ceilLat] = currentRoute.driveCoords[nextCoordIdx]; - return [ - floorLng + ((ceilLng - floorLng) * offsetFractionalPart), - floorLat + ((ceilLat - floorLat) * offsetFractionalPart), - ]; - } + const onViewportChange = (newViewport) => { + setViewport(newViewport); + }; - initMap(mapComponent) { + const initMap = (mapComponent) => { if (!mapComponent) { - this.map = null; + mapRef.current = null; return; } const map = mapComponent.getMap(); if (!map) { - this.map = null; + mapRef.current = null; + return; + } + + // Prevent setting up the event handler multiple times + if (mapInitializedRef.current) { return; } + mapInitializedRef.current = true; map.on('load', () => { map.addSource('route', { @@ -267,50 +233,85 @@ class DriveMap extends Component { map.addLayer(markerGeoJson); - this.map = mapComponent; - - const { currentRoute } = this.props; - if (currentRoute?.driveCoords) { - this.shouldFlyTo = false; - const keys = Object.keys(currentRoute.driveCoords); - this.setState({ - driveCoordsMin: Math.min(...keys), - driveCoordsMax: Math.max(...keys), - }); - this.populateMap(); + mapRef.current = mapComponent; + mapLoadedRef.current = true; // Mark map as loaded + + // Use ref to get current value, not closure + const route = currentRouteRef.current; + if (route?.driveCoords) { + shouldFlyToRef.current = false; + const keys = Object.keys(route.driveCoords); + setDriveCoordsMin(Math.min(...keys)); + setDriveCoordsMax(Math.max(...keys)); + populateMap(route); } }); - } - - render() { - const { viewport } = this.state; - return ( -
- -
- ); - } -} - -const stateToProps = (state) => ({ - offset: state.offset, - currentRoute: selectCurrentRoute(state), - startTime: state.startTime, -}); - -export default connect(stateToProps)(DriveMap); + }; + + // Initialize on mount - fetch coords and start animation + useEffect(() => { + const route = currentRoute?.fullname || null; + if (route) { + dispatch(fetchDriveCoords(currentRoute)); + } + + animationFrameId.current = requestAnimationFrame(updateMarkerPos); + + return () => { + if (animationFrameId.current) { + cancelAnimationFrame(animationFrameId.current); + } + }; + }, []); + + // Handle route changes + useEffect(() => { + const route = currentRoute?.fullname || null; + if (route) { + dispatch(fetchDriveCoords(currentRoute)); + } else { + setPath([]); + } + }, [currentRoute?.fullname]); + + // Handle startTime changes + useEffect(() => { + if (startTime) { + shouldFlyToRef.current = true; + } + }, [startTime]); + + // Handle driveCoords updates + useEffect(() => { + if (currentRoute?.driveCoords) { + shouldFlyToRef.current = false; + const keys = Object.keys(currentRoute.driveCoords); + setDriveCoordsMin(Math.min(...keys)); + setDriveCoordsMax(Math.max(...keys)); + populateMap(currentRoute); + } + }, [currentRoute?.driveCoords]); + + return ( +
+ +
+ ); +}; + +export default DriveMap; diff --git a/src/components/TimeDisplay/index.jsx b/src/components/TimeDisplay/index.jsx index c5da8230..27379759 100644 --- a/src/components/TimeDisplay/index.jsx +++ b/src/components/TimeDisplay/index.jsx @@ -1,5 +1,5 @@ -import React, { Component } from 'react'; -import { connect } from 'react-redux'; +import React, { useState, useEffect, useRef } from 'react'; +import { useSelector, useDispatch } from 'react-redux'; import dayjs from 'dayjs'; import { withStyles } from '@material-ui/core/styles'; @@ -99,47 +99,25 @@ const styles = (theme) => ({ }, }); -class TimeDisplay extends Component { - static getDerivedStateFromProps(props, state) { - if (props.desiredPlaySpeed !== 0 && props.desiredPlaySpeed !== state.desiredPlaySpeed) { - return { - ...state, - desiredPlaySpeed: props.desiredPlaySpeed, - }; - } - return state; - } - - constructor(props) { - super(props); - - this.textHolder = React.createRef(); +const TimeDisplay = ({ classes, isThin, onMuteToggle, isMuted, hasAudio }) => { + const dispatch = useDispatch(); + const currentRoute = useSelector((state) => selectCurrentRoute(state)); + const zoom = useSelector((state) => selectRouteZoom(state)); + const videoPlaySpeed = useSelector((state) => state.desiredPlaySpeed); - this.updateTime = this.updateTime.bind(this); - this.togglePause = this.togglePause.bind(this); - this.increaseSpeed = this.increaseSpeed.bind(this); - this.decreaseSpeed = this.decreaseSpeed.bind(this); - this.jumpBack = this.jumpBack.bind(this); - this.jumpForward = this.jumpForward.bind(this); - - this.state = { - desiredPlaySpeed: 1, - displayTime: this.getDisplayTime(), - }; - } + const textHolder = useRef(null); + const animationFrameId = useRef(null); + const [desiredPlaySpeed, setDesiredPlaySpeed] = useState(videoPlaySpeed || 1); - componentDidMount() { - this.mounted = true; - requestAnimationFrame(this.updateTime); - } - - componentWillUnmount() { - this.mounted = false; - } + // Update desiredPlaySpeed when videoPlaySpeed changes + useEffect(() => { + if (videoPlaySpeed !== 0) { + setDesiredPlaySpeed(videoPlaySpeed); + } + }, [videoPlaySpeed]); - getDisplayTime() { + const getDisplayTime = () => { const offset = currentOffset(); - const { currentRoute } = this.props; const now = new Date(offset + currentRoute.start_time_utc_millis); if (Number.isNaN(now.getTime())) { return '...'; @@ -149,174 +127,164 @@ class TimeDisplay extends Component { if (seg !== null) { dateString = `${dateString} \u2013 ${seg}`; } - return dateString; - } - - jumpBack(amount) { - this.props.dispatch(seek(currentOffset() - amount)); - } + }; - jumpForward(amount) { - this.props.dispatch(seek(currentOffset() + amount)); - } - - updateTime() { - if (!this.mounted || !this.textHolder.current) { - return; - } - const newDisplayTime = this.getDisplayTime(); - const { displayTime } = this.state; - if (newDisplayTime !== displayTime) { - this.setState({ displayTime: newDisplayTime }); + const updateTime = () => { + if (textHolder.current) { + const newDisplayTime = getDisplayTime(); + // Update DOM directly instead of setState to avoid re-renders every frame + if (textHolder.current.textContent !== newDisplayTime) { + textHolder.current.textContent = newDisplayTime; + } } + animationFrameId.current = requestAnimationFrame(updateTime); + }; - requestAnimationFrame(this.updateTime); - } + const jumpBack = (amount) => { + dispatch(seek(currentOffset() - amount)); + }; - decreaseSpeed() { - const { dispatch } = this.props; - const { desiredPlaySpeed } = this.state; + const jumpForward = (amount) => { + dispatch(seek(currentOffset() + amount)); + }; + + const decreaseSpeed = () => { let curIndex = timerSteps.indexOf(desiredPlaySpeed); if (curIndex === -1) { curIndex = timerSteps.indexOf(1); } curIndex = Math.max(0, curIndex - 1); dispatch(play(timerSteps[curIndex])); - } + }; - canDecreaseSpeed() { - const { desiredPlaySpeed } = this.state; + const canDecreaseSpeed = () => { let curIndex = timerSteps.indexOf(desiredPlaySpeed); if (curIndex === -1) { curIndex = timerSteps.indexOf(1); } return curIndex > 0; - } + }; - increaseSpeed() { - const { dispatch } = this.props; - const { desiredPlaySpeed } = this.state; + const increaseSpeed = () => { let curIndex = timerSteps.indexOf(desiredPlaySpeed); if (curIndex === -1) { curIndex = timerSteps.indexOf(1); } curIndex = Math.min(timerSteps.length - 1, curIndex + 1); dispatch(play(timerSteps[curIndex])); - } + }; - canIncreaseSpeed() { - const { desiredPlaySpeed } = this.state; + const canIncreaseSpeed = () => { let curIndex = timerSteps.indexOf(desiredPlaySpeed); if (curIndex === -1) { curIndex = timerSteps.indexOf(1); } return curIndex < timerSteps.length - 1; - } + }; - togglePause() { - const { desiredPlaySpeed, dispatch } = this.props; - if (desiredPlaySpeed === 0) { - // eslint-disable-next-line react/destructuring-assignment - dispatch(play(this.state.desiredPlaySpeed)); + const togglePause = () => { + if (videoPlaySpeed === 0) { + dispatch(play(desiredPlaySpeed)); } else { dispatch(pause()); } - } + }; + + // Initialize RAF loop on mount + useEffect(() => { + animationFrameId.current = requestAnimationFrame(updateTime); + return () => { + if (animationFrameId.current) { + cancelAnimationFrame(animationFrameId.current); + } + }; + }, []); + + const isPaused = videoPlaySpeed === 0; + const isExpandedCls = zoom ? 'isExpanded' : ''; + const isThinCls = isThin ? 'isThin' : ''; - render() { - const { classes, zoom, desiredPlaySpeed: videoPlaySpeed, isThin, onMuteToggle, isMuted, hasAudio } = this.props; - const { displayTime, desiredPlaySpeed } = this.state; - const isPaused = videoPlaySpeed === 0; - const isExpandedCls = zoom ? 'isExpanded' : ''; - const isThinCls = isThin ? 'isThin' : ''; - return ( -
-
+ return ( +
+
+ jumpBack(10000) } + aria-label="Jump back 10 seconds" + > + + +
+
+ jumpForward(10000) } + aria-label="Jump forward 10 seconds" + > + + +
+ { !isThin && ( + + CURRENT PLAYBACK TIME + + )} + + { getDisplayTime() } + + {!isIos() && ( +
this.jumpBack(10000) } - aria-label="Jump back 10 seconds" + className={classes.tinyArrowIcon} + onClick={increaseSpeed} + disabled={!canIncreaseSpeed()} + aria-label="Increase play speed by 1 step" > - + -
-
+ + {desiredPlaySpeed} + × + this.jumpForward(10000) } - aria-label="Jump forward 10 seconds" + className={classes.tinyArrowIcon} + onClick={decreaseSpeed} + disabled={!canDecreaseSpeed()} + aria-label="Decrease play speed by 1 step" > - +
- { !isThin && ( - - CURRENT PLAYBACK TIME - - )} - - { displayTime } - - {!isIos() && ( -
- - - - - {desiredPlaySpeed} - × - + )} +
+ +
- + {isMuted + ? () + : ()}
- )} -
- -
- - {isMuted - ? () - : ()} - -
-
-
-
- - {isPaused - ? () - : ()} - -
+
- ); - } -} - -const stateToProps = (state) => ({ - currentRoute: selectCurrentRoute(state), - zoom: selectRouteZoom(state), - desiredPlaySpeed: state.desiredPlaySpeed, -}); +
+ + {isPaused + ? () + : ()} + +
+
+ ); +}; -export default connect(stateToProps)(withStyles(styles)(TimeDisplay)); +export default withStyles(styles)(TimeDisplay); diff --git a/src/components/Timeline/index.jsx b/src/components/Timeline/index.jsx index 56734fc2..f01d2a4f 100644 --- a/src/components/Timeline/index.jsx +++ b/src/components/Timeline/index.jsx @@ -1,8 +1,8 @@ // timeline minimap // rapidly change high level timeline stuff // rapid seeking, etc -import React, { Component } from 'react'; -import { connect } from 'react-redux'; +import React, { useState, useEffect, useRef } from 'react'; +import { useSelector, useDispatch } from 'react-redux'; import { withStyles } from '@material-ui/core/styles'; import dayjs from 'dayjs'; @@ -145,207 +145,134 @@ function percentFromPointerEvent(ev) { return x / boundingBox.width; } -class Timeline extends Component { - constructor(props) { - super(props); - - this.getOffset = this.getOffset.bind(this); - this.handleClick = this.handleClick.bind(this); - this.handlePointerMove = this.handlePointerMove.bind(this); - this.handlePointerDown = this.handlePointerDown.bind(this); - this.handlePointerUp = this.handlePointerUp.bind(this); - this.handlePointerLeave = this.handlePointerLeave.bind(this); - this.percentToOffset = this.percentToOffset.bind(this); - this.segmentNum = this.segmentNum.bind(this); - this.onRulerRef = this.onRulerRef.bind(this); - this.renderRoute = this.renderRoute.bind(this); - - this.rulerRemaining = React.createRef(); - this.rulerRef = React.createRef(); - this.dragBar = React.createRef(); - this.hoverBead = React.createRef(); - this.thumbnailsRef = React.createRef(); - - const { zoomOverride, zoom } = this.props; - this.state = { - dragging: null, - hoverX: null, - zoom: zoomOverride || zoom, - thumbnail: { - height: 0, - width: 0, - }, - }; - } +const Timeline = ({ classes, hasRuler, className, route, thumbnailsVisible, zoomOverride }) => { + const dispatch = useDispatch(); + const propsZoom = useSelector((state) => selectRouteZoom(state)); + const dongleId = useSelector((state) => state.dongleId); + + const rulerRemaining = useRef(null); + const rulerRef = useRef(null); + const dragBar = useRef(null); + const hoverBead = useRef(null); + const thumbnailsRef = useRef(null); + const animationFrameId = useRef(null); + const seekIndexRef = useRef(null); + const resizeObserverRef = useRef(null); + + // Store zoom in a ref to avoid triggering state updates + const zoomRef = useRef(zoomOverride || propsZoom); + const [dragging, setDragging] = useState(null); + const [hoverX, setHoverX] = useState(null); + const [thumbnail, setThumbnail] = useState({ height: 0, width: 0 }); + + // Update zoom ref when props change + useEffect(() => { + zoomRef.current = zoomOverride || propsZoom; + }, [zoomOverride, propsZoom]); + + const percentToOffset = (perc) => { + const zoom = zoomRef.current; + return perc * (zoom.end - zoom.start) + zoom.start; + }; - componentDidMount() { - this.mounted = true; - requestAnimationFrame(this.getOffset); - this.componentDidUpdate({}); + const offsetToPercent = (offset) => { + const zoom = zoomRef.current; + return (offset - zoom.start) / (zoom.end - zoom.start); + }; - // Set up ResizeObserver for thumbnails - if (this.thumbnailsRef.current) { - this.resizeObserver = new ResizeObserver((entries) => { - for (const entry of entries) { - const { width, height } = entry.contentRect; - this.setState({ thumbnail: { width, height } }); - } - }); - this.resizeObserver.observe(this.thumbnailsRef.current); + const segmentNum = (offset) => { + if (route) { + return getSegmentNumber(route, offset); } - } + return null; + }; - componentDidUpdate(prevProps) { - const { zoomOverride, zoom } = this.props; - if (prevProps.zoomOverride !== zoomOverride || prevProps.zoom !== zoom) { - this.setState({ zoom: zoomOverride || zoom }); + const getOffset = () => { + animationFrameId.current = requestAnimationFrame(getOffset); + let offset = currentOffset(); + if (seekIndexRef.current) { + offset = seekIndexRef.current; } - } - - componentWillUnmount() { - this.mounted = false; - if (this.resizeObserver) { - this.resizeObserver.disconnect(); + offset = Math.floor(offset); + const percent = offsetToPercent(offset); + if (rulerRemaining.current && rulerRemaining.current.parentElement) { + rulerRemaining.current.style.left = `${Math.floor(10000 * percent) / 100}%`; + rulerRemaining.current.style.width = `${100 - Math.floor(10000 * percent) / 100}%`; } - } + }; - handleClick(ev) { - const { dragging } = this.state; + const handleClick = (ev) => { if (!dragging || Math.abs(dragging[1] - dragging[0]) <= 3) { const percent = percentFromPointerEvent(ev); - this.props.dispatch(seek(this.percentToOffset(percent))); - } - } - - handlePointerDown(ev) { - if (ev.button !== 0) { - return; + dispatch(seek(percentToOffset(percent))); } + }; + const handlePointerMove = (ev) => { ev.preventDefault(); - document.addEventListener('pointerup', this.handlePointerUp); - document.addEventListener('pointermove', this.handlePointerMove); - this.setState({ dragging: [ev.pageX, ev.pageX] }); - } - - handlePointerMove(ev) { - ev.preventDefault(); - const { dragging } = this.state; - if (!this.rulerRef.current) { + if (!rulerRef.current) { return; } - ev.preventDefault(); - const rulerBounds = this.rulerRef.current.getBoundingClientRect(); + const rulerBounds = rulerRef.current.getBoundingClientRect(); const endDrag = Math.max(rulerBounds.x, Math.min(rulerBounds.x + rulerBounds.width, ev.pageX)); if (dragging) { - this.setState({ dragging: [dragging[0], endDrag] }); + setDragging([dragging[0], endDrag]); } - this.setState({ hoverX: endDrag }); - } - - handlePointerUp(ev) { - const { route, dongleId } = this.props; + setHoverX(endDrag); + }; + const handlePointerUp = (ev) => { // prevent preventDefault for back(3) and forward(4) mouse buttons if (ev.button !== 3 && ev.button !== 4) { ev.preventDefault(); } - document.removeEventListener('pointerup', this.handlePointerUp); - document.removeEventListener('pointermove', this.handlePointerMove); - const { dragging } = this.state; + document.removeEventListener('pointerup', handlePointerUp); + document.removeEventListener('pointermove', handlePointerMove); if (!dragging) { return; } - this.setState({ dragging: null }); + setDragging(null); - const rulerBounds = this.rulerRef.current.getBoundingClientRect(); + const rulerBounds = rulerRef.current.getBoundingClientRect(); const startPercent = (Math.min(dragging[0], dragging[1]) - rulerBounds.x) / rulerBounds.width; const endPercent = (Math.max(dragging[0], dragging[1]) - rulerBounds.x) / rulerBounds.width; - const startOffset = Math.round(this.percentToOffset(startPercent)); - const endOffset = Math.round(this.percentToOffset(endPercent)); + const startOffset = Math.round(percentToOffset(startPercent)); + const endOffset = Math.round(percentToOffset(endPercent)); if (Math.abs(dragging[1] - dragging[0]) > 3) { const startSec = Math.floor(startOffset / 1000); const endSec = Math.floor(endOffset / 1000); navigate(`/${dongleId}/${route.log_id}/${startSec}/${endSec}`); } else if (ev.currentTarget !== document) { - this.handleClick(ev); - } - } - - handlePointerLeave() { - this.setState({ hoverX: null }); - } - - onRulerRef(el) { - this.rulerRef.current = el; - if (el) { - el.addEventListener('touchstart', (ev) => ev.stopPropagation()); + handleClick(ev); } - } + }; - getOffset() { - if (!this.mounted) { + const handlePointerDown = (ev) => { + if (ev.button !== 0) { return; } - requestAnimationFrame(this.getOffset); - let offset = currentOffset(); - if (this.seekIndex) { - offset = this.seekIndex; - } - offset = Math.floor(offset); - const percent = this.offsetToPercent(offset); - if (this.rulerRemaining.current && this.rulerRemaining.current.parentElement) { - this.rulerRemaining.current.style.left = `${Math.floor(10000 * percent) / 100}%`; - this.rulerRemaining.current.style.width = `${100 - Math.floor(10000 * percent) / 100}%`; - } - } - - percentToOffset(perc) { - const { zoom } = this.state; - return perc * (zoom.end - zoom.start) + zoom.start; - } - - offsetToPercent(offset) { - const { zoom } = this.state; - return (offset - zoom.start) / (zoom.end - zoom.start); - } - segmentNum(offset) { - const { route } = this.props; - if (route) { - return getSegmentNumber(route, offset); - } - return null; - } + ev.preventDefault(); + document.addEventListener('pointerup', handlePointerUp); + document.addEventListener('pointermove', handlePointerMove); + setDragging([ev.pageX, ev.pageX]); + }; - renderRoute() { - const { classes, route } = this.props; - const { zoom } = this.state; + const handlePointerLeave = () => { + setHoverX(null); + }; - if (!route.events) { - return null; + const onRulerRef = (el) => { + rulerRef.current = el; + if (el) { + el.addEventListener('touchstart', (ev) => ev.stopPropagation()); } + }; - const zoomDuration = zoom.end - zoom.start; - const startPerc = (100 * (-zoom.start)) / zoomDuration; - const widthPerc = (100 * route.duration) / zoomDuration; - - const style = { - width: `${widthPerc}%`, - left: `${startPerc}%`, - }; - return ( -
- { this.renderRouteEvents(route) } -
- ); - } - - renderRouteEvents(route) { - const { classes } = this.props; + const renderRouteEvents = (route) => { if (!route.events) { return null; } @@ -367,91 +294,131 @@ class Timeline extends Component { /> ); }); - } + }; - render() { - const { classes, hasRuler, className, route, thumbnailsVisible } = this.props; - const { thumbnail, hoverX, dragging } = this.state; + const renderRoute = () => { + const zoom = zoomRef.current; + if (!route.events) { + return null; + } - const hasRulerCls = hasRuler ? 'hasRuler' : ''; + const zoomDuration = zoom.end - zoom.start; + const startPerc = (100 * (-zoom.start)) / zoomDuration; + const widthPerc = (100 * route.duration) / zoomDuration; - let rulerBounds; - if (this.rulerRef.current) { - rulerBounds = this.rulerRef.current.getBoundingClientRect(); - } + const style = { + width: `${widthPerc}%`, + left: `${startPerc}%`, + }; + return ( +
+ { renderRouteEvents(route) } +
+ ); + }; - let hoverString; let - hoverStyle; - if (rulerBounds && hoverX) { - const hoverOffset = this.percentToOffset((hoverX - rulerBounds.x) / rulerBounds.width); - hoverStyle = { left: Math.max(-10, Math.min(rulerBounds.width - 70, hoverX - rulerBounds.x - 40)) }; - if (!Number.isNaN(hoverOffset)) { - hoverString = dayjs(route.start_time_utc_millis + hoverOffset).format('HH:mm:ss'); - const segNum = this.segmentNum(hoverOffset); - if (segNum !== null) { - hoverString = `${segNum}, ${hoverString}`; - } + // Initialize on mount - RAF loop + useEffect(() => { + animationFrameId.current = requestAnimationFrame(getOffset); + + return () => { + if (animationFrameId.current) { + cancelAnimationFrame(animationFrameId.current); } - } + }; + }, []); + + // Set up ResizeObserver for thumbnails + useEffect(() => { + if (thumbnailsRef.current) { + resizeObserverRef.current = new ResizeObserver((entries) => { + for (const entry of entries) { + const { width, height } = entry.contentRect; + setThumbnail({ width, height }); + } + }); + resizeObserverRef.current.observe(thumbnailsRef.current); - let draggerStyle; - if (rulerBounds && dragging && Math.abs(dragging[1] - dragging[0]) > 0) { - draggerStyle = { - left: `${Math.min(dragging[1], dragging[0]) - rulerBounds.x}px`, - width: `${Math.abs(dragging[1] - dragging[0])}px`, + return () => { + if (resizeObserverRef.current) { + resizeObserverRef.current.disconnect(); + } }; } + }, []); - const baseWidthStyle = { width: '100%' }; + const hasRulerCls = hasRuler ? 'hasRuler' : ''; - return ( -
-
-
- { route && this.renderRoute() } -
-
-
- { thumbnailsVisible && ( - - ) } -
- { hasRuler && ( - <> -
-
- { draggerStyle &&
} -
- { hoverString && ( -
- { hoverString } -
- ) } - + let rulerBounds; + if (rulerRef.current) { + rulerBounds = rulerRef.current.getBoundingClientRect(); + } + + let hoverString; let + hoverStyle; + if (rulerBounds && hoverX) { + const hoverOffset = percentToOffset((hoverX - rulerBounds.x) / rulerBounds.width); + hoverStyle = { left: Math.max(-10, Math.min(rulerBounds.width - 70, hoverX - rulerBounds.x - 40)) }; + if (!Number.isNaN(hoverOffset)) { + hoverString = dayjs(route.start_time_utc_millis + hoverOffset).format('HH:mm:ss'); + const segNum = segmentNum(hoverOffset); + if (segNum !== null) { + hoverString = `${segNum}, ${hoverString}`; + } + } + } + + let draggerStyle; + if (rulerBounds && dragging && Math.abs(dragging[1] - dragging[0]) > 0) { + draggerStyle = { + left: `${Math.min(dragging[1], dragging[0]) - rulerBounds.x}px`, + width: `${Math.abs(dragging[1] - dragging[0])}px`, + }; + } + + const baseWidthStyle = { width: '100%' }; + + return ( +
+
+
+ { route && renderRoute() } +
+
+
+ { thumbnailsVisible && ( + ) }
+ { hasRuler && ( + <> +
+
+ { draggerStyle &&
} +
+ { hoverString && ( +
+ { hoverString } +
+ ) } + + ) }
- ); - } -} - -const stateToProps = (state) => ({ - zoom: selectRouteZoom(state), - loop: state.loop, - dongleId: state.dongleId, -}); +
+ ); +}; -export default connect(stateToProps)(withStyles(styles)(Timeline)); +export default withStyles(styles)(Timeline); From be01d241841576f21bd0b0f0a986a229192f6b6f Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 2 Nov 2025 17:55:13 -0800 Subject: [PATCH 13/26] biome! --- .eslintignore | 5 -- .eslintrc.js | 68 ------------------ AGENTS.md | 18 +++++ biome.json | 38 ++++++++++ bun.lockb | Bin 487537 -> 460988 bytes package.json | 7 +- src/App.jsx | 25 +++---- src/__tests__/App.test.jsx | 2 +- src/actions/cached.js | 6 +- src/actions/files.js | 15 ++-- src/actions/history.test.js | 5 +- src/actions/index.js | 13 ++-- src/actions/startup.js | 5 +- src/components/AppDrawer/index.jsx | 13 ++-- src/components/AppHeader/AccountMenu.jsx | 10 ++- src/components/AppHeader/index.jsx | 14 ++-- src/components/Dashboard/AddDevice.jsx | 13 ++-- src/components/Dashboard/DeviceList.jsx | 16 ++--- .../Dashboard/DeviceSettingsModal.jsx | 12 ++-- src/components/Dashboard/DriveList.jsx | 10 ++- src/components/Dashboard/DriveListEmpty.jsx | 1 - src/components/Dashboard/DriveListItem.jsx | 11 ++- .../Dashboard/DriveListItem.test.js | 4 +- src/components/Dashboard/index.jsx | 10 ++- src/components/DeviceInfo/index.jsx | 16 ++--- src/components/DriveMap/index.jsx | 20 +++--- src/components/DriveVideo/index.jsx | 16 ++--- src/components/DriveView/Media.jsx | 37 +++++----- src/components/DriveView/NoDeviceUpsell.jsx | 2 +- src/components/DriveView/index.jsx | 18 ++--- src/components/ErrorFallback.jsx | 2 +- src/components/Files/UploadQueue.jsx | 14 ++-- src/components/IosPwaPopup/index.jsx | 15 ++-- src/components/Navigation/index.jsx | 20 +++--- src/components/PWAIcon.jsx | 3 +- src/components/Prime/PrimeCheckout.jsx | 26 ++++--- src/components/Prime/PrimeManage.jsx | 25 +++---- src/components/Prime/index.jsx | 6 +- .../ResizeHandler/ResizeHandler.test.js | 5 +- src/components/ResizeHandler/index.js | 31 ++++---- src/components/ScrollIntoView/index.jsx | 2 +- src/components/TimeDisplay/index.jsx | 18 ++--- src/components/TimeSelect/index.jsx | 14 ++-- src/components/Timeline/index.jsx | 14 ++-- src/components/Timeline/thumbnails.jsx | 2 +- src/components/Timeline/thumbnails.test.js | 2 +- src/components/VisibilityHandler/index.jsx | 4 +- src/components/anonymous.jsx | 10 +-- src/components/explorer.jsx | 29 ++++---- src/components/utils/InfoTooltip.jsx | 2 +- src/components/utils/PullDownReload.jsx | 3 +- src/components/utils/SwitchLoading.jsx | 5 +- src/historySync.js | 4 +- src/icons/index.jsx | 2 +- src/index.jsx | 5 +- src/reducers/globalState.js | 1 - src/store.js | 5 +- src/timeline/segments.test.js | 3 +- src/utils/geocode.js | 3 +- 59 files changed, 312 insertions(+), 393 deletions(-) delete mode 100644 .eslintignore delete mode 100644 .eslintrc.js create mode 100644 AGENTS.md create mode 100644 biome.json diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 33512fa0..00000000 --- a/.eslintignore +++ /dev/null @@ -1,5 +0,0 @@ -node_modules/ -public/ -build/ -.storybook -src/stories/* diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index c4118bf7..00000000 --- a/.eslintrc.js +++ /dev/null @@ -1,68 +0,0 @@ -module.exports = { - extends: [ - 'eslint:recommended', - 'plugin:react/recommended', - 'plugin:jest-dom/recommended', - ], - parserOptions: { - ecmaVersion: 2020, - sourceType: "module", - }, - rules: { - 'camelcase': 0, - 'class-methods-use-this': 0, - 'default-case': 'error', - 'import/prefer-default-export': 0, - 'import/no-named-as-default': 0, - 'react/destructuring-assignment': 0, - 'react/jsx-curly-spacing': 0, - 'react/jsx-filename-extension': 0, - 'react/forbid-prop-types': 0, - 'react/function-component-definition': [ - 'error', - { - namedComponents: 'arrow-function', - }, - ], - 'react/prop-types': 0, - 'react/require-default-props': 0, - 'react/sort-comp': 0, - 'max-len': 0, - 'no-await-in-loop': 'error', - 'no-case-declarations': 'error', - 'no-console': 0, - 'no-else-return': 0, - 'no-empty': 'error', - 'no-multi-spaces': ['error', { - ignoreEOLComments: true, - }], - 'no-nested-ternary': 0, - 'no-plusplus': [ - 'error', - { - allowForLoopAfterthoughts: true, - }, - ], - 'no-param-reassign': 0, - 'no-shadow': 'error', - 'no-underscore-dangle': 0, - 'no-unused-vars': ['error', { - args: 'none', - }], - 'no-use-before-define': 'error', - 'object-curly-newline': [ - 'error', - { - consistent: true, - }, - ], - 'quote-props': ['error', 'as-needed', { - unnecessary: false, - }], - }, - env: { - es6: true, - node: true, - browser: true, - }, -}; diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..cb28e24b --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,18 @@ +welcome! + +our goal is to modernize and cleanup this ancient codebase. +you are a refactoring machine! you love clean code and ripping out complexity. +and i will wisely guide you. + +your loop is: +- evaluate the options and come up with a plan +- i will give feedback and an approval +- if i give feedback, please present the plan again given the feedback before proceeding + + +for all changes, make sure to: +- run the tests +- run the linter and formatter ("bun lint") + +some more tips: +- always prioritize the simple, straightforward changes over risky big ones. diff --git a/biome.json b/biome.json new file mode 100644 index 00000000..585af7db --- /dev/null +++ b/biome.json @@ -0,0 +1,38 @@ +{ + "$schema": "https://biomejs.dev/schemas/2.3.2/schema.json", + "vcs": { + "enabled": true, + "clientKind": "git", + "useIgnoreFile": true + }, + "files": { + "includes": ["**", "!!**/dist"] + }, + "formatter": { + "enabled": false + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "correctness": { + "noUnusedFunctionParameters": "off" + }, + "suspicious": { + "noArrayIndexKey": "off", + "noUnknownAtRules": "off", + "noExportsInTest": "off" + }, + "complexity": { + "useOptionalChain": "off" + }, + "a11y": { + "noStaticElementInteractions": "off", + "useKeyWithClickEvents": "off", + "useValidAnchor": "off", + "useMediaCaption": "off", + "useAltText": "off" + } + } + } +} diff --git a/bun.lockb b/bun.lockb index 2d0fc00cf10f6a4e06bbaa59fa5546fbc5d706d1..1605bd836dffd3b8f440a1738d385a28e0d1665d 100755 GIT binary patch delta 70808 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

i~=G*2)f>D6$8d#!l$XpnF+)p?a`!1t!bxkY;sE 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%0D0lETg1oF_v)+HN> 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 DY=o8@ diff --git a/package.json b/package.json index 28593052..9a96a001 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "build:development": "vite build --mode development", "build:production": "vite build", "serve": "vite preview", - "lint": "eslint --ext .js,.jsx,.ts,.tsx src", + "lint": "biome lint src", "test": "jest", "test-coverage": "jest --coverage", "test-puppeteer": "jest -c src/__puppeteer__/jest.config.js", @@ -47,6 +47,7 @@ "redux-thunk": "^2.4.2" }, "devDependencies": { + "@biomejs/biome": "^2.3.2", "@swc/core": "^1.3.80", "@swc/jest": "^0.2.29", "@tailwindcss/typography": "^0.5.9", @@ -55,10 +56,6 @@ "@vitejs/plugin-react": "^4.0.4", "autoprefixer": "^10.4.15", "camelcase": "^6.3.0", - "eslint": "^8.48.0", - "eslint-plugin-import": "^2.28.1", - "eslint-plugin-jest-dom": "^5.1.0", - "eslint-plugin-react": "^7.33.2", "expect-puppeteer": "^9.0.0", "jest": "^27.5.1", "jest-chain-transform": "^0.0.5", diff --git a/src/App.jsx b/src/App.jsx index f63d76d7..e1f4dbf5 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,20 +1,15 @@ -import React, { Component, lazy, Suspense } from 'react'; -import { Provider } from 'react-redux'; -import { Route, Switch, Redirect } from 'react-router'; -import { Router } from 'react-router'; -import localforage from 'localforage'; -import * as Sentry from '@sentry/react'; - -import { CircularProgress, Grid } from '@material-ui/core'; - -import MyCommaAuth, { config as AuthConfig, storage as AuthStorage } from '@commaai/my-comma-auth'; import { athena as Athena, auth as Auth, billing as Billing, request as Request } from '@commaai/api'; - -import { getZoom, getSegmentRange } from './url'; -import store from './store'; -import { history } from './history'; - +import MyCommaAuth, { config as AuthConfig, storage as AuthStorage } from '@commaai/my-comma-auth'; +import { CircularProgress, Grid } from '@material-ui/core'; +import * as Sentry from '@sentry/react'; +import localforage from 'localforage'; +import { Component, lazy, Suspense } from 'react'; +import { Provider } from 'react-redux'; +import { Redirect, Route, Router, Switch } from 'react-router'; import ErrorFallback from './components/ErrorFallback'; +import { history } from './history'; +import store from './store'; +import { getSegmentRange, getZoom } from './url'; const Explorer = lazy(() => import('./components/explorer')); const AnonymousLanding = lazy(() => import('./components/anonymous')); diff --git a/src/__tests__/App.test.jsx b/src/__tests__/App.test.jsx index 4231306b..1edf7d88 100644 --- a/src/__tests__/App.test.jsx +++ b/src/__tests__/App.test.jsx @@ -1,5 +1,5 @@ /* eslint-env jest */ -import React from 'react'; + import { act, render } from '@testing-library/react'; import App from '../App'; diff --git a/src/actions/cached.js b/src/actions/cached.js index c9f00e30..2ada313f 100644 --- a/src/actions/cached.js +++ b/src/actions/cached.js @@ -1,8 +1,7 @@ import * as Sentry from '@sentry/react'; - -import * as Types from './types'; -import { reverseLookup } from '../utils/geocode'; import { toBool } from '../utils'; +import { reverseLookup } from '../utils/geocode'; +import * as Types from './types'; const USE_LOCAL_COORDS_DATA = toBool(import.meta.env.VITE_APP_LOCAL_COORDS_DATA); if (USE_LOCAL_COORDS_DATA) { @@ -489,6 +488,7 @@ export function fetchDriveCoords(route) { } driveCoords = driveCoords.reduce((prev, curr) => ({ + // biome-ignore lint/performance/noAccumulatingSpread: existing code pattern, refactoring would require testing to ensure behavior unchanged ...prev, ...curr.reduce((p, cs) => { p[cs.t] = [cs.lng, cs.lat]; diff --git a/src/actions/files.js b/src/actions/files.js index 182291bf..f4f1460e 100644 --- a/src/actions/files.js +++ b/src/actions/files.js @@ -1,9 +1,8 @@ -import * as Sentry from '@sentry/react'; import { athena as Athena, devices as Devices, raw as Raw } from '@commaai/api'; - -import { updateDeviceOnline, fetchDeviceNetworkStatus } from '.'; +import * as Sentry from '@sentry/react'; +import { asyncSleep, deviceOnCellular, deviceVersionAtLeast, getDeviceFromState } from '../utils'; +import { fetchDeviceNetworkStatus, updateDeviceOnline } from '.'; import * as Types from './types'; -import { deviceOnCellular, getDeviceFromState, deviceVersionAtLeast, asyncSleep } from '../utils'; export const FILE_NAMES = { qcameras: ['qcamera.ts'], @@ -249,13 +248,13 @@ export function doUpload(dongleId, paths, urls) { }, {}); dispatch(updateFiles(newUploading)); } else if (resp.result) { - let failed = resp.result.failed || []; + const failed = resp.result.failed || []; // only if all file names for a segment file type failed - let failedFiltered = []; + const failedFiltered = []; for (const f of failed) { - let failedCnt = failed.filter((p) => pathToFileName(dongleId, p) === pathToFileName(dongleId, f)).length; - let requestedCnt = paths.filter((p) => pathToFileName(dongleId, p) === pathToFileName(dongleId, f)).length; + const failedCnt = failed.filter((p) => pathToFileName(dongleId, p) === pathToFileName(dongleId, f)).length; + const requestedCnt = paths.filter((p) => pathToFileName(dongleId, p) === pathToFileName(dongleId, f)).length; if (failedCnt >= requestedCnt) { failedFiltered.push(f); } diff --git a/src/actions/history.test.js b/src/actions/history.test.js index da83659c..2da2b6ca 100644 --- a/src/actions/history.test.js +++ b/src/actions/history.test.js @@ -1,9 +1,10 @@ /* eslint-env jest */ + +import { drives as Drives } from '@commaai/api'; import { history } from '../history'; import installHistorySync from '../historySync'; -import * as actionsIndex from './index'; -import { drives as Drives } from '@commaai/api'; import { replace } from '../navigation'; +import * as actionsIndex from './index'; jest.mock('./index', () => ({ selectDevice: jest.fn(), diff --git a/src/actions/index.js b/src/actions/index.js index 5772dcb4..505233f4 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -1,13 +1,12 @@ -import * as Sentry from '@sentry/react'; import { athena as Athena, billing as Billing, devices as Devices, drives as Drives } from '@commaai/api'; import MyCommaAuth from '@commaai/my-comma-auth'; - -import * as Types from './types'; +import * as Sentry from '@sentry/react'; +import { navigate } from '../navigation'; +import { selectSegmentRange } from '../selectors/route'; import { resetPlayback, selectLoop } from '../timeline/playback'; import {hasRoutesData } from '../timeline/segments'; -import { selectSegmentRange } from '../selectors/route'; -import { getDeviceFromState, deviceVersionAtLeast } from '../utils'; -import { navigate } from '../navigation'; +import { deviceVersionAtLeast, getDeviceFromState } from '../utils'; +import * as Types from './types'; let routesRequest = null; let routesRequestPromise = null; @@ -158,7 +157,7 @@ export function urlForState(dongleId, log_id, start, end) { return `/${path.join('/')}`; } -function updateTimeline(state, dispatch, log_id, start, end, allowPathChange) { +function _updateTimeline(state, dispatch, log_id, start, end, allowPathChange) { if (!state.loop || !state.loop.startTime || !state.loop.duration || state.loop.startTime < start || state.loop.startTime + state.loop.duration > end || state.loop.duration < end - start) { dispatch(resetPlayback()); diff --git a/src/actions/startup.js b/src/actions/startup.js index 66901080..025b809d 100644 --- a/src/actions/startup.js +++ b/src/actions/startup.js @@ -1,9 +1,8 @@ -import * as Sentry from '@sentry/react'; import { account as Account, devices as Devices } from '@commaai/api'; import MyCommaAuth from '@commaai/my-comma-auth'; - +import * as Sentry from '@sentry/react'; +import { checkLastRoutesData, fetchSharedDevice, primeFetchSubscription, selectDevice } from '.'; import { ACTION_STARTUP_DATA } from './types'; -import { primeFetchSubscription, checkLastRoutesData, selectDevice, fetchSharedDevice } from '.'; async function initProfile() { if (MyCommaAuth.isAuthenticated()) { diff --git a/src/components/AppDrawer/index.jsx b/src/components/AppDrawer/index.jsx index 00c313d6..98fcfba9 100644 --- a/src/components/AppDrawer/index.jsx +++ b/src/components/AppDrawer/index.jsx @@ -1,12 +1,9 @@ -import React, { useCallback, useEffect, useRef } from 'react'; -import { useSelector, useDispatch } from 'react-redux'; -import { Link } from 'react-router-dom'; - import Drawer from '@material-ui/core/Drawer'; - -import DeviceList from '../Dashboard/DeviceList'; - +import { useCallback, useEffect, useRef } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { Link } from 'react-router-dom'; import { selectDevice } from '../../actions'; +import DeviceList from '../Dashboard/DeviceList'; const listener = (ev) => ev.stopPropagation(); @@ -23,7 +20,7 @@ const AppDrawer = ({ return () => { if (el) el.removeEventListener('touchstart', listener); }; - }, [contentRef]); + }, []); const toggleDrawerOff = useCallback(() => { handleDrawerStateChanged(false); diff --git a/src/components/AppHeader/AccountMenu.jsx b/src/components/AppHeader/AccountMenu.jsx index ec9ed2a8..fe652ea5 100644 --- a/src/components/AppHeader/AccountMenu.jsx +++ b/src/components/AppHeader/AccountMenu.jsx @@ -1,14 +1,12 @@ -import React, { useCallback, useMemo } from 'react'; -import dayjs from 'dayjs'; - +import MyCommaAuth from '@commaai/my-comma-auth'; import { Divider, ListItem, Menu, MenuItem, } from '@material-ui/core'; - -import MyCommaAuth from '@commaai/my-comma-auth'; +import dayjs from 'dayjs'; +import { useCallback, useMemo } from 'react'; const logOut = async () => { await MyCommaAuth.logOut(); @@ -21,7 +19,7 @@ const Version = () => { const sha = import.meta.env.VITE_APP_GIT_SHA; const timestamp = import.meta.env.VITE_APP_GIT_TIMESTAMP; - let content = ['Version: ']; + const content = ['Version: ']; if (sha) { const commitUrl = `https://github.com/commaai/connect/commit/${sha}`; diff --git a/src/components/AppHeader/index.jsx b/src/components/AppHeader/index.jsx index f282c49a..67317ad4 100644 --- a/src/components/AppHeader/index.jsx +++ b/src/components/AppHeader/index.jsx @@ -1,18 +1,16 @@ -import React, { Suspense, useCallback, useState } from 'react'; -import { useSelector, useDispatch } from 'react-redux'; +import MyCommaAuth from '@commaai/my-comma-auth'; +import { AppBar, Icon, IconButton, Typography } from '@material-ui/core'; import { withStyles } from '@material-ui/core/styles'; -import { Typography, IconButton, Icon, AppBar } from '@material-ui/core'; - -import MyCommaAuth from '@commaai/my-comma-auth'; +import { Suspense, useCallback, useState } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; import { selectDevice } from '../../actions'; -import { AccountIcon } from '../../icons'; import Colors from '../../colors'; +import { AccountIcon } from '../../icons'; import { filterRegularClick } from '../../utils'; - -import AccountMenu from './AccountMenu'; import PWAIcon from '../PWAIcon'; +import AccountMenu from './AccountMenu'; const styles = () => ({ header: { diff --git a/src/components/Dashboard/AddDevice.jsx b/src/components/Dashboard/AddDevice.jsx index 82f93a48..712b8f4d 100644 --- a/src/components/Dashboard/AddDevice.jsx +++ b/src/components/Dashboard/AddDevice.jsx @@ -1,14 +1,13 @@ -import React, { Component } from 'react'; -import { connect } from 'react-redux'; -import QrScanner from 'qr-scanner'; -import { withStyles, Typography, Button, Modal, Paper, Divider, CircularProgress } from '@material-ui/core'; +import { devices as Devices } from '@commaai/api'; +import { Button, CircularProgress, Divider, Modal, Paper, Typography, withStyles } from '@material-ui/core'; import AddCircleOutlineIcon from '@material-ui/icons/AddCircleOutline'; import * as Sentry from '@sentry/react'; - -import { devices as Devices } from '@commaai/api'; +import QrScanner from 'qr-scanner'; +import { Component } from 'react'; +import { connect } from 'react-redux'; import { selectDevice, updateDevice } from '../../actions'; -import { verifyPairToken, pairErrorToMessage } from '../../utils'; import Colors from '../../colors'; +import { pairErrorToMessage, verifyPairToken } from '../../utils'; const styles = (theme) => ({ titleContainer: { diff --git a/src/components/Dashboard/DeviceList.jsx b/src/components/Dashboard/DeviceList.jsx index ac9dbe95..77493cc8 100644 --- a/src/components/Dashboard/DeviceList.jsx +++ b/src/components/Dashboard/DeviceList.jsx @@ -1,16 +1,14 @@ -import React, { useState, useCallback } from 'react'; -import { useSelector, useDispatch } from 'react-redux'; -import * as Sentry from '@sentry/react'; - -import { withStyles, Typography, IconButton } from '@material-ui/core'; -import SettingsIcon from '@material-ui/icons/Settings'; - -import MyCommaAuth from '@commaai/my-comma-auth'; import { devices as Devices } from '@commaai/api'; +import MyCommaAuth from '@commaai/my-comma-auth'; +import { IconButton, Typography, withStyles } from '@material-ui/core'; +import SettingsIcon from '@material-ui/icons/Settings'; +import * as Sentry from '@sentry/react'; +import { useCallback, useState } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; import { updateDevices } from '../../actions'; import Colors from '../../colors'; -import { deviceNamePretty, deviceIsOnline, filterRegularClick, emptyDevice } from '../../utils'; +import { deviceIsOnline, deviceNamePretty, emptyDevice, filterRegularClick } from '../../utils'; import VisibilityHandler from '../VisibilityHandler'; import AddDevice from './AddDevice'; diff --git a/src/components/Dashboard/DeviceSettingsModal.jsx b/src/components/Dashboard/DeviceSettingsModal.jsx index 7fb1fa14..3742505a 100644 --- a/src/components/Dashboard/DeviceSettingsModal.jsx +++ b/src/components/Dashboard/DeviceSettingsModal.jsx @@ -1,7 +1,4 @@ -import React, { Component } from 'react'; -import { connect } from 'react-redux'; -import * as Sentry from '@sentry/react'; - +import { devices as Devices } from '@commaai/api'; import { Button, CircularProgress, @@ -17,12 +14,13 @@ import CheckIcon from '@material-ui/icons/Check'; import SaveIcon from '@material-ui/icons/Save'; import ShareIcon from '@material-ui/icons/Share'; import WarningIcon from '@material-ui/icons/Warning'; - -import { devices as Devices } from '@commaai/api'; +import * as Sentry from '@sentry/react'; +import { Component } from 'react'; +import { connect } from 'react-redux'; import { selectDevice, updateDevice } from '../../actions'; -import { navigate } from '../../navigation'; import Colors from '../../colors'; import { ErrorOutline } from '../../icons'; +import { navigate } from '../../navigation'; import UploadQueue from '../Files/UploadQueue'; const styles = (theme) => ({ diff --git a/src/components/Dashboard/DriveList.jsx b/src/components/Dashboard/DriveList.jsx index 39a7194c..605e278b 100644 --- a/src/components/Dashboard/DriveList.jsx +++ b/src/components/Dashboard/DriveList.jsx @@ -1,13 +1,11 @@ -import React from 'react'; -import { useSelector, useDispatch } from 'react-redux'; -import { withStyles, Typography } from '@material-ui/core'; +import { Typography, withStyles } from '@material-ui/core'; +import { useDispatch, useSelector } from 'react-redux'; -import { checkRoutesData, checkLastRoutesData } from '../../actions'; +import { checkLastRoutesData, checkRoutesData } from '../../actions'; +import ScrollIntoView from '../ScrollIntoView' import VisibilityHandler from '../VisibilityHandler'; - import DriveListEmpty from './DriveListEmpty'; import DriveListItem from './DriveListItem'; -import ScrollIntoView from '../ScrollIntoView' const styles = () => ({ drivesTable: { diff --git a/src/components/Dashboard/DriveListEmpty.jsx b/src/components/Dashboard/DriveListEmpty.jsx index 2147f256..b49ff29c 100644 --- a/src/components/Dashboard/DriveListEmpty.jsx +++ b/src/components/Dashboard/DriveListEmpty.jsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Grid, Typography, withStyles } from '@material-ui/core'; import { useWindowWidth } from '../../hooks/window'; diff --git a/src/components/Dashboard/DriveListItem.jsx b/src/components/Dashboard/DriveListItem.jsx index b177bf92..06dad958 100644 --- a/src/components/Dashboard/DriveListItem.jsx +++ b/src/components/Dashboard/DriveListItem.jsx @@ -1,15 +1,14 @@ -import React, { useEffect, useRef, useState } from 'react'; -import { useDispatch } from 'react-redux'; +import { Grid, Typography, withStyles } from '@material-ui/core'; import dayjs from 'dayjs'; - -import { withStyles, Grid, Typography } from '@material-ui/core'; +import { useEffect, useRef, useState } from 'react'; +import { useDispatch } from 'react-redux'; import { pushTimelineRange } from '../../actions'; import { fetchEvents, fetchLocations } from '../../actions/cached'; import Colors from '../../colors'; import { useWindowWidth } from '../../hooks/window'; import { RightArrow } from '../../icons'; -import { formatDriveDuration, filterRegularClick } from '../../utils'; +import { filterRegularClick, formatDriveDuration } from '../../utils'; import { isMetric, KM_PER_MI } from '../../utils/conversions'; import Timeline from '../Timeline'; @@ -82,7 +81,7 @@ const DriveListItem = (props) => { window.removeEventListener('scroll', onScroll); window.removeEventListener('resize', onScroll); }; - }, [drive, dispatch, isVisible, el]); + }, [drive, dispatch, isVisible]); const onClick = filterRegularClick( () => dispatch(pushTimelineRange(drive.log_id, 0, drive.duration, true)), diff --git a/src/components/Dashboard/DriveListItem.test.js b/src/components/Dashboard/DriveListItem.test.js index 1910bd77..72fc933d 100644 --- a/src/components/Dashboard/DriveListItem.test.js +++ b/src/components/Dashboard/DriveListItem.test.js @@ -1,8 +1,8 @@ /* eslint-env jest */ -import React from 'react'; + +import { render, screen } from '@testing-library/react'; import * as Redux from 'redux'; import thunk from 'redux-thunk'; -import { render, screen } from '@testing-library/react'; import DriveListItem from './DriveListItem'; const defaultState = { diff --git a/src/components/Dashboard/index.jsx b/src/components/Dashboard/index.jsx index f077856a..4f6b42c3 100644 --- a/src/components/Dashboard/index.jsx +++ b/src/components/Dashboard/index.jsx @@ -1,12 +1,10 @@ -import React, { lazy, Suspense } from 'react'; +import { CircularProgress, Grid } from '@material-ui/core'; +import { lazy, Suspense } from 'react'; import { useSelector } from 'react-redux'; import { withRouter } from 'react-router'; - -import { CircularProgress, Grid } from '@material-ui/core'; - -import DriveList from './DriveList'; -import Navigation from '../Navigation'; import DeviceInfo from '../DeviceInfo'; +import Navigation from '../Navigation'; +import DriveList from './DriveList'; const Prime = lazy(() => import('../Prime')); diff --git a/src/components/DeviceInfo/index.jsx b/src/components/DeviceInfo/index.jsx index 55567df6..33a4db09 100644 --- a/src/components/DeviceInfo/index.jsx +++ b/src/components/DeviceInfo/index.jsx @@ -1,18 +1,16 @@ -import React, { Component } from 'react'; -import { connect } from 'react-redux'; +import { athena as Athena, devices as Devices } from '@commaai/api'; +import { Button, CircularProgress, Popper, Tooltip, Typography, withStyles } from '@material-ui/core'; +import AccessTime from '@material-ui/icons/AccessTime'; import * as Sentry from '@sentry/react'; import dayjs from 'dayjs'; - -import { withStyles, Typography, Button, CircularProgress, Popper, Tooltip } from '@material-ui/core'; -import AccessTime from '@material-ui/icons/AccessTime'; - -import { athena as Athena, devices as Devices } from '@commaai/api'; +import React, { Component } from 'react'; +import { connect } from 'react-redux'; import Colors from '../../colors'; -import { deviceNamePretty, deviceIsOnline } from '../../utils'; +import { deviceIsOnline, deviceNamePretty } from '../../utils'; import { isMetric, KM_PER_MI } from '../../utils/conversions'; import ResizeHandler from '../ResizeHandler'; -import VisibilityHandler from '../VisibilityHandler'; import TimeSelect from '../TimeSelect' +import VisibilityHandler from '../VisibilityHandler'; const styles = (theme) => ({ container: { diff --git a/src/components/DriveMap/index.jsx b/src/components/DriveMap/index.jsx index cff78af3..478a9f38 100644 --- a/src/components/DriveMap/index.jsx +++ b/src/components/DriveMap/index.jsx @@ -1,11 +1,8 @@ -import React, { useState, useEffect, useRef } from 'react'; -import { useSelector, useDispatch } from 'react-redux'; - -import { selectCurrentRoute } from '../../selectors/route'; - +import { useEffect, useRef, useState } from 'react'; import ReactMapGL, { LinearInterpolator } from 'react-map-gl'; - +import { useDispatch, useSelector } from 'react-redux'; import { fetchDriveCoords } from '../../actions/cached'; +import { selectCurrentRoute } from '../../selectors/route'; import { currentOffset } from '../../timeline'; import { DEFAULT_LOCATION, MAPBOX_STYLE, MAPBOX_TOKEN } from '../../utils/geocode'; @@ -123,7 +120,7 @@ const DriveMap = () => { const route = currentRouteRef.current; if (route && route.driveCoords) { const pos = posAtOffset(currentOffset(), route, driveCoordsMinRef.current, driveCoordsMaxRef.current); - if (pos && pos.some((coordinate, index) => coordinate != lastMapPosRef.current[index])) { + if (pos && pos.some((coordinate, index) => coordinate !== lastMapPosRef.current[index])) { lastMapPosRef.current = pos; markerSource.setData({ type: 'Point', @@ -249,6 +246,7 @@ const DriveMap = () => { }; // Initialize on mount - fetch coords and start animation + // biome-ignore lint/correctness/useExhaustiveDependencies: updateMarkerPos intentionally not in deps to avoid infinite RAF loop useEffect(() => { const route = currentRoute?.fullname || null; if (route) { @@ -262,9 +260,10 @@ const DriveMap = () => { cancelAnimationFrame(animationFrameId.current); } }; - }, []); + }, [currentRoute, dispatch]); // Handle route changes + // biome-ignore lint/correctness/useExhaustiveDependencies: setPath intentionally not in deps to avoid re-running on every render useEffect(() => { const route = currentRoute?.fullname || null; if (route) { @@ -272,7 +271,7 @@ const DriveMap = () => { } else { setPath([]); } - }, [currentRoute?.fullname]); + }, [currentRoute?.fullname, dispatch, currentRoute]); // Handle startTime changes useEffect(() => { @@ -282,6 +281,7 @@ const DriveMap = () => { }, [startTime]); // Handle driveCoords updates + // biome-ignore lint/correctness/useExhaustiveDependencies: populateMap intentionally not in deps to avoid re-running on every render useEffect(() => { if (currentRoute?.driveCoords) { shouldFlyToRef.current = false; @@ -290,7 +290,7 @@ const DriveMap = () => { setDriveCoordsMax(Math.max(...keys)); populateMap(currentRoute); } - }, [currentRoute?.driveCoords]); + }, [currentRoute?.driveCoords, currentRoute]); return (

diff --git a/src/components/DriveVideo/index.jsx b/src/components/DriveVideo/index.jsx index e53ed58a..426348df 100644 --- a/src/components/DriveVideo/index.jsx +++ b/src/components/DriveVideo/index.jsx @@ -1,18 +1,18 @@ /* eslint-disable camelcase */ -import React, { Component } from 'react'; -import { connect } from 'react-redux'; + + +import { video as Video } from '@commaai/api'; import { CircularProgress, Typography } from '@material-ui/core'; import debounce from 'debounce'; -import { selectCurrentRoute } from '../../selectors/route'; +import React, { Component } from 'react'; import ReactPlayer from 'react-player/file'; - -import { video as Video } from '@commaai/api'; - +import { connect } from 'react-redux'; import Colors from '../../colors'; import { ErrorOutline } from '../../icons'; +import { selectCurrentRoute } from '../../selectors/route'; import { currentOffset } from '../../timeline'; -import { seek, bufferVideo } from '../../timeline/playback'; -import { isIos, isFirefox } from '../../utils/browser.js'; +import { bufferVideo, seek } from '../../timeline/playback'; +import { isFirefox, isIos } from '../../utils/browser.js'; const VideoOverlay = ({ loading, error }) => { let content; diff --git a/src/components/DriveView/Media.jsx b/src/components/DriveView/Media.jsx index eaee1d19..fe36e47c 100644 --- a/src/components/DriveView/Media.jsx +++ b/src/components/DriveView/Media.jsx @@ -1,27 +1,24 @@ -import React, { Component } from 'react'; -import { connect } from 'react-redux'; -import * as Sentry from '@sentry/react'; - -import { withStyles, Divider, Typography, Menu, MenuItem, CircularProgress, Button, Popper, ListItem } from '@material-ui/core'; -import WarningIcon from '@material-ui/icons/Warning'; +import { drives as Drives } from '@commaai/api'; +import { Button, CircularProgress, Divider, ListItem, Menu, MenuItem, Popper, Typography, withStyles } from '@material-ui/core'; import ContentCopyIcon from '@material-ui/icons/ContentCopy'; import ShareIcon from '@material-ui/icons/Share'; - -import { drives as Drives } from '@commaai/api'; - +import WarningIcon from '@material-ui/icons/Warning'; +import * as Sentry from '@sentry/react'; +import { Component } from 'react'; +import { connect } from 'react-redux'; +import { updateRoute } from '../../actions'; +import { fetchEvents } from '../../actions/cached'; +import { doUpload, FILE_NAMES, fetchAthenaQueue, fetchFiles, fetchUploadUrls, setRouteViewed, updateFiles } from '../../actions/files'; +import Colors from '../../colors'; +import { InfoOutline } from '../../icons'; +import { bufferVideo } from '../../timeline/playback'; +import { deviceIsOnline, deviceOnCellular, getSegmentNumber } from '../../utils'; import DriveMap from '../DriveMap'; import DriveVideo from '../DriveVideo'; +import UploadQueue from '../Files/UploadQueue'; import ResizeHandler from '../ResizeHandler'; import TimeDisplay from '../TimeDisplay'; -import UploadQueue from '../Files/UploadQueue'; import SwitchLoading from '../utils/SwitchLoading'; -import { bufferVideo } from '../../timeline/playback'; -import Colors from '../../colors'; -import { InfoOutline } from '../../icons'; -import { deviceIsOnline, deviceOnCellular, getSegmentNumber } from '../../utils'; -import { updateRoute } from '../../actions'; -import { fetchEvents } from '../../actions/cached'; -import { setRouteViewed, fetchFiles, doUpload, fetchUploadUrls, fetchAthenaQueue, updateFiles, FILE_NAMES } from '../../actions/files'; const publicTooltip = 'Making a route public allows anyone with the route name or link to access it.'; const preservedTooltip = 'Preserving a route will prevent it from being deleted. You can preserve up to 10 routes, or 100 if you have comma prime.'; @@ -338,8 +335,8 @@ class Media extends Component { uploading[fileName] = { requested: true }; this.props.dispatch(updateFiles(uploading)); - let paths = []; - let url_promises = []; + const paths = []; + const url_promises = []; // request all possible file names for (const fn of FILE_NAMES[type]) { @@ -435,8 +432,6 @@ class Media extends Component { } downloadFile(file, type) { - const { currentRoute } = this.props; - window.location.href = file.url; } diff --git a/src/components/DriveView/NoDeviceUpsell.jsx b/src/components/DriveView/NoDeviceUpsell.jsx index c73246db..600cec2e 100644 --- a/src/components/DriveView/NoDeviceUpsell.jsx +++ b/src/components/DriveView/NoDeviceUpsell.jsx @@ -1,4 +1,4 @@ -import React from 'react'; + import AddDevice from '../Dashboard/AddDevice'; diff --git a/src/components/DriveView/index.jsx b/src/components/DriveView/index.jsx index 91f2942e..cc3a8f77 100644 --- a/src/components/DriveView/index.jsx +++ b/src/components/DriveView/index.jsx @@ -1,16 +1,12 @@ -import React, { Component } from 'react'; -import { connect } from 'react-redux'; -import dayjs from 'dayjs'; - import { IconButton, Typography } from '@material-ui/core'; - -import { navigate } from '../../navigation'; -import { selectRouteZoom, selectCurrentRoute } from '../../selectors/route'; +import dayjs from 'dayjs'; +import { Component } from 'react'; +import { connect } from 'react-redux'; import { ArrowBackBold, CloseBold } from '../../icons'; -import { filterRegularClick } from '../../utils'; - -import Media from './Media'; +import { navigate } from '../../navigation'; +import { selectCurrentRoute, selectRouteZoom } from '../../selectors/route'; import Timeline from '../Timeline'; +import Media from './Media'; class DriveView extends Component { constructor(props) { @@ -29,7 +25,7 @@ class DriveView extends Component { } render() { - const { dongleId, zoom, currentRoute, routes } = this.props; + const { zoom, currentRoute, routes } = this.props; const currentRouteBoundsSelected = zoom.start === 0 && zoom.end === currentRoute?.duration; const backButtonDisabled = currentRouteBoundsSelected; diff --git a/src/components/ErrorFallback.jsx b/src/components/ErrorFallback.jsx index c4e0f00b..afb7fcaf 100644 --- a/src/components/ErrorFallback.jsx +++ b/src/components/ErrorFallback.jsx @@ -1,4 +1,4 @@ -import React, { useEffect, useRef, useState } from 'react'; +import { useEffect, useRef, useState } from 'react'; import { Check, ContentCopy, Refresh } from '../icons'; diff --git a/src/components/Files/UploadQueue.jsx b/src/components/Files/UploadQueue.jsx index 85c501fa..83a70e00 100644 --- a/src/components/Files/UploadQueue.jsx +++ b/src/components/Files/UploadQueue.jsx @@ -1,16 +1,15 @@ -import React, { Component } from 'react'; -import { connect } from 'react-redux'; - -import { +import {Button, CircularProgress, + Divider, LinearProgress,Modal, Paper, Typography, withStyles, - Divider, Typography, CircularProgress, Button, Modal, Paper, LinearProgress, } from '@material-ui/core'; import HighlightOffIcon from '@material-ui/icons/HighlightOff'; import WarningIcon from '@material-ui/icons/Warning'; +import { Component } from 'react'; +import { connect } from 'react-redux'; -import { fetchUploadQueue, cancelUploads, cancelFetchUploadQueue, FILE_NAMES } from '../../actions/files'; -import { deviceIsOnline, deviceOnCellular, deviceVersionAtLeast } from '../../utils'; +import { cancelFetchUploadQueue, cancelUploads, FILE_NAMES, fetchUploadQueue } from '../../actions/files'; import Colors from '../../colors'; +import { deviceIsOnline, deviceOnCellular, deviceVersionAtLeast } from '../../utils'; import ResizeHandler from '../ResizeHandler'; const styles = (theme) => ({ @@ -165,6 +164,7 @@ class UploadQueue extends Component { if (deviceVersionAtLeast(device, '0.8.13')) { dispatch(cancelUploads(device.dongle_id, ids)); } else { + // biome-ignore lint/suspicious/useIterableCallbackReturn: dispatch intentionally returns an action, forEach usage is correct here ids.forEach((id) => dispatch(cancelUploads(device.dongle_id, id))); } diff --git a/src/components/IosPwaPopup/index.jsx b/src/components/IosPwaPopup/index.jsx index cbbc4bfb..8d009b42 100644 --- a/src/components/IosPwaPopup/index.jsx +++ b/src/components/IosPwaPopup/index.jsx @@ -1,10 +1,9 @@ -import React, { Component } from 'react'; -import { withRouter } from 'react-router'; -import localforage from 'localforage'; -import { withStyles, Typography } from '@material-ui/core'; -import { Clear } from '@material-ui/icons'; - import MyCommaAuth from '@commaai/my-comma-auth'; +import { Typography, withStyles } from '@material-ui/core'; +import { Clear } from '@material-ui/icons'; +import localforage from 'localforage'; +import { Component } from 'react'; +import { withRouter } from 'react-router'; import Colors from '../../colors'; import { IosShareIcon } from '../../icons'; @@ -69,7 +68,7 @@ class IosPwaPopup extends Component { let isHidden; try { isHidden = await localforage.getItem('hideIosPwaPopup'); - } catch (err) { + } catch (_err) { isHidden = true; } this.setState({ show: !isHidden }); @@ -103,7 +102,7 @@ class IosPwaPopup extends Component { hide() { try { localforage.setItem('hideIosPwaPopup', true); - } catch (err) { + } catch (_err) { // pass } this.setState({ show: false }); diff --git a/src/components/Navigation/index.jsx b/src/components/Navigation/index.jsx index 2f8db4dc..9c28d681 100644 --- a/src/components/Navigation/index.jsx +++ b/src/components/Navigation/index.jsx @@ -1,21 +1,20 @@ -import React, { Component } from 'react'; -import { connect } from 'react-redux'; -import * as Sentry from '@sentry/react'; -import ReactMapGL, { GeolocateControl, HTMLOverlay, Marker, Source, WebMercatorViewport, Layer } from 'react-map-gl'; -import { withStyles, Typography, Button } from '@material-ui/core'; +import { athena as Athena, devices as Devices } from '@commaai/api'; +import { Button, Typography, withStyles } from '@material-ui/core'; import { Clear } from '@material-ui/icons'; +import * as Sentry from '@sentry/react'; import dayjs from 'dayjs'; - -import { athena as Athena, devices as Devices } from '@commaai/api'; -import { navigate } from '../../navigation'; -import { DEFAULT_LOCATION, MAPBOX_STYLE, MAPBOX_TOKEN, networkPositioning, reverseLookup } from '../../utils/geocode'; +import React, { Component } from 'react'; +import ReactMapGL, { GeolocateControl, HTMLOverlay, Layer, Marker, Source, WebMercatorViewport } from 'react-map-gl'; +import { connect } from 'react-redux'; import Colors from '../../colors'; import { PinCarIcon } from '../../icons'; +import { navigate } from '../../navigation'; import { timeFromNow } from '../../utils'; +import { isIos } from '../../utils/browser.js'; +import { DEFAULT_LOCATION, MAPBOX_STYLE, MAPBOX_TOKEN, networkPositioning, reverseLookup } from '../../utils/geocode'; import ResizeHandler from '../ResizeHandler'; import VisibilityHandler from '../VisibilityHandler'; import * as Utils from './utils'; -import { isIos } from '../../utils/browser.js'; const styles = () => ({ mapContainer: { @@ -371,6 +370,7 @@ class Navigation extends Component { if (searchSelect) { bounds.push(this.itemLngLat(searchSelect, true)); } else if (search) { + // biome-ignore lint/suspicious/useIterableCallbackReturn: push intentionally returns array length, forEach usage is correct for side effects search.forEach((item) => bounds.push(this.itemLngLat(item, true))); } diff --git a/src/components/PWAIcon.jsx b/src/components/PWAIcon.jsx index c90a4062..2e620dd4 100644 --- a/src/components/PWAIcon.jsx +++ b/src/components/PWAIcon.jsx @@ -1,11 +1,10 @@ -import React, { useState } from 'react'; import { useRegisterSW } from 'virtual:pwa-register/react'; - import { CircularProgress, IconButton, Tooltip, } from '@material-ui/core'; +import { useState } from 'react'; import { CheckCircle, Download } from '../icons'; diff --git a/src/components/Prime/PrimeCheckout.jsx b/src/components/Prime/PrimeCheckout.jsx index 74b798e4..ae9f430a 100644 --- a/src/components/Prime/PrimeCheckout.jsx +++ b/src/components/Prime/PrimeCheckout.jsx @@ -1,18 +1,16 @@ -import React, { Component } from 'react'; -import { connect } from 'react-redux'; -import dayjs from 'dayjs'; -import * as Sentry from '@sentry/react'; -import { withStyles, Typography, IconButton, Button, CircularProgress } from '@material-ui/core'; -import KeyboardBackspaceIcon from '@material-ui/icons/KeyboardBackspace'; -import CheckIcon from '@material-ui/icons/Check'; - import { billing as Billing } from '@commaai/api'; - -import { deviceNamePretty } from '../../utils'; -import ResizeHandler from '../ResizeHandler'; +import { Button, CircularProgress, IconButton, Typography, withStyles } from '@material-ui/core'; +import CheckIcon from '@material-ui/icons/Check'; +import KeyboardBackspaceIcon from '@material-ui/icons/KeyboardBackspace'; +import * as Sentry from '@sentry/react'; +import dayjs from 'dayjs'; +import { Component } from 'react'; +import { connect } from 'react-redux'; import Colors from '../../colors'; -import { navigate } from '../../navigation'; import { ErrorOutline, InfoOutline } from '../../icons'; +import { navigate } from '../../navigation'; +import { deviceNamePretty } from '../../utils'; +import ResizeHandler from '../ResizeHandler'; const styles = () => ({ linkHighlight: { @@ -244,7 +242,7 @@ class PrimeCheckout extends Component { } async gotoCheckout() { - const { dispatch, dongleId, subscribeInfo } = this.props; + const { dongleId, subscribeInfo } = this.props; this.setState({ loadingCheckout: true }); try { const { selectedPlan: plan } = this.state; @@ -293,7 +291,7 @@ class PrimeCheckout extends Component { } render() { - const { classes, dispatch, device, subscribeInfo } = this.props; + const { classes, device, subscribeInfo } = this.props; const { windowWidth, windowHeight, error, loadingCheckout, selectedPlan } = this.state; let chargeText = null; diff --git a/src/components/Prime/PrimeManage.jsx b/src/components/Prime/PrimeManage.jsx index 8f86b6d5..61cd809a 100644 --- a/src/components/Prime/PrimeManage.jsx +++ b/src/components/Prime/PrimeManage.jsx @@ -1,19 +1,17 @@ -import React, { Component } from 'react'; -import { connect } from 'react-redux'; -import dayjs from 'dayjs'; -import * as Sentry from '@sentry/react'; - -import { withStyles, Typography, Button, Modal, Paper, IconButton, CircularProgress } from '@material-ui/core'; +import { billing as Billing } from '@commaai/api'; +import { Button, CircularProgress, IconButton, Modal, Paper, Typography, withStyles } from '@material-ui/core'; import KeyboardBackspaceIcon from '@material-ui/icons/KeyboardBackspace'; import PriorityHighIcon from '@material-ui/icons/PriorityHigh'; - -import { billing as Billing } from '@commaai/api'; -import { deviceNamePretty, deviceTypePretty } from '../../utils'; -import ResizeHandler from '../ResizeHandler'; +import * as Sentry from '@sentry/react'; +import dayjs from 'dayjs'; +import { Component } from 'react'; +import { connect } from 'react-redux'; +import { primeGetSubscription } from '../../actions'; import Colors from '../../colors'; import { ErrorOutline, InfoOutline } from '../../icons'; -import { primeGetSubscription } from '../../actions'; import { navigate } from '../../navigation'; +import { deviceNamePretty, deviceTypePretty } from '../../utils'; +import ResizeHandler from '../ResizeHandler'; const styles = (theme) => ({ linkHighlight: { @@ -210,9 +208,6 @@ class PrimeManage extends Component { } componentDidUpdate(prevProps, prevState) { - const { subscription } = this.props; - const { stripeStatus } = this.state; - if (!prevProps.stripeSuccess && this.props.stripeSuccess) { this.setState({ stripeStatus: { sessionId: this.props.stripeSuccess, loading: true, paid: null }, @@ -309,7 +304,7 @@ class PrimeManage extends Component { } render() { - const { dispatch, dongleId, subscription, classes, device } = this.props; + const { dongleId, subscription, classes, device } = this.props; const { windowWidth, stripeStatus } = this.state; const hasPrimeSub = subscription && subscription.user_id; diff --git a/src/components/Prime/index.jsx b/src/components/Prime/index.jsx index 795466d7..6ec1e01f 100644 --- a/src/components/Prime/index.jsx +++ b/src/components/Prime/index.jsx @@ -1,9 +1,7 @@ -import React from 'react'; -import { useSelector } from 'react-redux'; - import { Typography } from '@material-ui/core'; -import PrimeManage from './PrimeManage'; +import { useSelector } from 'react-redux'; import PrimeCheckout from './PrimeCheckout'; +import PrimeManage from './PrimeManage'; const Prime = () => { const device = useSelector((state) => state.device); diff --git a/src/components/ResizeHandler/ResizeHandler.test.js b/src/components/ResizeHandler/ResizeHandler.test.js index fbadfad2..4b56b8a5 100644 --- a/src/components/ResizeHandler/ResizeHandler.test.js +++ b/src/components/ResizeHandler/ResizeHandler.test.js @@ -1,9 +1,8 @@ /* eslint-env jest */ -import React from 'react'; -import { fireEvent, render, waitFor } from '@testing-library/react'; -import ResizeHandler from '.'; +import { fireEvent, render, waitFor } from '@testing-library/react'; import { asyncSleep } from '../../utils'; +import ResizeHandler from '.'; describe('resize handler', () => { it('registers, triggers and unregistered resize listener', async () => { diff --git a/src/components/ResizeHandler/index.js b/src/components/ResizeHandler/index.js index 6a8f939d..29bddf04 100644 --- a/src/components/ResizeHandler/index.js +++ b/src/components/ResizeHandler/index.js @@ -1,30 +1,31 @@ -import { useEffect } from 'react'; +import { useEffect, useRef } from 'react'; const ResizeHandler = (props) => { const { onResize } = props; + const resizeTimeoutRef = useRef(null); - let resizeTimeout; - const handleResize = () => { - if (resizeTimeout) { - window.clearTimeout(resizeTimeout); - } + // biome-ignore lint/correctness/useExhaustiveDependencies: onResize is passed as prop and may change, but we want to use latest version without re-subscribing + useEffect(() => { + const handleResize = () => { + if (resizeTimeoutRef.current) { + window.clearTimeout(resizeTimeoutRef.current); + } - resizeTimeout = window.setTimeout(() => { - onResize(window.innerWidth, window.innerHeight); - resizeTimeout = null; - }, 150); - }; + resizeTimeoutRef.current = window.setTimeout(() => { + onResize(window.innerWidth, window.innerHeight); + resizeTimeoutRef.current = null; + }, 150); + }; - useEffect(() => { window.addEventListener('resize', handleResize); return () => { window.removeEventListener('resize', handleResize); - if (resizeTimeout) { - window.clearTimeout(resizeTimeout); + if (resizeTimeoutRef.current) { + window.clearTimeout(resizeTimeoutRef.current); } }; - }, [onResize]); + }, []); return null; }; diff --git a/src/components/ScrollIntoView/index.jsx b/src/components/ScrollIntoView/index.jsx index dd20fb79..8996201c 100644 --- a/src/components/ScrollIntoView/index.jsx +++ b/src/components/ScrollIntoView/index.jsx @@ -1,4 +1,4 @@ -import React, { useEffect, useRef } from 'react'; +import { useEffect, useRef } from 'react'; const ScrollIntoView = ({ onInView, children }) => { const elementRef = useRef(null); diff --git a/src/components/TimeDisplay/index.jsx b/src/components/TimeDisplay/index.jsx index 27379759..bcf6c2b1 100644 --- a/src/components/TimeDisplay/index.jsx +++ b/src/components/TimeDisplay/index.jsx @@ -1,20 +1,19 @@ -import React, { useState, useEffect, useRef } from 'react'; -import { useSelector, useDispatch } from 'react-redux'; -import dayjs from 'dayjs'; - +import { Tooltip } from '@material-ui/core'; +import IconButton from '@material-ui/core/IconButton'; import { withStyles } from '@material-ui/core/styles'; import Typography from '@material-ui/core/Typography'; -import IconButton from '@material-ui/core/IconButton'; -import VolumeUp from '@material-ui/icons/VolumeUp'; import VolumeOff from '@material-ui/icons/VolumeOff'; -import { Tooltip } from '@material-ui/core'; +import VolumeUp from '@material-ui/icons/VolumeUp'; +import dayjs from 'dayjs'; +import { useEffect, useRef, useState } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; import { DownArrow, Forward10, Pause, PlayArrow, Replay10, UpArrow } from '../../icons'; +import { selectCurrentRoute, selectRouteZoom } from '../../selectors/route'; import { currentOffset } from '../../timeline'; -import { seek, play, pause } from '../../timeline/playback'; +import { pause, play, seek } from '../../timeline/playback'; import { getSegmentNumber } from '../../utils'; import { isIos } from '../../utils/browser.js'; -import { selectRouteZoom, selectCurrentRoute } from '../../selectors/route'; const timerSteps = [ 0.1, @@ -192,6 +191,7 @@ const TimeDisplay = ({ classes, isThin, onMuteToggle, isMuted, hasAudio }) => { }; // Initialize RAF loop on mount + // biome-ignore lint/correctness/useExhaustiveDependencies: updateTime intentionally not in deps to avoid infinite RAF loop useEffect(() => { animationFrameId.current = requestAnimationFrame(updateTime); return () => { diff --git a/src/components/TimeSelect/index.jsx b/src/components/TimeSelect/index.jsx index b3e298ff..6e18dca5 100644 --- a/src/components/TimeSelect/index.jsx +++ b/src/components/TimeSelect/index.jsx @@ -1,11 +1,9 @@ -import React, { useState, useEffect, useCallback } from 'react'; -import { useSelector, useDispatch } from 'react-redux'; -import dayjs from 'dayjs'; - import { Button, Divider, Modal, Paper, Typography, withStyles } from '@material-ui/core'; - -import Colors from '../../colors'; +import dayjs from 'dayjs'; +import { useCallback, useEffect, useState } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; import { selectTimeFilter } from '../../actions'; +import Colors from '../../colors'; const styles = (theme) => ({ modal: { @@ -96,8 +94,7 @@ const TimeSelect = (props) => { const endDate = dayjs(end || filter.end).format('YYYY-MM-DD'); return ( - <> - {
- ); }; diff --git a/src/components/Timeline/index.jsx b/src/components/Timeline/index.jsx index f01d2a4f..abdd5eb0 100644 --- a/src/components/Timeline/index.jsx +++ b/src/components/Timeline/index.jsx @@ -1,20 +1,19 @@ // timeline minimap // rapidly change high level timeline stuff // rapid seeking, etc -import React, { useState, useEffect, useRef } from 'react'; -import { useSelector, useDispatch } from 'react-redux'; + import { withStyles } from '@material-ui/core/styles'; import dayjs from 'dayjs'; - - -import Thumbnails from './thumbnails'; -import theme from '../../theme'; +import { useEffect, useRef, useState } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import Colors from '../../colors'; import { navigate } from '../../navigation'; import { selectRouteZoom } from '../../selectors/route'; -import Colors from '../../colors'; +import theme from '../../theme'; import { currentOffset } from '../../timeline'; import { seek } from '../../timeline/playback'; import { getSegmentNumber } from '../../utils'; +import Thumbnails from './thumbnails'; const styles = () => ({ base: { @@ -318,6 +317,7 @@ const Timeline = ({ classes, hasRuler, className, route, thumbnailsVisible, zoom }; // Initialize on mount - RAF loop + // biome-ignore lint/correctness/useExhaustiveDependencies: getOffset intentionally not in deps to avoid infinite RAF loop useEffect(() => { animationFrameId.current = requestAnimationFrame(getOffset); diff --git a/src/components/Timeline/thumbnails.jsx b/src/components/Timeline/thumbnails.jsx index fa5731c9..b1c866b2 100644 --- a/src/components/Timeline/thumbnails.jsx +++ b/src/components/Timeline/thumbnails.jsx @@ -1,4 +1,4 @@ -import React from 'react'; + import { getSegmentNumber } from '../../utils'; export default function Thumbnails(props) { diff --git a/src/components/Timeline/thumbnails.test.js b/src/components/Timeline/thumbnails.test.js index 57afa811..795de0d5 100644 --- a/src/components/Timeline/thumbnails.test.js +++ b/src/components/Timeline/thumbnails.test.js @@ -1,5 +1,5 @@ /* eslint-env jest */ -import React from 'react'; + import { render, screen } from '@testing-library/react'; import Thumbnails from './thumbnails'; diff --git a/src/components/VisibilityHandler/index.jsx b/src/components/VisibilityHandler/index.jsx index ca161607..857fa488 100644 --- a/src/components/VisibilityHandler/index.jsx +++ b/src/components/VisibilityHandler/index.jsx @@ -1,6 +1,6 @@ -import { useEffect, useRef, useCallback } from 'react'; -import { useSelector } from 'react-redux'; import debounce from 'debounce'; +import { useCallback, useEffect, useRef } from 'react'; +import { useSelector } from 'react-redux'; const VisibilityHandler = (props) => { const { onInit, onInterval, onVisible, minInterval, resetOnHidden, onDongleId } = props; diff --git a/src/components/anonymous.jsx b/src/components/anonymous.jsx index 32afee43..be3e3224 100644 --- a/src/components/anonymous.jsx +++ b/src/components/anonymous.jsx @@ -1,11 +1,11 @@ /* global AppleID */ -import React, { Component } from 'react'; -import { withRouter } from 'react-router'; -import { withStyles } from '@material-ui/core/styles'; -import Typography from '@material-ui/core/Typography'; import {config as AuthConfig, storage as AuthStorage} from '@commaai/my-comma-auth'; +import { withStyles } from '@material-ui/core/styles'; +import Typography from '@material-ui/core/Typography'; +import { Component } from 'react'; +import { withRouter } from 'react-router'; import Colors from '../colors'; import { AuthAppleIcon, AuthGithubIcon, AuthGoogleIcon, RightArrow } from '../icons'; @@ -124,7 +124,7 @@ class AnonymousLanding extends Component { render() { const { classes } = this.props; - const loginAsDemoUser = function() { + const loginAsDemoUser = () => { AuthStorage.setCommaAccessToken('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEwMzg5NTgwNzM1LCJuYmYiOjE3NDk1ODA3MzUsImlhdCI6MTc0OTU4MDczNSwiaWRlbnRpdHkiOiIwZGVjZGRjZmRmMjQxYTYwIn0.KsDzqJxgkYhAs4tCgrMJIdORyxO0CQNb0gHXIf8aUT0'); window.location = window.location.origin; }; diff --git a/src/components/explorer.jsx b/src/components/explorer.jsx index 46ca49aa..05cb7120 100644 --- a/src/components/explorer.jsx +++ b/src/components/explorer.jsx @@ -1,30 +1,25 @@ -import React, { Component } from 'react'; -import { connect } from 'react-redux'; +import { Button, CircularProgress, Divider, Modal, Paper, Typography, withStyles } from '@material-ui/core'; import localforage from 'localforage'; +import { Component } from 'react'; +import { connect } from 'react-redux'; import { withRouter } from 'react-router'; import { replace } from '../navigation'; - -import { withStyles, Button, CircularProgress, Divider, Modal, Paper, Typography } from '@material-ui/core'; import 'mapbox-gl/dist/mapbox-gl.css'; import { devices as Devices } from '@commaai/api'; - -import AppHeader from './AppHeader'; -import Dashboard from './Dashboard'; -import IosPwaPopup from './IosPwaPopup'; -import AppDrawer from './AppDrawer'; -import PullDownReload from './utils/PullDownReload'; - -import { selectDevice, updateDevice, checkLastRoutesData } from '../actions'; +import { checkLastRoutesData, selectDevice, updateDevice } from '../actions'; import init from '../actions/startup'; import Colors from '../colors'; -import { play, pause } from '../timeline/playback'; -import { verifyPairToken, pairErrorToMessage } from '../utils'; - -import ResizeHandler from './ResizeHandler'; - +import { pause, play } from '../timeline/playback'; +import { pairErrorToMessage, verifyPairToken } from '../utils'; +import AppDrawer from './AppDrawer'; +import AppHeader from './AppHeader'; +import Dashboard from './Dashboard'; import DriveView from './DriveView'; import NoDeviceUpsell from './DriveView/NoDeviceUpsell'; +import IosPwaPopup from './IosPwaPopup'; +import ResizeHandler from './ResizeHandler'; +import PullDownReload from './utils/PullDownReload'; const styles = (theme) => ({ window: { diff --git a/src/components/utils/InfoTooltip.jsx b/src/components/utils/InfoTooltip.jsx index 6139f7a4..265b2438 100644 --- a/src/components/utils/InfoTooltip.jsx +++ b/src/components/utils/InfoTooltip.jsx @@ -1,5 +1,5 @@ -import React, { Component } from 'react'; import { ClickAwayListener, Tooltip, Typography, withStyles } from '@material-ui/core'; +import { Component } from 'react'; import { InfoOutline } from '../../icons'; diff --git a/src/components/utils/PullDownReload.jsx b/src/components/utils/PullDownReload.jsx index 51015daf..5a782817 100644 --- a/src/components/utils/PullDownReload.jsx +++ b/src/components/utils/PullDownReload.jsx @@ -1,7 +1,6 @@ -import React, { Component } from 'react'; - import { withStyles } from '@material-ui/core'; import ReplayIcon from '@material-ui/icons/Replay'; +import React, { Component } from 'react'; import Colors from '../../colors'; import { isIos } from '../../utils/browser.js'; diff --git a/src/components/utils/SwitchLoading.jsx b/src/components/utils/SwitchLoading.jsx index 31a7b924..81e36f3d 100644 --- a/src/components/utils/SwitchLoading.jsx +++ b/src/components/utils/SwitchLoading.jsx @@ -1,6 +1,5 @@ -import React, { Component } from 'react'; - -import { withStyles, Switch, FormControlLabel, Popper, Typography } from '@material-ui/core'; +import { FormControlLabel, Popper, Switch, Typography, withStyles } from '@material-ui/core'; +import { Component } from 'react'; import Colors from '../../colors'; import { ErrorOutline } from '../../icons'; diff --git a/src/historySync.js b/src/historySync.js index f840ab86..e29d269b 100644 --- a/src/historySync.js +++ b/src/historySync.js @@ -1,7 +1,7 @@ -import { getDongleID, getZoom, getSegmentRange } from './url'; -import { selectDevice, pushTimelineRange } from './actions'; import { drives as Drives } from '@commaai/api'; +import { pushTimelineRange, selectDevice } from './actions'; import { replace } from './navigation'; +import { getDongleID, getSegmentRange, getZoom } from './url'; export function installHistorySync(store, history) { async function handle(location, action) { diff --git a/src/icons/index.jsx b/src/icons/index.jsx index 1dd0da70..cfd42b79 100644 --- a/src/icons/index.jsx +++ b/src/icons/index.jsx @@ -1,5 +1,5 @@ /* eslint-disable react/jsx-props-no-spreading */ -import React from 'react'; + import SvgIcon from '@material-ui/core/SvgIcon'; import AuthAppleIcon from './auth_apple.png'; diff --git a/src/index.jsx b/src/index.jsx index 198e534b..cf532f68 100644 --- a/src/index.jsx +++ b/src/index.jsx @@ -1,13 +1,12 @@ -import React from 'react'; -import ReactDOM from 'react-dom/client'; import { CssBaseline, MuiThemeProvider } from '@material-ui/core'; import * as Sentry from '@sentry/react'; +import ReactDOM from 'react-dom/client'; import './index.css'; import App from './App'; -import store from './store'; import { history } from './history'; import installHistorySync from './historySync'; +import store from './store'; import Theme from './theme'; if (window.SENTRY_ENV) { diff --git a/src/reducers/globalState.js b/src/reducers/globalState.js index ed402338..47e39aa5 100644 --- a/src/reducers/globalState.js +++ b/src/reducers/globalState.js @@ -1,6 +1,5 @@ import * as Types from '../actions/types'; import { emptyDevice } from '../utils'; -import { getSegmentRange } from '../url'; const eventsMap = {}; const locationMap = {}; diff --git a/src/store.js b/src/store.js index c198da57..ea664a1a 100644 --- a/src/store.js +++ b/src/store.js @@ -1,10 +1,9 @@ import * as Redux from 'redux'; import thunk from 'redux-thunk'; - -import rootReducer from './reducers'; import composeEnhancers from './devtools'; -import initialState from './initialState'; import { history } from './history'; +import initialState from './initialState'; +import rootReducer from './reducers'; const store = Redux.createStore( rootReducer, diff --git a/src/timeline/segments.test.js b/src/timeline/segments.test.js index edb58671..4f5c253b 100644 --- a/src/timeline/segments.test.js +++ b/src/timeline/segments.test.js @@ -1,6 +1,7 @@ /* eslint-env jest */ -import { hasRoutesData } from './segments'; + import { getSegmentNumber } from '../utils'; +import { hasRoutesData } from './segments'; export const SEGMENT_LENGTH = 1000 * 60; diff --git a/src/utils/geocode.js b/src/utils/geocode.js index e6d7492b..6dd75cb0 100644 --- a/src/utils/geocode.js +++ b/src/utils/geocode.js @@ -1,6 +1,5 @@ -import * as Sentry from '@sentry/react'; - import mbxGeocoding from '@mapbox/mapbox-sdk/services/geocoding'; +import * as Sentry from '@sentry/react'; export const DEFAULT_LOCATION = { latitude: 32.711483, From 6c1a54c50cb734ac55482d2e614dee00e3e2e8b3 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 2 Nov 2025 17:57:50 -0800 Subject: [PATCH 14/26] biome format! --- biome.json | 12 +- package.json | 2 + src/App.jsx | 16 +- src/__puppeteer__/demo.test.js | 6 +- src/__puppeteer__/drive.test.js | 10 +- src/__puppeteer__/routing.test.js | 6 +- src/actions/cached.js | 89 +++-- src/actions/files.js | 26 +- src/actions/index.js | 201 ++++++----- src/actions/index.test.js | 2 +- src/actions/types.js | 3 +- src/components/AppDrawer/index.jsx | 40 +-- src/components/AppHeader/AccountMenu.jsx | 27 +- src/components/AppHeader/index.jsx | 52 +-- src/components/Dashboard/AddDevice.jsx | 78 ++-- src/components/Dashboard/DeviceList.jsx | 93 +++-- .../Dashboard/DeviceSettingsModal.jsx | 175 ++++----- src/components/Dashboard/DriveList.jsx | 20 +- src/components/Dashboard/DriveListEmpty.jsx | 4 +- src/components/Dashboard/DriveListItem.jsx | 52 +-- .../Dashboard/DriveListItem.test.js | 26 +- src/components/Dashboard/index.jsx | 18 +- src/components/DeviceInfo/index.jsx | 189 ++++------ src/components/DriveMap/index.jsx | 21 +- src/components/DriveVideo/index.jsx | 28 +- src/components/DriveView/Media.jsx | 340 +++++++----------- src/components/DriveView/NoDeviceUpsell.jsx | 11 +- src/components/DriveView/index.jsx | 17 +- src/components/ErrorFallback.jsx | 49 ++- src/components/Files/UploadQueue.jsx | 141 ++++---- src/components/IosPwaPopup/index.jsx | 16 +- src/components/Navigation/index.jsx | 250 +++++++------ src/components/Navigation/utils.test.js | 7 +- src/components/PWAIcon.jsx | 23 +- src/components/Prime/PrimeCheckout.jsx | 166 ++++----- src/components/Prime/PrimeManage.jsx | 225 ++++++------ src/components/Prime/index.jsx | 6 +- src/components/ScrollIntoView/index.jsx | 12 +- src/components/TimeDisplay/index.jsx | 77 +--- src/components/TimeSelect/index.jsx | 78 ++-- src/components/Timeline/index.jsx | 59 ++- src/components/Timeline/thumbnails.jsx | 13 +- src/components/Timeline/thumbnails.test.js | 22 +- src/components/VisibilityHandler/index.jsx | 25 +- src/components/anonymous.jsx | 19 +- src/components/explorer.jsx | 51 +-- src/components/utils/InfoTooltip.jsx | 9 +- src/components/utils/SwitchLoading.jsx | 56 ++- src/devtools.js | 6 +- src/history.js | 1 - src/icons/index.jsx | 25 +- src/index.css | 6 +- src/index.jsx | 6 +- src/initialState.js | 8 +- src/navigation.js | 1 - src/reducers/globalState.js | 26 +- src/selectors/route.js | 2 +- src/store.js | 8 +- src/timeline/index.js | 4 +- src/timeline/playback.js | 5 +- src/timeline/playback.test.js | 12 +- src/timeline/segments.js | 5 +- src/timeline/segments.test.js | 177 +++++---- src/utils/geocode.test.js | 8 +- src/utils/index.js | 8 +- 65 files changed, 1339 insertions(+), 1837 deletions(-) diff --git a/biome.json b/biome.json index 585af7db..89d27603 100644 --- a/biome.json +++ b/biome.json @@ -9,7 +9,17 @@ "includes": ["**", "!!**/dist"] }, "formatter": { - "enabled": false + "enabled": true, + "indentStyle": "space", + "indentWidth": 2, + "lineWidth": 180 + }, + "javascript": { + "formatter": { + "quoteStyle": "single", + "trailingCommas": "all", + "semicolons": "always" + } }, "linter": { "enabled": true, diff --git a/package.json b/package.json index 9a96a001..30d3cc64 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,8 @@ "build:production": "vite build", "serve": "vite preview", "lint": "biome lint src", + "format": "biome format --write src", + "format:check": "biome format src", "test": "jest", "test-coverage": "jest --coverage", "test-puppeteer": "jest -c src/__puppeteer__/jest.config.js", diff --git a/src/App.jsx b/src/App.jsx index e1f4dbf5..3a32d1a9 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -117,26 +117,16 @@ class App extends Component { } const showLogin = !MyCommaAuth.isAuthenticated() && !getZoom(window.location.pathname) && !getSegmentRange(window.location.pathname); - let content = ( - - { showLogin ? this.anonymousRoutes() : this.authRoutes() } - - ); + let content = {showLogin ? this.anonymousRoutes() : this.authRoutes()}; // Use ErrorBoundary in production only if (import.meta.env.PROD) { - content = ( - }> - {content} - - ); + content = }>{content}; } return ( - - {content} - + {content} ); } diff --git a/src/__puppeteer__/demo.test.js b/src/__puppeteer__/demo.test.js index 7ff18420..3d1ca3c4 100644 --- a/src/__puppeteer__/demo.test.js +++ b/src/__puppeteer__/demo.test.js @@ -17,10 +17,6 @@ describe('demo mode', () => { await expect(page).toClick('.DriveEntry'); // Wait for video src to be set - await page.waitForFunction( - (video) => video.getAttribute('src')?.startsWith('blob:'), - {}, - await page.waitForSelector('video'), - ); + await page.waitForFunction((video) => video.getAttribute('src')?.startsWith('blob:'), {}, await page.waitForSelector('video')); }); }); diff --git a/src/__puppeteer__/drive.test.js b/src/__puppeteer__/drive.test.js index 3309bf64..ce53359b 100644 --- a/src/__puppeteer__/drive.test.js +++ b/src/__puppeteer__/drive.test.js @@ -34,10 +34,7 @@ describe('drive view', () => { expect(await backButton.evaluate((button) => button.hasAttribute('disabled'))).toBeFalsy(); - await Promise.all([ - page.waitForNavigation(), - backButton.click(), - ]); + await Promise.all([page.waitForNavigation(), backButton.click()]); expect(page.url().endsWith(DEMO_ROUTE_URL)).toBeTruthy(); }); @@ -50,10 +47,7 @@ describe('drive view', () => { expect(closeButton).toBeTruthy(); - await Promise.all([ - page.waitForNavigation(), - closeButton.click(), - ]); + await Promise.all([page.waitForNavigation(), closeButton.click()]); expect(page.url().endsWith(DEMO_DEVICE_URL)).toBeTruthy(); }); diff --git a/src/__puppeteer__/routing.test.js b/src/__puppeteer__/routing.test.js index 39e5b9db..e6de0b0d 100644 --- a/src/__puppeteer__/routing.test.js +++ b/src/__puppeteer__/routing.test.js @@ -27,10 +27,6 @@ describe('routing', () => { await goto('/1d3dc3e03047b0c7/000000dd--455f14369d', { timeout: 50000 }); // Wait for video src to be set - await page.waitForFunction( - (video) => video.getAttribute('src')?.startsWith('blob:'), - {}, - await page.waitForSelector('video'), - ); + await page.waitForFunction((video) => video.getAttribute('src')?.startsWith('blob:'), {}, await page.waitForSelector('video')); }, 80000); }); diff --git a/src/actions/cached.js b/src/actions/cached.js index 2ada313f..977b6c29 100644 --- a/src/actions/cached.js +++ b/src/actions/cached.js @@ -287,7 +287,9 @@ export function fetchEvents(route) { } let resolveEvents; - eventsRequests[route.fullname] = new Promise((resolve) => { resolveEvents = resolve; }); + eventsRequests[route.fullname] = new Promise((resolve) => { + resolveEvents = resolve; + }); if (!USE_LOCAL_EVENTS_DATA) { // in cache? @@ -306,18 +308,20 @@ export function fetchEvents(route) { let driveEvents; const promises = []; for (let i = 0; i <= route.maxqlog; i++) { - promises.push((async (j) => { - const url = new URL(`${route.url}/${j}/events.json`); - if (USE_LOCAL_EVENTS_DATA) { - url.hostname = 'chffrprivate.azureedge.local'; - } - const resp = await fetch(url, { method: 'GET' }); - if (!resp.ok) { - return []; - } - const events = await resp.json(); - return events; - })(i)); + promises.push( + (async (j) => { + const url = new URL(`${route.url}/${j}/events.json`); + if (USE_LOCAL_EVENTS_DATA) { + url.hostname = 'chffrprivate.azureedge.local'; + } + const resp = await fetch(url, { method: 'GET' }); + if (!resp.ok) { + return []; + } + const events = await resp.json(); + return events; + })(i), + ); } try { @@ -336,7 +340,7 @@ export function fetchEvents(route) { }); resolveEvents(driveEvents); if (!USE_LOCAL_EVENTS_DATA) { - setCacheItem('events', route.fullname, Math.floor(Date.now() / 1000) + (86400 * 14), driveEvents, route.maxqlog); + setCacheItem('events', route.fullname, Math.floor(Date.now() / 1000) + 86400 * 14, driveEvents, route.maxqlog); } }; } @@ -376,7 +380,9 @@ export function fetchCoord(route, coord, locationKey) { } let resolveLocation; - coordsRequests[cacheKey] = new Promise((resolve) => { resolveLocation = resolve; }); + coordsRequests[cacheKey] = new Promise((resolve) => { + resolveLocation = resolve; + }); // in cache? const cacheCoords = await getCacheItem('coords', coord); @@ -403,7 +409,7 @@ export function fetchCoord(route, coord, locationKey) { location, }); resolveLocation(location); - setCacheItem('coords', coord, Math.floor(Date.now() / 1000) + (86400 * 14), location); + setCacheItem('coords', coord, Math.floor(Date.now() / 1000) + 86400 * 14, location); }; } @@ -445,7 +451,9 @@ export function fetchDriveCoords(route) { } let resolveDriveCoords; - driveCoordsRequests[route.fullname] = new Promise((resolve) => { resolveDriveCoords = resolve; }); + driveCoordsRequests[route.fullname] = new Promise((resolve) => { + resolveDriveCoords = resolve; + }); if (!USE_LOCAL_COORDS_DATA) { // in cache? @@ -465,18 +473,20 @@ export function fetchDriveCoords(route) { const promises = []; for (let i = 0; i <= route.maxqlog; i++) { - promises.push((async (j) => { - const url = new URL(`${route.url}/${j}/coords.json`); - if (USE_LOCAL_COORDS_DATA) { - url.hostname = 'chffrprivate.azureedge.local'; - } - const resp = await fetch(url, { method: 'GET' }); - if (!resp.ok) { - return []; - } - const events = await resp.json(); - return events; - })(i)); + promises.push( + (async (j) => { + const url = new URL(`${route.url}/${j}/coords.json`); + if (USE_LOCAL_COORDS_DATA) { + url.hostname = 'chffrprivate.azureedge.local'; + } + const resp = await fetch(url, { method: 'GET' }); + if (!resp.ok) { + return []; + } + const events = await resp.json(); + return events; + })(i), + ); } let driveCoords; @@ -487,14 +497,17 @@ export function fetchDriveCoords(route) { return; } - driveCoords = driveCoords.reduce((prev, curr) => ({ - // biome-ignore lint/performance/noAccumulatingSpread: existing code pattern, refactoring would require testing to ensure behavior unchanged - ...prev, - ...curr.reduce((p, cs) => { - p[cs.t] = [cs.lng, cs.lat]; - return p; - }, {}), - }), {}); + driveCoords = driveCoords.reduce( + (prev, curr) => ({ + // biome-ignore lint/performance/noAccumulatingSpread: existing code pattern, refactoring would require testing to ensure behavior unchanged + ...prev, + ...curr.reduce((p, cs) => { + p[cs.t] = [cs.lng, cs.lat]; + return p; + }, {}), + }), + {}, + ); dispatch({ type: Types.ACTION_UPDATE_ROUTE, @@ -505,7 +518,7 @@ export function fetchDriveCoords(route) { }); resolveDriveCoords(driveCoords); if (!USE_LOCAL_COORDS_DATA) { - setCacheItem('driveCoords', route.fullname, Math.floor(Date.now() / 1000) + (86400 * 14), driveCoords, route.maxqlog); + setCacheItem('driveCoords', route.fullname, Math.floor(Date.now() / 1000) + 86400 * 14, driveCoords, route.maxqlog); } }; } diff --git a/src/actions/files.js b/src/actions/files.js index f4f1460e..ccdb4279 100644 --- a/src/actions/files.js +++ b/src/actions/files.js @@ -43,8 +43,7 @@ async function athenaCall(dongleId, payload, sentryFingerprint, retryCount = 0) await asyncSleep(2000); return athenaCall(dongleId, payload, sentryFingerprint, retryCount + 1); } - if (err.message && (err.message.indexOf('Timed out') === -1 - || err.message.indexOf('Device not registered') === -1)) { + if (err.message && (err.message.indexOf('Timed out') === -1 || err.message.indexOf('Device not registered') === -1)) { return { offline: true }; } console.error(err); @@ -107,10 +106,9 @@ export function fetchFiles(routeName, nocache = false) { const dongleId = routeName.split('|')[0]; const urlName = routeName.replace('|', '/'); - const urls = Object - .keys(FILE_NAMES) + const urls = Object.keys(FILE_NAMES) .filter((type) => files[type]) - .flatMap((type) => files[type].map((file) => ([type, file]))) + .flatMap((type) => files[type].map((file) => [type, file])) .reduce((state, [type, file]) => { const segmentNum = parseInt(file.split(urlName)[1].split('/')[1], 10); const fileName = `${routeName}--${segmentNum}/${type}`; @@ -226,11 +224,10 @@ export function doUpload(dongleId, paths, urls) { jsonrpc: '2.0', method: 'uploadFilesToUrls', params: { files_data: filesData }, - expiry: Math.floor(Date.now() / 1000) + (86400 * 7), + expiry: Math.floor(Date.now() / 1000) + 86400 * 7, }; const resp = await athenaCall(dongleId, payload, 'action_files_athena_uploads'); - if (resp && resp.error && resp.error.code === -32000 - && resp.error.data.message === 'too many values to unpack (expected 3)') { + if (resp && resp.error && resp.error.code === -32000 && resp.error.data.message === 'too many values to unpack (expected 3)') { loopedUploads = true; } else if (!resp || resp.error) { const newUploading = paths.reduce((state, path) => { @@ -261,12 +258,11 @@ export function doUpload(dongleId, paths, urls) { } if (failedFiltered) { - const uploading = failedFiltered - .reduce((state, path) => { - const fn = pathToFileName(dongleId, path); - state[fn] = { notFound: true }; - return state; - }, {}); + const uploading = failedFiltered.reduce((state, path) => { + const fn = pathToFileName(dongleId, path); + state[fn] = { notFound: true }; + return state; + }, {}); dispatch(updateFiles(uploading)); } dispatch(fetchUploadQueue(dongleId)); @@ -280,7 +276,7 @@ export function doUpload(dongleId, paths, urls) { jsonrpc: '2.0', method: 'uploadFileToUrl', params: [paths[i], urls[i], { 'x-ms-blob-type': 'BlockBlob' }], - expiry: Math.floor(Date.now() / 1000) + (86400 * 7), + expiry: Math.floor(Date.now() / 1000) + 86400 * 7, }; // eslint-disable-next-line no-await-in-loop const resp = await athenaCall(dongleId, payload, 'files_actions_athena_upload'); diff --git a/src/actions/index.js b/src/actions/index.js index 505233f4..9ed835ff 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -4,13 +4,13 @@ import * as Sentry from '@sentry/react'; import { navigate } from '../navigation'; import { selectSegmentRange } from '../selectors/route'; import { resetPlayback, selectLoop } from '../timeline/playback'; -import {hasRoutesData } from '../timeline/segments'; +import { hasRoutesData } from '../timeline/segments'; import { deviceVersionAtLeast, getDeviceFromState } from '../utils'; import * as Types from './types'; let routesRequest = null; let routesRequestPromise = null; -const LIMIT_INCREMENT = 5 +const LIMIT_INCREMENT = 5; const FIVE_YEARS = 1000 * 60 * 60 * 24 * 365 * 5; export function checkRoutesData() { @@ -45,89 +45,89 @@ export function checkRoutesData() { }; } - routesRequestPromise = routesRequest.req.then((routesData) => { - state = getState(); - const currentRange = state.filter; - if (currentRange.start !== fetchRange.start - || currentRange.end !== fetchRange.end - || state.dongleId !== dongleId) { - routesRequest = null; - dispatch(checkRoutesData()); - return; - } - if (routesData && routesData.length === 0 - && !MyCommaAuth.isAuthenticated()) { - window.location = `/?r=${encodeURI(window.location.pathname)}`; // redirect to login - return; - } - - const routes = routesData.map((r) => { - let startTime = r.segment_start_times[0]; - let endTime = r.segment_end_times[r.segment_end_times.length - 1]; - - // TODO: these will all be relative times soon - // fix segment boundary times for routes that have the wrong time at the start - if ((Math.abs(r.start_time_utc_millis - startTime) > 24 * 60 * 60 * 1000) - && (Math.abs(r.end_time_utc_millis - endTime) < 10 * 1000)) { - startTime = r.start_time_utc_millis; - endTime = r.end_time_utc_millis; - r.segment_start_times = r.segment_numbers.map((x) => startTime + (x * 60 * 1000)); - r.segment_end_times = r.segment_numbers.map((x) => Math.min(startTime + ((x + 1) * 60 * 1000), endTime)); + routesRequestPromise = routesRequest.req + .then((routesData) => { + state = getState(); + const currentRange = state.filter; + if (currentRange.start !== fetchRange.start || currentRange.end !== fetchRange.end || state.dongleId !== dongleId) { + routesRequest = null; + dispatch(checkRoutesData()); + return; } - // TODO: backwards compatiblity, remove later - if (r.distance == null && r.length != null) { - r.distance = r.length; + if (routesData && routesData.length === 0 && !MyCommaAuth.isAuthenticated()) { + window.location = `/?r=${encodeURI(window.location.pathname)}`; // redirect to login + return; } - return { - ...r, - url: r.url.replace('chffrprivate.blob.core.windows.net', 'chffrprivate.azureedge.net'), - log_id: r.fullname.split('|')[1], - duration: endTime - startTime, - start_time_utc_millis: startTime, - end_time_utc_millis: endTime, - // TODO: get this from the API, this isn't correct for segments with a time jump - segment_durations: r.segment_start_times.map((x, i) => r.segment_end_times[i] - x), - }; - }).sort((a, b) => { - return b.create_time - a.create_time; - }); - dispatch({ - type: Types.ACTION_ROUTES_METADATA, - dongleId, - start: fetchRange.start, - end: fetchRange.end, - routes, - }); + const routes = routesData + .map((r) => { + let startTime = r.segment_start_times[0]; + let endTime = r.segment_end_times[r.segment_end_times.length - 1]; + + // TODO: these will all be relative times soon + // fix segment boundary times for routes that have the wrong time at the start + if (Math.abs(r.start_time_utc_millis - startTime) > 24 * 60 * 60 * 1000 && Math.abs(r.end_time_utc_millis - endTime) < 10 * 1000) { + startTime = r.start_time_utc_millis; + endTime = r.end_time_utc_millis; + r.segment_start_times = r.segment_numbers.map((x) => startTime + x * 60 * 1000); + r.segment_end_times = r.segment_numbers.map((x) => Math.min(startTime + (x + 1) * 60 * 1000, endTime)); + } + // TODO: backwards compatiblity, remove later + if (r.distance == null && r.length != null) { + r.distance = r.length; + } + return { + ...r, + url: r.url.replace('chffrprivate.blob.core.windows.net', 'chffrprivate.azureedge.net'), + log_id: r.fullname.split('|')[1], + duration: endTime - startTime, + start_time_utc_millis: startTime, + end_time_utc_millis: endTime, + // TODO: get this from the API, this isn't correct for segments with a time jump + segment_durations: r.segment_start_times.map((x, i) => r.segment_end_times[i] - x), + }; + }) + .sort((a, b) => { + return b.create_time - a.create_time; + }); - routesRequest = null; + dispatch({ + type: Types.ACTION_ROUTES_METADATA, + dongleId, + start: fetchRange.start, + end: fetchRange.end, + routes, + }); - return routes - }).catch((err) => { - console.error('Failure fetching routes metadata', err); - Sentry.captureException(err, { fingerprint: 'timeline_fetch_routes' }); - routesRequest = null; - }); + routesRequest = null; + + return routes; + }) + .catch((err) => { + console.error('Failure fetching routes metadata', err); + Sentry.captureException(err, { fingerprint: 'timeline_fetch_routes' }); + routesRequest = null; + }); - return routesRequestPromise + return routesRequestPromise; }; } export function checkLastRoutesData() { return (dispatch, getState) => { - const limit = getState().limit - const routes = getState().routes + const limit = getState().limit; + const routes = getState().routes; // if current routes are fewer than limit, that means the last fetch already fetched all the routes if (routes && routes.length < limit) { - return + return; } - console.log(`fetching ${limit +LIMIT_INCREMENT } routes`) + console.log(`fetching ${limit + LIMIT_INCREMENT} routes`); dispatch({ type: Types.ACTION_UPDATE_ROUTE_LIMIT, limit: limit + LIMIT_INCREMENT, - }) + }); const d = new Date(); const end = d.getTime(); @@ -158,14 +158,20 @@ export function urlForState(dongleId, log_id, start, end) { } function _updateTimeline(state, dispatch, log_id, start, end, allowPathChange) { - if (!state.loop || !state.loop.startTime || !state.loop.duration || state.loop.startTime < start - || state.loop.startTime + state.loop.duration > end || state.loop.duration < end - start) { + if ( + !state.loop || + !state.loop.startTime || + !state.loop.duration || + state.loop.startTime < start || + state.loop.startTime + state.loop.duration > end || + state.loop.duration < end - start + ) { dispatch(resetPlayback()); dispatch(selectLoop(start, end)); } if (allowPathChange) { - const desiredPath = urlForState(state.dongleId, log_id, Math.floor(start/1000), Math.floor(end/1000)); + const desiredPath = urlForState(state.dongleId, log_id, Math.floor(start / 1000), Math.floor(end / 1000)); if (window.location.pathname !== desiredPath) { navigate(desiredPath); } @@ -185,7 +191,7 @@ export function pushTimelineRange(log_id, start, end, allowPathChange = true) { return (dispatch, getState) => { const state = getState(); if (allowPathChange && state.dongleId) { - const desiredPath = urlForState(state.dongleId, log_id, Math.floor((start||0)/1000), Math.floor((end||0)/1000)); + const desiredPath = urlForState(state.dongleId, log_id, Math.floor((start || 0) / 1000), Math.floor((end || 0) / 1000)); if (window.location.pathname !== desiredPath) { navigate(desiredPath); } @@ -198,7 +204,6 @@ export function pushTimelineRange(log_id, start, end, allowPathChange = true) { }; } - export function primeGetSubscription(dongleId, subscription) { return { type: Types.ACTION_PRIME_SUBSCRIPTION, @@ -220,23 +225,27 @@ export function primeFetchSubscription(dongleId, device, profile) { if (device && (device.is_owner || profile.superuser)) { if (device.prime) { - Billing.getSubscription(dongleId).then((subscription) => { - dispatch(primeGetSubscription(dongleId, subscription)); - }).catch((err) => { - console.error(err); - Sentry.captureException(err, { fingerprint: 'actions_fetch_subscription' }); - }); + Billing.getSubscription(dongleId) + .then((subscription) => { + dispatch(primeGetSubscription(dongleId, subscription)); + }) + .catch((err) => { + console.error(err); + Sentry.captureException(err, { fingerprint: 'actions_fetch_subscription' }); + }); } else { - Billing.getSubscribeInfo(dongleId).then((subscribeInfo) => { - dispatch({ - type: Types.ACTION_PRIME_SUBSCRIBE_INFO, - dongleId, - subscribeInfo, + Billing.getSubscribeInfo(dongleId) + .then((subscribeInfo) => { + dispatch({ + type: Types.ACTION_PRIME_SUBSCRIBE_INFO, + dongleId, + subscribeInfo, + }); + }) + .catch((err) => { + console.error(err); + Sentry.captureException(err, { fingerprint: 'actions_fetch_subscribe_info' }); }); - }).catch((err) => { - console.error(err); - Sentry.captureException(err, { fingerprint: 'actions_fetch_subscribe_info' }); - }); } } }; @@ -244,14 +253,16 @@ export function primeFetchSubscription(dongleId, device, profile) { export function fetchDeviceOnline(dongleId) { return (dispatch) => { - Devices.fetchDevice(dongleId).then((resp) => { - dispatch({ - type: Types.ACTION_UPDATE_DEVICE_ONLINE, - dongleId, - last_athena_ping: resp.last_athena_ping, - fetched_at: Math.floor(Date.now() / 1000), - }); - }).catch(console.log); + Devices.fetchDevice(dongleId) + .then((resp) => { + dispatch({ + type: Types.ACTION_UPDATE_DEVICE_ONLINE, + dongleId, + last_athena_ping: resp.last_athena_ping, + fetched_at: Math.floor(Date.now() / 1000), + }); + }) + .catch(console.log); }; } @@ -402,7 +413,7 @@ export function selectTimeFilter(start, end) { dispatch({ type: Types.ACTION_UPDATE_ROUTE_LIMIT, limit: undefined, - }) + }); dispatch(checkRoutesData()); }; diff --git a/src/actions/index.test.js b/src/actions/index.test.js index fb242bf8..e945932e 100644 --- a/src/actions/index.test.js +++ b/src/actions/index.test.js @@ -11,7 +11,7 @@ describe('timeline actions', () => { it('should push history state when editing zoom', () => { const dispatch = jest.fn(); const getState = jest.fn(); - const actionThunk = pushTimelineRange("log_id", 123, 1234); + const actionThunk = pushTimelineRange('log_id', 123, 1234); getState.mockImplementationOnce(() => ({ dongleId: 'statedongle', diff --git a/src/actions/types.js b/src/actions/types.js index cfa917ca..4453a770 100644 --- a/src/actions/types.js +++ b/src/actions/types.js @@ -1,11 +1,10 @@ - // init export const ACTION_STARTUP_DATA = 'ACTION_STARTUP_DATA'; // global state management export const ACTION_SELECT_DEVICE = 'ACTION_SELECT_DEVICE'; export const ACTION_SELECT_TIME_FILTER = 'ACTION_SELECT_TIME_FILTER'; -export const ACTION_UPDATE_ROUTE_LIMIT = 'ACTION_UPDATE_ROUTE_LIMIT' +export const ACTION_UPDATE_ROUTE_LIMIT = 'ACTION_UPDATE_ROUTE_LIMIT'; export const ACTION_UPDATE_DEVICES = 'ACTION_UPDATE_DEVICES'; export const ACTION_UPDATE_DEVICE = 'ACTION_UPDATE_DEVICE'; export const ACTION_UPDATE_ROUTE = 'ACTION_UPDATE_ROUTE'; diff --git a/src/components/AppDrawer/index.jsx b/src/components/AppDrawer/index.jsx index 98fcfba9..dc6caf0b 100644 --- a/src/components/AppDrawer/index.jsx +++ b/src/components/AppDrawer/index.jsx @@ -7,9 +7,7 @@ import DeviceList from '../Dashboard/DeviceList'; const listener = (ev) => ev.stopPropagation(); -const AppDrawer = ({ - isPermanent, drawerIsOpen, handleDrawerStateChanged, width, -}) => { +const AppDrawer = ({ isPermanent, drawerIsOpen, handleDrawerStateChanged, width }) => { const dispatch = useDispatch(); const selectedDongleId = useSelector((state) => state.dongleId); const contentRef = useRef(null); @@ -26,30 +24,24 @@ const AppDrawer = ({ handleDrawerStateChanged(false); }, [handleDrawerStateChanged]); - const handleDeviceSelected = useCallback((dongleId) => { - dispatch(selectDevice(dongleId)); - toggleDrawerOff(); - }, [dispatch, toggleDrawerOff]); + const handleDeviceSelected = useCallback( + (dongleId) => { + dispatch(selectDevice(dongleId)); + toggleDrawerOff(); + }, + [dispatch, toggleDrawerOff], + ); return ( - +
- {!isPermanent - && ( - - comma - connect - - )} - + {!isPermanent && ( + + comma + connect + + )} +
); diff --git a/src/components/AppHeader/AccountMenu.jsx b/src/components/AppHeader/AccountMenu.jsx index fe652ea5..9073b596 100644 --- a/src/components/AppHeader/AccountMenu.jsx +++ b/src/components/AppHeader/AccountMenu.jsx @@ -1,10 +1,5 @@ import MyCommaAuth from '@commaai/my-comma-auth'; -import { - Divider, - ListItem, - Menu, - MenuItem, -} from '@material-ui/core'; +import { Divider, ListItem, Menu, MenuItem } from '@material-ui/core'; import dayjs from 'dayjs'; import { useCallback, useMemo } from 'react'; @@ -23,7 +18,11 @@ const Version = () => { if (sha) { const commitUrl = `https://github.com/commaai/connect/commit/${sha}`; - content.push(
{sha.substring(0, 7)}); + content.push( + + {sha.substring(0, 7)} + , + ); if (timestamp) { const buildDate = dayjs(timestamp).fromNow(); @@ -33,7 +32,7 @@ const Version = () => { content.push('dev'); } - return {content} + return {content}; }; const AccountMenu = ({ profile, open, anchorEl, onClose, ...rest }) => { @@ -59,18 +58,10 @@ const AccountMenu = ({ profile, open, anchorEl, onClose, ...rest }) => { {version} - + Manage Account - + Log out diff --git a/src/components/AppHeader/index.jsx b/src/components/AppHeader/index.jsx index 67317ad4..ab6b5813 100644 --- a/src/components/AppHeader/index.jsx +++ b/src/components/AppHeader/index.jsx @@ -53,10 +53,7 @@ const styles = () => ({ }, }); -const AppHeader = ({ - classes, drawerIsOpen, viewingRoute, showDrawerButton, - forwardRef, handleDrawerStateChanged, -}) => { +const AppHeader = ({ classes, drawerIsOpen, viewingRoute, showDrawerButton, forwardRef, handleDrawerStateChanged }) => { const dispatch = useDispatch(); const dongleId = useSelector((state) => state.dongleId); const profile = useSelector((state) => state.profile); @@ -86,52 +83,29 @@ const AppHeader = ({ - {Boolean(MyCommaAuth.isAuthenticated() && profile) && ( - - )} + {Boolean(MyCommaAuth.isAuthenticated() && profile) && } ); }; diff --git a/src/components/Dashboard/AddDevice.jsx b/src/components/Dashboard/AddDevice.jsx index 712b8f4d..857a88a1 100644 --- a/src/components/Dashboard/AddDevice.jsx +++ b/src/components/Dashboard/AddDevice.jsx @@ -62,7 +62,7 @@ const styles = (theme) => ({ }, videoContainerOverlay: { '&::before': { - content: '\'\'', + content: "''", position: 'absolute', backgroundColor: 'rgba(0, 0, 0, 0.8)', top: -1, @@ -145,8 +145,8 @@ class AddDevice extends Component { if (canvasWidth !== width || canvasHeight !== height) { this.setState({ canvasWidth: width, canvasHeight: height }); const size = Math.min(width, height); - const x = (width - size) / 2 + (size / 6); - const y = (height - size) / 2 + (size / 6); + const x = (width - size) / 2 + size / 6; + const y = (height - size) / 2 + size / 6; const rect = size * (2 / 3); const stroke = size / 6; @@ -297,7 +297,8 @@ class AddDevice extends Component { const resp = await Devices.pilotPair(pairToken); if (resp.dongle_id) { const device = await Devices.fetchDevice(resp.dongle_id); - if (devices.length > 0) { // state change from no device to a device requires reload. + if (devices.length > 0) { + // state change from no device to a device requires reload. dispatch(updateDevice(device)); } this.setState({ pairLoading: false, pairDongleId: resp.dongle_id, pairError: null }); @@ -319,63 +320,54 @@ class AddDevice extends Component { const { classes, buttonText, buttonStyle, buttonIcon } = this.props; const { modalOpen, hasCamera, pairLoading, pairDongleId, pairError } = this.state; - const videoContainerOverlay = (pairLoading || pairDongleId || pairError) ? classes.videoContainerOverlay : ''; + const videoContainerOverlay = pairLoading || pairDongleId || pairError ? classes.videoContainerOverlay : ''; return ( <> - - - -
+ + +
Pair device - - scan QR code - + scan QR code
- - { hasCamera === false - ? ( - <> - - Camera not found, please enable camera access. - - - You can also scan the QR code on your comma device using any other QR code - reader application. - - - ) - : ( -
- -
- { pairLoading && } - { pairError && ( + + {hasCamera === false ? ( + <> + Camera not found, please enable camera access. + You can also scan the QR code on your comma device using any other QR code reader application. + + ) : ( +
+ +
+ {pairLoading && } + {pairError && ( <> - { pairError } - - ) } - { pairDongleId && ( + )} + {pairDongleId && ( <> {'Successfully paired device '} - { pairDongleId } + {pairDongleId} - - ) } -
-
- )} +
+ )} diff --git a/src/components/Dashboard/DeviceList.jsx b/src/components/Dashboard/DeviceList.jsx index 77493cc8..e6c1f8c5 100644 --- a/src/components/Dashboard/DeviceList.jsx +++ b/src/components/Dashboard/DeviceList.jsx @@ -113,40 +113,36 @@ const DeviceList = (props) => { } }, [dispatch]); - const renderDevice = useCallback((device) => { - const isSelectedCls = (selectedDevice === device.dongle_id) ? 'isSelected' : ''; - const offlineCls = !deviceIsOnline(device) ? classes.deviceOffline : ''; - return ( - handleDeviceSelected(device.dongle_id)) } - href={ `/${device.dongle_id}` } - > -
-
 
-
- { (device.is_owner || (profile && profile.superuser)) - && ( - handleOpenedSettingsModal(device.dongle_id, ev) } - > - - + {(device.is_owner || (profile && profile.superuser)) && ( + handleOpenedSettingsModal(device.dongle_id, ev)}> + + )} - - ); - }, [classes, handleDeviceSelected, profile, selectedDevice, handleOpenedSettingsModal]); + + ); + }, + [classes, handleDeviceSelected, profile, selectedDevice, handleOpenedSettingsModal], + ); if (devices === null) { return null; @@ -156,15 +152,19 @@ const DeviceList = (props) => { const dongleId = selectedDevice; const found = devicesList.some((d) => d.dongle_id === dongleId); if (!found && device && dongleId === device.dongle_id) { - devicesList = [{ - ...device, - alias: emptyDevice.alias, - }].concat(devicesList); + devicesList = [ + { + ...device, + alias: emptyDevice.alias, + }, + ].concat(devicesList); } else if (!found && dongleId) { - devicesList = [{ - ...emptyDevice, - dongle_id: dongleId, - }].concat(devicesList); + devicesList = [ + { + ...emptyDevice, + dongle_id: dongleId, + }, + ].concat(devicesList); } const addButtonStyle = { @@ -178,11 +178,8 @@ const DeviceList = (props) => { return ( <> - -
+ +
{devicesList.map(renderDevice)} {MyCommaAuth.isAuthenticated() && (
@@ -190,11 +187,7 @@ const DeviceList = (props) => {
)}
- + ); }; diff --git a/src/components/Dashboard/DeviceSettingsModal.jsx b/src/components/Dashboard/DeviceSettingsModal.jsx index 3742505a..70791195 100644 --- a/src/components/Dashboard/DeviceSettingsModal.jsx +++ b/src/components/Dashboard/DeviceSettingsModal.jsx @@ -1,15 +1,5 @@ import { devices as Devices } from '@commaai/api'; -import { - Button, - CircularProgress, - Divider, - IconButton, - Modal, - Paper, - TextField, - Typography, - withStyles, -} from '@material-ui/core'; +import { Button, CircularProgress, Divider, IconButton, Modal, Paper, TextField, Typography, withStyles } from '@material-ui/core'; import CheckIcon from '@material-ui/icons/Check'; import SaveIcon from '@material-ui/icons/Save'; import ShareIcon from '@material-ui/icons/Share'; @@ -282,164 +272,119 @@ class DeviceSettingsModal extends Component { return ( <> - + -
- - Device settings - - - { device.dongle_id } - +
+ Device settings + {device.dongle_id}
- -
-
- { this.state.error && ( -
- { this.state.error } -
- ) } + {this.state.error && ( +
+ {this.state.error} +
+ )}
this.callOnEnter(this.setDeviceAlias, ev) } + onKeyPress={(ev) => this.callOnEnter(this.setDeviceAlias, ev)} /> - { (this.props.device.alias !== this.state.deviceAlias || this.state.hasSavedAlias) - && ( -
- - { this.state.hasSavedAlias ? : } - - {this.state.loadingDeviceAlias && } -
+ {(this.props.device.alias !== this.state.deviceAlias || this.state.hasSavedAlias) && ( +
+ + {this.state.hasSavedAlias ? : } + + {this.state.loadingDeviceAlias && } +
)}
this.callOnEnter(this.shareDevice, ev) } + onKeyPress={(ev) => this.callOnEnter(this.shareDevice, ev)} helperText="give another user read access to this device" /> - { (this.state.shareEmail.length > 0 || this.state.hasShared) - && ( -
- - { this.state.hasShared ? : } - - {this.state.loadingDeviceShare && } -
+ {(this.state.shareEmail.length > 0 || this.state.hasShared) && ( +
+ + {this.state.hasShared ? : } + + {this.state.loadingDeviceShare && } +
)}
-
- - -
- - Unpair device - - - { device.dongle_id } - + + +
+ Unpair device + {device.dongle_id}
- { this.state.unpairError - && ( -
- - { this.state.unpairError } -
+ {this.state.unpairError && ( +
+ + {this.state.unpairError} +
)} - { this.props.device.prime - && ( -
- - Unpairing will also cancel the comma prime subscription for this device. -
+ {this.props.device.prime && ( +
+ + Unpairing will also cancel the comma prime subscription for this device. +
)} -
- - { this.state.unpaired - ? Unpaired - : ( - - )} + {this.state.unpaired ? ( + Unpaired + ) : ( + + )}
- this.setState({ uploadModal: false }) } - device={ device } - /> + this.setState({ uploadModal: false })} device={device} /> ); } } const stateToProps = (state, ownProps) => { - const device = state.devices.find((d) => d.dongle_id === ownProps.dongleId) - || ((state.device && state.device.dongle_id === ownProps.dongleId) ? state.device : null); + const device = state.devices.find((d) => d.dongle_id === ownProps.dongleId) || (state.device && state.device.dongle_id === ownProps.dongleId ? state.device : null); return { subscription: state.subscription, device, diff --git a/src/components/Dashboard/DriveList.jsx b/src/components/Dashboard/DriveList.jsx index 605e278b..da0ff464 100644 --- a/src/components/Dashboard/DriveList.jsx +++ b/src/components/Dashboard/DriveList.jsx @@ -2,7 +2,7 @@ import { Typography, withStyles } from '@material-ui/core'; import { useDispatch, useSelector } from 'react-redux'; import { checkLastRoutesData, checkRoutesData } from '../../actions'; -import ScrollIntoView from '../ScrollIntoView' +import ScrollIntoView from '../ScrollIntoView'; import VisibilityHandler from '../VisibilityHandler'; import DriveListEmpty from './DriveListEmpty'; import DriveListItem from './DriveListItem'; @@ -44,22 +44,24 @@ const DriveList = (props) => { // we clean up routes during data fetching, fallback to using lastRoutes to display current data const displayRoutes = routes || lastRoutes; - if (displayRoutes && displayRoutes.length){ + if (displayRoutes && displayRoutes.length) { // sort routes by start_time_utc_millis with the latest drive first // Workaround upstream sorting issue for now // possibly from https://github.com/commaai/connect/issues/451 displayRoutes.sort((a, b) => b.start_time_utc_millis - a.start_time_utc_millis); - const routesSize = displayRoutes.length + const routesSize = displayRoutes.length; content = (
{displayRoutes.map((drive, index) => { - // when the last item is in view, we fetch the next routes - return (index === routesSize - 1 ? - dispatch(checkLastRoutesData())}> - - : - ) + // when the last item is in view, we fetch the next routes + return index === routesSize - 1 ? ( + dispatch(checkLastRoutesData())}> + + + ) : ( + + ); })}
); diff --git a/src/components/Dashboard/DriveListEmpty.jsx b/src/components/Dashboard/DriveListEmpty.jsx index b49ff29c..991e4a26 100644 --- a/src/components/Dashboard/DriveListEmpty.jsx +++ b/src/components/Dashboard/DriveListEmpty.jsx @@ -16,9 +16,7 @@ const DriveListEmpty = (props) => { if (device && routes === null) { zeroRidesEle = Loading...; } else if (routes?.length === 0) { - zeroRidesEle = ( - No routes found in selected time range. - ); + zeroRidesEle = No routes found in selected time range.; } const containerPadding = windowWidth > 520 ? 36 : 16; diff --git a/src/components/Dashboard/DriveListItem.jsx b/src/components/Dashboard/DriveListItem.jsx index 06dad958..dafee7f8 100644 --- a/src/components/Dashboard/DriveListItem.jsx +++ b/src/components/Dashboard/DriveListItem.jsx @@ -61,9 +61,7 @@ const DriveListItem = (props) => { useEffect(() => { const onScroll = () => { - if (!isVisible && el.current && window && (!window.visualViewport - || window.visualViewport.height >= el.current.getBoundingClientRect().y - 300) - ) { + if (!isVisible && el.current && window && (!window.visualViewport || window.visualViewport.height >= el.current.getBoundingClientRect().y - 300)) { setVisible(true); dispatch(fetchEvents(drive)); dispatch(fetchLocations(drive)); @@ -83,9 +81,7 @@ const DriveListItem = (props) => { }; }, [drive, dispatch, isVisible]); - const onClick = filterRegularClick( - () => dispatch(pushTimelineRange(drive.log_id, 0, drive.duration, true)), - ); + const onClick = filterRegularClick(() => dispatch(pushTimelineRange(drive.log_id, 0, drive.duration, true))); const small = windowWidth < 580; const dateFormat = small ? 'ddd, MMM D' : 'dddd, MMM D'; @@ -95,33 +91,27 @@ const DriveListItem = (props) => { const endTime = dayjs(drive.end_time_utc_millis).format('HH:mm'); const duration = formatDriveDuration(drive.duration); - const distance = isMetric() - ? `${+(drive.distance * KM_PER_MI).toFixed(1)} km` - : `${+drive.distance.toFixed(1)} mi`; + const distance = isMetric() ? `${+(drive.distance * KM_PER_MI).toFixed(1)} km` : `${+drive.distance.toFixed(1)} mi`; /* eslint-disable key-spacing, no-multi-spaces */ - const gridStyle = small ? { - date: { order: 1, maxWidth: '72%', flexBasis: '72%', marginBottom: 12 }, - dur: { order: 2, maxWidth: '28%', flexBasis: '28%', marginBottom: 12 }, - origin: { order: 3, maxWidth: '50%', flexBasis: '50%' }, - dest: { order: 4, maxWidth: '50%', flexBasis: '50%' }, - } : { - date: { order: 1, maxWidth: '28%', flexBasis: '26%' }, - dur: { order: 2, maxWidth: '14%', flexBasis: '14%' }, - origin: { order: 3, maxWidth: '26%', flexBasis: '22%' }, - dest: { order: 4, maxWidth: '26%', flexBasis: '22%' }, - arrow: { order: 5, maxWidth: '6%', flexBasis: '6%' }, - }; + const gridStyle = small + ? { + date: { order: 1, maxWidth: '72%', flexBasis: '72%', marginBottom: 12 }, + dur: { order: 2, maxWidth: '28%', flexBasis: '28%', marginBottom: 12 }, + origin: { order: 3, maxWidth: '50%', flexBasis: '50%' }, + dest: { order: 4, maxWidth: '50%', flexBasis: '50%' }, + } + : { + date: { order: 1, maxWidth: '28%', flexBasis: '26%' }, + dur: { order: 2, maxWidth: '14%', flexBasis: '14%' }, + origin: { order: 3, maxWidth: '26%', flexBasis: '22%' }, + dest: { order: 4, maxWidth: '26%', flexBasis: '22%' }, + arrow: { order: 5, maxWidth: '6%', flexBasis: '6%' }, + }; /* eslint-enable key-spacing, no-multi-spaces */ return ( - +
@@ -147,11 +137,7 @@ const DriveListItem = (props) => { )}
- +
); }; diff --git a/src/components/Dashboard/DriveListItem.test.js b/src/components/Dashboard/DriveListItem.test.js index 72fc933d..47769e2c 100644 --- a/src/components/Dashboard/DriveListItem.test.js +++ b/src/components/Dashboard/DriveListItem.test.js @@ -20,18 +20,20 @@ const store = Redux.createStore((state) => { describe('drive list items', () => { it('has DriveEntry class', () => { - render(); + render( + , + ); expect(screen.getByRole('link')).toHaveClass('DriveEntry'); }); }); diff --git a/src/components/Dashboard/index.jsx b/src/components/Dashboard/index.jsx index 4f6b42c3..2800953b 100644 --- a/src/components/Dashboard/index.jsx +++ b/src/components/Dashboard/index.jsx @@ -30,15 +30,15 @@ const Dashboard = ({ location }) => { return (
}> - { primeNav - ? - : ( - <> - - - - - )} + {primeNav ? ( + + ) : ( + <> + + + + + )}
); diff --git a/src/components/DeviceInfo/index.jsx b/src/components/DeviceInfo/index.jsx index 33a4db09..c66765a6 100644 --- a/src/components/DeviceInfo/index.jsx +++ b/src/components/DeviceInfo/index.jsx @@ -9,7 +9,7 @@ import Colors from '../../colors'; import { deviceIsOnline, deviceNamePretty } from '../../utils'; import { isMetric, KM_PER_MI } from '../../utils/conversions'; import ResizeHandler from '../ResizeHandler'; -import TimeSelect from '../TimeSelect' +import TimeSelect from '../TimeSelect'; import VisibilityHandler from '../VisibilityHandler'; const styles = (theme) => ({ @@ -356,60 +356,40 @@ class DeviceInfo extends Component { return ( <> - - -
- { windowWidth >= 768 - ? ( -
+ + +
+ {windowWidth >= 768 ? ( +
+ {deviceNamePretty(device)} +
{this.renderStats()}
+
{this.renderButtons()}
+
+ ) : ( + <> +
{deviceNamePretty(device)} -
{ this.renderStats() }
-
{ this.renderButtons() }
- ) - : ( - <> -
- {deviceNamePretty(device)} -
-
- { this.renderButtons() } -
- { deviceStats.result - && ( -
- { this.renderStats() } -
- )} - - ) } +
{this.renderButtons()}
+ {deviceStats.result &&
{this.renderStats()}
} + + )}
- { snapshot.result - && ( -
- { windowWidth >= 640 - ? ( -
-
- { this.renderSnapshotImage(snapshot.result.jpegBack, false) } -
-
- { this.renderSnapshotImage(snapshot.result.jpegFront, true) } -
-
- ) - : ( -
-
- { this.renderSnapshotImage(snapshot.result.jpegBack, false) } -
-
- { this.renderSnapshotImage(snapshot.result.jpegFront, true) } -
-
- )} + {snapshot.result && ( +
+ {windowWidth >= 640 ? ( +
+
{this.renderSnapshotImage(snapshot.result.jpegBack, false)}
+
{this.renderSnapshotImage(snapshot.result.jpegFront, true)}
+
+ ) : ( +
+
{this.renderSnapshotImage(snapshot.result.jpegBack, false)}
+
{this.renderSnapshotImage(snapshot.result.jpegFront, true)}
+
+ )}
- )} + )} ); } @@ -429,29 +409,25 @@ class DeviceInfo extends Component { } const metric = isMetric(); - const distance = metric - ? Math.round(deviceStats.result.all.distance * KM_PER_MI) - : Math.round(deviceStats.result.all.distance); + const distance = metric ? Math.round(deviceStats.result.all.distance * KM_PER_MI) : Math.round(deviceStats.result.all.distance); return ( <> -
- - { distance } - - - { metric ? 'kilometers' : 'miles' } +
+ + {distance} + {metric ? 'kilometers' : 'miles'}
-
- - { deviceStats.result.all.routes } +
+ + {deviceStats.result.all.routes} drives
-
- - { Math.round(deviceStats.result.all.minutes / 60.0) } +
+ + {Math.round(deviceStats.result.all.minutes / 60.0)} hours
@@ -465,15 +441,12 @@ class DeviceInfo extends Component { let batteryVoltage; let batteryBackground = Colors.grey400; - if (deviceIsOnline(device) && carHealth?.result && carHealth.result.peripheralState - && carHealth.result.peripheralState.voltage) { + if (deviceIsOnline(device) && carHealth?.result && carHealth.result.peripheralState && carHealth.result.peripheralState.voltage) { batteryVoltage = carHealth.result.peripheralState.voltage / 1000.0; batteryBackground = batteryVoltage < 11.0 ? Colors.red400 : Colors.green400; } - const actionButtonClass = windowWidth >= 520 - ? classes.actionButton - : classes.actionButtonSmall; + const actionButtonClass = windowWidth >= 520 ? classes.actionButton : classes.actionButtonSmall; const buttonOffline = deviceIsOnline(device) ? '' : classes.buttonOffline; let error = null; @@ -493,53 +466,30 @@ class DeviceInfo extends Component { return ( <> -
- { deviceIsOnline(device) - ? ( - - { `${windowWidth >= 520 ? 'car ' : '' - }battery: ${ - batteryVoltage ? `${batteryVoltage.toFixed(1)}\u00a0V` : 'N/A'}` } - - ) - : ( - - device offline - - )} +
+ {deviceIsOnline(device) ? ( + {`${windowWidth >= 520 ? 'car ' : ''}battery: ${batteryVoltage ? `${batteryVoltage.toFixed(1)}\u00a0V` : 'N/A'}`} + ) : ( + + device offline + + )}
- - - { error } + + {error} - + ); } @@ -548,23 +498,14 @@ class DeviceInfo extends Component { const { classes } = this.props; if (!src) { return ( -
- - { isFront && 'Interior' } - {' '} - snapshot not available - - { isFront - && ( - - Enable “Record and Upload Driver Camera” on your device for interior camera snapshots - - )} +
+ {isFront && 'Interior'} snapshot not available + {isFront && Enable “Record and Upload Driver Camera” on your device for interior camera snapshots}
); } - return (); + return ; } } diff --git a/src/components/DriveMap/index.jsx b/src/components/DriveMap/index.jsx index 478a9f38..f8898fce 100644 --- a/src/components/DriveMap/index.jsx +++ b/src/components/DriveMap/index.jsx @@ -21,8 +21,8 @@ const DriveMap = () => { const [driveCoordsMax, setDriveCoordsMax] = useState(null); const mapRef = useRef(null); - const mapInitializedRef = useRef(false); // Track if map.on('load') has been set up - const mapLoadedRef = useRef(false); // Track if map has fully loaded + const mapInitializedRef = useRef(false); // Track if map.on('load') has been set up + const mapLoadedRef = useRef(false); // Track if map has fully loaded const shouldFlyToRef = useRef(false); const isInteractingRef = useRef(false); const isInteractingTimeoutRef = useRef(null); @@ -46,14 +46,8 @@ const DriveMap = () => { const offsetSeconds = Math.floor(offset / 1e3); const offsetFractionalPart = (offset % 1e3) / 1000.0; - const coordIdx = Math.max(minCoord, Math.min( - offsetSeconds, - maxCoord, - )); - const nextCoordIdx = Math.max(minCoord, Math.min( - offsetSeconds + 1, - maxCoord, - )); + const coordIdx = Math.max(minCoord, Math.min(offsetSeconds, maxCoord)); + const nextCoordIdx = Math.max(minCoord, Math.min(offsetSeconds + 1, maxCoord)); if (!route.driveCoords[coordIdx]) { return null; @@ -65,10 +59,7 @@ const DriveMap = () => { } const [ceilLng, ceilLat] = route.driveCoords[nextCoordIdx]; - return [ - floorLng + ((ceilLng - floorLng) * offsetFractionalPart), - floorLat + ((ceilLat - floorLat) * offsetFractionalPart), - ]; + return [floorLng + (ceilLng - floorLng) * offsetFractionalPart, floorLat + (ceilLat - floorLat) * offsetFractionalPart]; }; const setPath = (coords) => { @@ -231,7 +222,7 @@ const DriveMap = () => { map.addLayer(markerGeoJson); mapRef.current = mapComponent; - mapLoadedRef.current = true; // Mark map as loaded + mapLoadedRef.current = true; // Mark map as loaded // Use ref to get current value, not closure const route = currentRouteRef.current; diff --git a/src/components/DriveVideo/index.jsx b/src/components/DriveVideo/index.jsx index 426348df..26c70125 100644 --- a/src/components/DriveVideo/index.jsx +++ b/src/components/DriveVideo/index.jsx @@ -1,6 +1,5 @@ /* eslint-disable camelcase */ - import { video as Video } from '@commaai/api'; import { CircularProgress, Typography } from '@material-ui/core'; import debounce from 'debounce'; @@ -30,9 +29,7 @@ const VideoOverlay = ({ loading, error }) => { } return (
-
- {content} -
+
{content}
); }; @@ -128,7 +125,7 @@ class DriveVideo extends Component { return; } - if (e.type === 'networkError' && (e.response?.code === 404)) { + if (e.type === 'networkError' && e.response?.code === 404) { this.setState({ videoError: 'This video segment has not uploaded yet or has been deleted.' }); } else { this.setState({ videoError: 'Unable to load video' }); @@ -172,9 +169,7 @@ class DriveVideo extends Component { return; } - const videoError = e.response?.code === 404 - ? 'This video segment has not uploaded yet or has been deleted.' - : (e.response?.text || 'Unable to load video'); + const videoError = e.response?.code === 404 ? 'This video segment has not uploaded yet or has been deleted.' : e.response?.text || 'Unable to load video'; this.setState({ videoError }); } @@ -211,19 +206,20 @@ class DriveVideo extends Component { const desiredVideoTime = this.currentVideoTime(); const curVideoTime = videoPlayer.getCurrentTime(); const timeDiff = desiredVideoTime - curVideoTime; - - if (Math.abs(timeDiff) <= Math.max(0.1, 0.5 * newPlaybackRate)) { // newPlaybackRate = 0 when paused, set minimum 0.1 to prevent seeking when paused + + if (Math.abs(timeDiff) <= Math.max(0.1, 0.5 * newPlaybackRate)) { + // newPlaybackRate = 0 when paused, set minimum 0.1 to prevent seeking when paused if (!isIos()) { newPlaybackRate = Math.max(0, newPlaybackRate + Math.round(timeDiff * 10) / 10); } } else if (desiredVideoTime === 0 && timeDiff < 0 && curVideoTime !== videoPlayer.getDuration()) { // logs start earlier than video, so skip to video ts 0 - dispatch(seek(currentOffset() - (timeDiff * 1000))); + dispatch(seek(currentOffset() - timeDiff * 1000)); } else { videoPlayer.seekTo(desiredVideoTime, 'seconds'); } // most browsers don't support more than 16x playback rate, firefox mutes audio above 8x causing audio to cut in and out with timeDiff rate shifts - newPlaybackRate = Math.max(0, Math.min((isFirefox() && !isMuted) ? 8 : 16, newPlaybackRate)); + newPlaybackRate = Math.max(0, Math.min(isFirefox() && !isMuted ? 8 : 16, newPlaybackRate)); const internalPlayer = videoPlayer.getInternalPlayer(); @@ -233,7 +229,7 @@ class DriveVideo extends Component { } else if (isBufferingVideo || !hasLoaded || internalPlayer.readyState < 2) { if (!isBufferingVideo) { dispatch(bufferVideo(true)); - } + } newPlaybackRate = 0; // in some circumstances, iOS won't update readyState unless temporarily paused } @@ -275,14 +271,16 @@ class DriveVideo extends Component { const { src, videoError } = this.state; const onPlayerReady = (player) => { - if (isIos()) { // ios does not support hls.js and on other browsers hls.js does not directly play the m3u8 so audioTracks are not visible + if (isIos()) { + // ios does not support hls.js and on other browsers hls.js does not directly play the m3u8 so audioTracks are not visible const videoElement = player.getInternalPlayer(); if (videoElement && videoElement.audioTracks && videoElement.audioTracks.length > 0) { if (onAudioStatusChange) { onAudioStatusChange(true); } } - } else { // on other platforms, inspect audio tracks before hls.js changes things + } else { + // on other platforms, inspect audio tracks before hls.js changes things const hlsPlayer = player.getInternalPlayer('hls'); if (hlsPlayer) { hlsPlayer.on('hlsBufferCodecs', (event, data) => { diff --git a/src/components/DriveView/Media.jsx b/src/components/DriveView/Media.jsx index fe36e47c..3d27d7b7 100644 --- a/src/components/DriveView/Media.jsx +++ b/src/components/DriveView/Media.jsx @@ -241,7 +241,7 @@ class Media extends Component { } handleMuteToggle() { - this.setState(prevState => ({ isMuted: !prevState.isMuted })); + this.setState((prevState) => ({ isMuted: !prevState.isMuted })); } handleAudioStatusChange(hasAudio) { @@ -267,17 +267,21 @@ class Media extends Component { this.props.dispatch(fetchEvents(this.props.currentRoute)); } - if (this.props.currentRoute && ((!prevState.downloadMenu && downloadMenu) - || (!this.props.files && !prevState.moreInfoMenu && moreInfoMenu) - || (!prevProps.currentRoute && (downloadMenu || moreInfoMenu)))) { + if ( + this.props.currentRoute && + ((!prevState.downloadMenu && downloadMenu) || (!this.props.files && !prevState.moreInfoMenu && moreInfoMenu) || (!prevProps.currentRoute && (downloadMenu || moreInfoMenu))) + ) { if ((this.props.device && !this.props.device.shared) || this.props.profile?.superuser) { this.props.dispatch(fetchAthenaQueue(this.props.dongleId)); } this.props.dispatch(fetchFiles(this.props.currentRoute.fullname)); } - if (routePreserved === null && (this.props.device?.is_owner || this.props.profile?.superuser) - && (!prevState.moreInfoMenu && !prevProps.currentRoute) !== (moreInfoMenu && this.props.currentRoute)) { + if ( + routePreserved === null && + (this.props.device?.is_owner || this.props.profile?.superuser) && + (!prevState.moreInfoMenu && !prevProps.currentRoute) !== (moreInfoMenu && this.props.currentRoute) + ) { this.fetchRoutePreserved(); } @@ -342,7 +346,7 @@ class Media extends Component { for (const fn of FILE_NAMES[type]) { const path = `${routeNoDongleId}--${getSegmentNumber(currentRoute)}/${fn}`; paths.push(path); - url_promises.push(fetchUploadUrls(dongleId, [path]).then(urls => urls[0])); + url_promises.push(fetchUploadUrls(dongleId, [path]).then((urls) => urls[0])); } const urls = await Promise.all(url_promises); @@ -364,8 +368,7 @@ class Media extends Component { const uploading = {}; const adjusted_start_time = currentRoute.start_time_utc_millis + loop.startTime; for (let i = 0; i < currentRoute.segment_numbers.length; i++) { - if (currentRoute.segment_start_times[i] < adjusted_start_time + loop.duration - && currentRoute.segment_end_times[i] > adjusted_start_time) { + if (currentRoute.segment_start_times[i] < adjusted_start_time + loop.duration && currentRoute.segment_end_times[i] > adjusted_start_time) { types.forEach((type) => { const fileName = `${currentRoute.fullname}--${currentRoute.segment_numbers[i]}/${type}`; if (!files[fileName]) { @@ -378,7 +381,7 @@ class Media extends Component { const paths = Object.keys(uploading).flatMap((fileName) => { const [seg, type] = fileName.split('/'); - return FILE_NAMES[type].map(file => `${seg.split('|')[1]}/${file}`); + return FILE_NAMES[type].map((file) => `${seg.split('|')[1]}/${file}`); }); const urls = await fetchUploadUrls(dongleId, paths); @@ -392,8 +395,7 @@ class Media extends Component { const adjusted_start_time = currentRoute.start_time_utc_millis + loop.startTime; for (let i = 0; i < currentRoute.segment_numbers.length; i++) { - if (currentRoute.segment_start_times[i] < adjusted_start_time + loop.duration - && currentRoute.segment_end_times[i] > adjusted_start_time) { + if (currentRoute.segment_start_times[i] < adjusted_start_time + loop.duration && currentRoute.segment_end_times[i] > adjusted_start_time) { for (let j = 0; j < types.length; j++) { count += 1; const log = files[`${currentRoute.fullname}--${currentRoute.segment_numbers[i]}/${types[j]}`]; @@ -491,42 +493,31 @@ class Media extends Component { const { classes } = this.props; const { inView, windowWidth, isMuted, hasAudio } = this.state; - if (this.props.menusOnly) { // for test + if (this.props.menusOnly) { + // for test return this.renderMenus(true); } const showMapAlways = windowWidth >= 1536; const mediaContainerStyle = showMapAlways ? { width: '60%' } : { width: '100%' }; - const mapContainerStyle = showMapAlways - ? { width: '40%', marginBottom: 62, marginTop: 46, paddingLeft: 24 } - : { width: '100%' }; + const mapContainerStyle = showMapAlways ? { width: '40%', marginBottom: 62, marginTop: 46, paddingLeft: 24 } : { width: '100%' }; return (
this.setState({ windowWidth: ww })} />
{this.renderMediaOptions(showMapAlways)} - {inView === MediaType.VIDEO && ( - - )} - {(inView === MediaType.MAP && !showMapAlways) && ( + {inView === MediaType.VIDEO && } + {inView === MediaType.MAP && !showMapAlways && (
)}
- +
- {(inView === MediaType.VIDEO && showMapAlways) && ( + {inView === MediaType.VIDEO && showMapAlways && (
@@ -541,44 +532,28 @@ class Media extends Component { return ( <>
- { showMapAlways - ?
- : ( -
-
this.setState({ inView: MediaType.VIDEO })} - > - Video -
-
this.setState({ inView: MediaType.MAP })} - > - Map -
+ {showMapAlways ? ( +
+ ) : ( +
+
this.setState({ inView: MediaType.VIDEO })}> + Video
- )} +
this.setState({ inView: MediaType.MAP })}> + Map +
+
+ )}
-
this.setState({ downloadMenu: ev.target }) } - > +
this.setState({ downloadMenu: ev.target })}> Files
-
this.setState({ moreInfoMenu: ev.target }) } - > +
this.setState({ moreInfoMenu: ev.target })}> More info
- { this.renderMenus() } + {this.renderMenus()} ); } @@ -591,8 +566,10 @@ class Media extends Component { return null; } - let fcam = {}; let ecam = {}; let dcam = {}; let - rlog = {}; + let fcam = {}; + let ecam = {}; + let dcam = {}; + let rlog = {}; if (files && currentRoute) { const seg = `${currentRoute.fullname}--${getSegmentNumber(currentRoute)}`; fcam = files[`${seg}/cameras`] || {}; @@ -618,161 +595,111 @@ class Media extends Component { <> this.setState({ downloadMenu: null }) } + open={Boolean(alwaysOpen || downloadMenu)} + anchorEl={downloadMenu} + onClose={() => this.setState({ downloadMenu: null })} anchorOrigin={{ vertical: 'top', horizontal: 'right' }} transformOrigin={{ vertical: 'top', horizontal: 'right' }} > - { !files - && ( -
- -
+ {!files && ( +
+ +
)} - { buttons.filter((b) => Boolean(b)).map(this.renderUploadMenuItem)} + {buttons.filter((b) => Boolean(b)).map(this.renderUploadMenuItem)} - + All logs - { Boolean(files && canUpload && !rlogUploadDisabled) - && ( - + {Boolean(files && canUpload && !rlogUploadDisabled) && ( + )} - { Boolean(canUpload && rlogUploadDisabled && stats) - && ( -
- { stats.isUploadedRlog - ? 'uploaded' - : (stats.isUploadingRlog ? 'pending' : )} -
+ {Boolean(canUpload && rlogUploadDisabled && stats) && ( +
+ {stats.isUploadedRlog ? 'uploaded' : stats.isUploadingRlog ? 'pending' : } +
)}
- + All files - { Boolean(files && canUpload && !allUploadDisabled) - && ( - + {Boolean(files && canUpload && !allUploadDisabled) && ( + )} - { Boolean(canUpload && allUploadDisabled && stats) - && ( -
- { stats.isUploadedAll - ? 'uploaded' - : (stats.isUploadingAll ? 'pending' : )} -
+ {Boolean(canUpload && allUploadDisabled && stats) && ( +
+ {stats.isUploadedAll ? 'uploaded' : stats.isUploadingAll ? 'pending' : } +
)}
- { deviceIsOnline(device) || !files ? ( + {deviceIsOnline(device) || !files ? ( this.setState({ uploadModal: true, downloadMenu: null }) : null } - style={ files ? { pointerEvents: 'auto' } : { color: Colors.white60 } } - className={ classes.filesItem } - disabled={ !files } + onClick={files ? () => this.setState({ uploadModal: true, downloadMenu: null }) : null} + style={files ? { pointerEvents: 'auto' } : { color: Colors.white60 }} + className={classes.filesItem} + disabled={!files} > View upload queue - ) - : ( - -
- - Device offline -
- uploading will resume when device is online -
- )} - { stats && stats.isPausedAll && deviceOnCellular(device) - && ( - -
- - Connect to WiFi -
- uploading paused on cellular connection -
+ ) : ( + +
+ + Device offline +
+ uploading will resume when device is online +
+ )} + {stats && stats.isPausedAll && deviceOnCellular(device) && ( + +
+ + Connect to WiFi +
+ uploading paused on cellular connection +
)}
this.setState({ moreInfoMenu: null }) } + open={Boolean(alwaysOpen || moreInfoMenu)} + anchorEl={moreInfoMenu} + onClose={() => this.setState({ moreInfoMenu: null })} transformOrigin={{ vertical: 'top', horizontal: windowWidth > 400 ? 260 : 300 }} > - 400 ? '0.8rem' : '0.7rem' }} - > -
{ currentRoute ? `${currentRoute.fullname.replace('|', '/')}/${getSegmentNumber(currentRoute)}` : '---' }
+ 400 ? '0.8rem' : '0.7rem' }}> +
{currentRoute ? `${currentRoute.fullname.replace('|', '/')}/${getSegmentNumber(currentRoute)}` : '---'}
- { typeof navigator.share !== 'undefined' - && ( - - Share this route - - + {typeof navigator.share !== 'undefined' && ( + + Share this route + + )} - - View in useradmin - - { Boolean(device?.is_owner || (profile && profile.superuser)) && [ + View in useradmin + {Boolean(device?.is_owner || (profile && profile.superuser)) && [ , - - + + , - - + + , - ] } + ]}
this.setState({ uploadModal: false }) } - update={ Boolean(moreInfoMenu || uploadModal || downloadMenu) } - store={ this.props.store } - device={ device } + open={uploadModal} + onClose={() => this.setState({ uploadModal: false })} + update={Boolean(moreInfoMenu || uploadModal || downloadMenu)} + store={this.props.store} + device={device} /> - + make sure to enable the “Record and Upload Driver Camera” toggle @@ -791,67 +718,52 @@ class Media extends Component { button = null; } else if (file.url) { button = ( - ); } else if (file.progress !== undefined) { button = ( -
- { file.current - ? `${Math.floor(file.progress * 100)}%` - : (file.paused ? 'paused' : 'pending') } +
+ {file.current ? `${Math.floor(file.progress * 100)}%` : file.paused ? 'paused' : 'pending'}
); } else if (file.requested) { button = ( -
- +
+
); } else if (file.notFound) { button = (
this.setState({ dcamUploadInfo: ev.target }) : null } - onMouseLeave={ type === 'dcameras' ? () => this.setState({ dcamUploadInfo: null }) : null } + className={classes.fakeUploadButton} + style={{ minWidth: uploadButtonWidth - 24 }} + onMouseEnter={type === 'dcameras' ? (ev) => this.setState({ dcamUploadInfo: ev.target }) : null} + onMouseLeave={type === 'dcameras' ? () => this.setState({ dcamUploadInfo: null }) : null} > not found - { type === 'dcameras' && } + {type === 'dcameras' && }
); } else if (!canUpload) { button = ( - ); } else { button = ( - ); } return ( - - { name } - { button } + + {name} + {button} ); } diff --git a/src/components/DriveView/NoDeviceUpsell.jsx b/src/components/DriveView/NoDeviceUpsell.jsx index 600cec2e..afb39288 100644 --- a/src/components/DriveView/NoDeviceUpsell.jsx +++ b/src/components/DriveView/NoDeviceUpsell.jsx @@ -1,24 +1,17 @@ - - import AddDevice from '../Dashboard/AddDevice'; const NoDeviceUpsell = () => (

Pair your device

-

- Scan the QR code on your device. - If you cannot see a QR code, check the following: -

+

Scan the QR code on your device. If you cannot see a QR code, check the following:

  • Your device is connected to the internet
  • You have installed the latest version of openpilot
  • You may need to look for "Pair Device" in Settings

- If you still cannot see a QR code, your device may already be paired to - another account. Make sure you have signed in with the same account you - may have used previously. + If you still cannot see a QR code, your device may already be paired to another account. Make sure you have signed in with the same account you may have used previously.

diff --git a/src/components/DriveView/index.jsx b/src/components/DriveView/index.jsx index cc3a8f77..a1023676 100644 --- a/src/components/DriveView/index.jsx +++ b/src/components/DriveView/index.jsx @@ -42,31 +42,20 @@ class DriveView extends Component {
- this.onBack(zoom, currentRoute) } - aria-label="Go Back" - disabled={ backButtonDisabled } - > + this.onBack(zoom, currentRoute)} aria-label="Go Back" disabled={backButtonDisabled}>
{`${startDay} `} {`${startTime} - ${endTime}`}
- +
-
- {(routes && routes.length === 0) - ? Route does not exist. - : } -
+
{routes && routes.length === 0 ? Route does not exist. : }
); diff --git a/src/components/ErrorFallback.jsx b/src/components/ErrorFallback.jsx index afb7fcaf..d3bb8ce3 100644 --- a/src/components/ErrorFallback.jsx +++ b/src/components/ErrorFallback.jsx @@ -10,16 +10,19 @@ const ErrorFallback = ({ error, componentStack }) => { useEffect(() => { if ('serviceWorker' in navigator) { setSwInfo('loading...'); - navigator.serviceWorker.getRegistrations().then((registrations) => { - if (registrations.length === 0) { - setSwInfo('none'); - return; - } - const serviceWorkers = registrations.map((r) => `${r.scope} ${r.active?.state}`); - setSwInfo(serviceWorkers.join('; ')); - }).catch((err) => { - setSwInfo(err.toString()); - }); + navigator.serviceWorker + .getRegistrations() + .then((registrations) => { + if (registrations.length === 0) { + setSwInfo('none'); + return; + } + const serviceWorkers = registrations.map((r) => `${r.scope} ${r.active?.state}`); + setSwInfo(serviceWorkers.join('; ')); + }) + .catch((err) => { + setSwInfo(err.toString()); + }); } else { setSwInfo('not supported'); } @@ -66,22 +69,18 @@ ${error.toString()}${componentStack}`;

Oops!

Something went wrong. Please reload the page.

- If you continue to have problems, let us know on - {' '} - Discord - {' '} - in the - {' '} - #connect-feedback - {' '} + If you continue to have problems, let us know on{' '} + + Discord + {' '} + in the{' '} + + #connect-feedback + {' '} channel.

- @@ -90,9 +89,7 @@ ${error.toString()}${componentStack}`;
Show debugging information
-
-            {information}
-          
+
{information}
-
diff --git a/src/components/IosPwaPopup/index.jsx b/src/components/IosPwaPopup/index.jsx index 8d009b42..48d3be08 100644 --- a/src/components/IosPwaPopup/index.jsx +++ b/src/components/IosPwaPopup/index.jsx @@ -62,7 +62,7 @@ class IosPwaPopup extends Component { } async componentDidMount() { - if (window && window.navigator) { + if (window && window.navigator) { const isStandalone = window.navigator.standalone === true; if (isIos() && !isStandalone && MyCommaAuth.isAuthenticated()) { let isHidden; @@ -118,17 +118,11 @@ class IosPwaPopup extends Component { return (
- - Add to home screen + + Add to home screen - Install this webapp on your home screen: - {' '} -
- tap - {' '} - share - {' '} - and then ‘Add to Home Screen’ + Install this webapp on your home screen:
+ tap share and then ‘Add to Home Screen’
diff --git a/src/components/Navigation/index.jsx b/src/components/Navigation/index.jsx index 9c28d681..96ac1617 100644 --- a/src/components/Navigation/index.jsx +++ b/src/components/Navigation/index.jsx @@ -193,9 +193,13 @@ class Navigation extends Component { const { dongleId, device } = this.props; const { geoLocateCoords, search, carLastLocation, carNetworkLocation, searchSelect } = this.state; - if ((carLastLocation && !prevState.carLastLocation) || (carNetworkLocation && !prevState.carNetworkLocation) - || (geoLocateCoords && !prevState.geoLocateCoords) || (searchSelect && prevState.searchSelect !== searchSelect) - || (search && prevState.search !== search)) { + if ( + (carLastLocation && !prevState.carLastLocation) || + (carNetworkLocation && !prevState.carNetworkLocation) || + (geoLocateCoords && !prevState.geoLocateCoords) || + (searchSelect && prevState.searchSelect !== searchSelect) || + (search && prevState.search !== search) + ) { this.flyToMarkers(); } @@ -209,7 +213,6 @@ class Navigation extends Component { if (prevProps.device !== device) { this.updateDevice(); } - } componentWillUnmount() { @@ -237,10 +240,13 @@ class Navigation extends Component { try { const resp = await Devices.fetchLocation(dongleId); if (this.mounted && dongleId === this.props.dongleId) { - this.setState({ - carLastLocation: [resp.lng, resp.lat], - carLastLocationTime: resp.time, - }, this.flyToMarkers); + this.setState( + { + carLastLocation: [resp.lng, resp.lat], + carLastLocationTime: resp.time, + }, + this.flyToMarkers, + ); } } catch (err) { if (!err.message || err.message.indexOf('no_segments_uploaded') === -1) { @@ -265,14 +271,16 @@ class Navigation extends Component { } resp = await networkPositioning(resp.result); if (resp && this.mounted && dongleId === this.props.dongleId) { - this.setState({ - carNetworkLocation: [resp.lng, resp.lat], - carNetworkLocationAccuracy: resp.accuracy, - }, this.flyToMarkers); + this.setState( + { + carNetworkLocation: [resp.lng, resp.lat], + carNetworkLocationAccuracy: resp.accuracy, + }, + this.flyToMarkers, + ); } } catch (err) { - if (this.mounted && dongleId === this.props.dongleId - && (!err.message || err.message.indexOf('{"error": "Device not registered"}') === -1)) { + if (this.mounted && dongleId === this.props.dongleId && (!err.message || err.message.indexOf('{"error": "Device not registered"}') === -1)) { console.error(err); Sentry.captureException(err, { fingerprint: 'nav_fetch_network_location' }); } @@ -282,8 +290,7 @@ class Navigation extends Component { getCarLocation() { const { carLastLocation, carLastLocationTime, carNetworkLocation, carNetworkLocationAccuracy } = this.state; - if (carNetworkLocation && carNetworkLocationAccuracy <= 10000 - && (carNetworkLocationAccuracy <= 100 || !carLastLocation)) { + if (carNetworkLocation && carNetworkLocationAccuracy <= 10000 && (carNetworkLocationAccuracy <= 100 || !carLastLocation)) { return { location: carNetworkLocation, accuracy: carNetworkLocationAccuracy, @@ -315,7 +322,8 @@ class Navigation extends Component { label: '', }, position: { - lng, lat, + lng, + lat, }, resultType: 'car', title: '', @@ -375,13 +383,28 @@ class Navigation extends Component { } if (bounds.length) { - const bbox = [[ - Math.min.apply(null, bounds.map((e) => e[0][0])), - Math.min.apply(null, bounds.map((e) => e[0][1])), - ], [ - Math.max.apply(null, bounds.map((e) => e[1][0])), - Math.max.apply(null, bounds.map((e) => e[1][1])), - ]]; + const bbox = [ + [ + Math.min.apply( + null, + bounds.map((e) => e[0][0]), + ), + Math.min.apply( + null, + bounds.map((e) => e[0][1]), + ), + ], + [ + Math.max.apply( + null, + bounds.map((e) => e[1][0]), + ), + Math.max.apply( + null, + bounds.map((e) => e[1][1]), + ), + ], + ]; if (Math.abs(bbox[0][0] - bbox[1][0]) < 0.01) { bbox[0][0] -= 0.01; @@ -392,8 +415,7 @@ class Navigation extends Component { bbox[1][1] += 0.01; } - const bottomBoxHeight = (this.searchSelectBoxRef.current && viewport.height > 200) - ? this.searchSelectBoxRef.current.getBoundingClientRect().height + 10 : 0; + const bottomBoxHeight = this.searchSelectBoxRef.current && viewport.height > 200 ? this.searchSelectBoxRef.current.getBoundingClientRect().height + 10 : 0; let rightBoxWidth = 0; let topBoxHeight = 0; @@ -408,7 +430,7 @@ class Navigation extends Component { } const padding = { - left: (windowWidth < 600 || !search) ? 20 : 390, + left: windowWidth < 600 || !search ? 20 : 390, right: rightBoxWidth + 20, top: topBoxHeight + 20, bottom: bottomBoxHeight + 20, @@ -426,8 +448,7 @@ class Navigation extends Component { } focus(ev) { - if (!this.state.hasFocus && (!ev || !ev.srcEvent || !ev.srcEvent.path || !this.mapContainerRef.current - || ev.srcEvent.path.includes(this.mapContainerRef.current))) { + if (!this.state.hasFocus && (!ev || !ev.srcEvent || !ev.srcEvent.path || !this.mapContainerRef.current || ev.srcEvent.path.includes(this.mapContainerRef.current))) { this.setState({ hasFocus: true }); } } @@ -473,12 +494,13 @@ class Navigation extends Component { const points = 128; const km = carLocation.accuracy / 1000; - const distanceX = km / (111.320 * Math.cos(carLocation.location[1] * (Math.PI / 180))); + const distanceX = km / (111.32 * Math.cos(carLocation.location[1] * (Math.PI / 180))); const distanceY = km / 110.574; const res = []; - let theta; let x; let - y; + let theta; + let x; + let y; for (let i = 0; i < points; i++) { theta = (i / points) * (2 * Math.PI); x = distanceX * Math.cos(theta); @@ -490,13 +512,15 @@ class Navigation extends Component { return { type: 'FeatureCollection', - features: [{ - type: 'Feature', - geometry: { - type: 'Polygon', - coordinates: [res], + features: [ + { + type: 'Feature', + geometry: { + type: 'Polygon', + coordinates: [res], + }, }, - }], + ], }; } @@ -512,9 +536,10 @@ class Navigation extends Component { const { mapError, hasFocus, searchSelect, viewport, windowWidth, showPrimeAd } = this.state; const carLocation = this.getCarLocation(); - const cardStyle = windowWidth < 600 - ? { zIndex: 4, width: 'auto', height: 'auto', top: 'auto', bottom: 'auto', left: 10, right: 10 } - : { zIndex: 4, width: 360, height: 'auto', top: 'auto', bottom: 'auto', left: 10 }; + const cardStyle = + windowWidth < 600 + ? { zIndex: 4, width: 'auto', height: 'auto', top: 'auto', bottom: 'auto', left: 10, right: 10 } + : { zIndex: 4, width: 360, height: 'auto', top: 'auto', bottom: 'auto', left: 10 }; let carPinTooltipStyle = { transform: 'translate(calc(-50% + 10px), -4px)' }; if (carLocation) { @@ -525,20 +550,15 @@ class Navigation extends Component { } return ( -
+
- {mapError - && ( -
- Could not initialize map. - {mapError} -
- )} + {mapError && ( +
+ Could not initialize map. + {mapError} +
+ )} { }} + onViewportChange={() => {}} /> - {carLocation - && ( - - this.toggleCarPinTooltip(true)} - onMouseLeave={() => this.toggleCarPinTooltip(false)} - alt="car-location" - onClick={() => this.onCarSelect(carLocation)} - /> -
- {dayjs(carLocation.time).format('h:mm A')} - , -
- {timeFromNow(carLocation.time)} -
-
- )} - {carLocation && Boolean(carLocation.accuracy) - && ( - - - - )} - {searchSelect - && ( - - )} - {showPrimeAd && !device.prime && device.is_owner - && ( - + this.toggleCarPinTooltip(true)} + onMouseLeave={() => this.toggleCarPinTooltip(false)} + alt="car-location" + onClick={() => this.onCarSelect(carLocation)} /> - )} +
+ {dayjs(carLocation.time).format('h:mm A')} + , +
+ {timeFromNow(carLocation.time)} +
+ + )} + {carLocation && Boolean(carLocation.accuracy) && ( + + + + )} + {searchSelect && ( + + )} + {showPrimeAd && !device.prime && device.is_owner && ( + + )}
); @@ -681,26 +679,18 @@ class Navigation extends Component { return (
- this.setState({ showPrimeAd: false }, this.flyToMarkers)} - /> + this.setState({ showPrimeAd: false }, this.flyToMarkers)} />
comma prime
-
- - Put your car on the internet with comma prime - + Put your car on the internet with comma prime
); } diff --git a/src/components/Navigation/utils.test.js b/src/components/Navigation/utils.test.js index becf2800..04fc2658 100644 --- a/src/components/Navigation/utils.test.js +++ b/src/components/Navigation/utils.test.js @@ -88,7 +88,7 @@ describe('navigation formatting utils', () => { countyCode: 'LDN', county: 'London', city: 'London', - district: 'St James\'s Park', + district: "St James's Park", street: 'Victoria Street', postalCode: 'SW1E 6', houseNumber: '123', @@ -112,10 +112,7 @@ describe('navigation formatting utils', () => { state: 'New Mexico', county: 'Rio Arriba', city: 'Chimayo', - streets: [ - '1441 Rd', - 'State Road 76', - ], + streets: ['1441 Rd', 'State Road 76'], postalCode: '87522', }, }, diff --git a/src/components/PWAIcon.jsx b/src/components/PWAIcon.jsx index 2e620dd4..97e95116 100644 --- a/src/components/PWAIcon.jsx +++ b/src/components/PWAIcon.jsx @@ -1,14 +1,10 @@ import { useRegisterSW } from 'virtual:pwa-register/react'; -import { - CircularProgress, - IconButton, - Tooltip, -} from '@material-ui/core'; +import { CircularProgress, IconButton, Tooltip } from '@material-ui/core'; import { useState } from 'react'; import { CheckCircle, Download } from '../icons'; -const intervalMS = 60 * 60 * 1000; // 1 hour +const intervalMS = 60 * 60 * 1000; // 1 hour const PWAIcon = ({ immediate }) => { const { @@ -72,18 +68,9 @@ const PWAIcon = ({ immediate }) => { } return ( - {title}} - > - - {installing ? ( - - ) : icon} + {title}}> + + {installing ? : icon} ); diff --git a/src/components/Prime/PrimeCheckout.jsx b/src/components/Prime/PrimeCheckout.jsx index ae9f430a..4be90e86 100644 --- a/src/components/Prime/PrimeCheckout.jsx +++ b/src/components/Prime/PrimeCheckout.jsx @@ -15,19 +15,19 @@ import ResizeHandler from '../ResizeHandler'; const styles = () => ({ linkHighlight: { '&:link': { - textDecoration: "underline", + textDecoration: 'underline', color: Colors.green300, }, '&:visited': { - textDecoration: "underline", + textDecoration: 'underline', color: Colors.green300, }, '&:active': { - textDecoration: "underline", + textDecoration: 'underline', color: Colors.green300, }, '&:hover': { - textDecoration: "underline", + textDecoration: 'underline', color: Colors.green400, }, }, @@ -246,11 +246,7 @@ class PrimeCheckout extends Component { this.setState({ loadingCheckout: true }); try { const { selectedPlan: plan } = this.state; - const resp = await Billing.getStripeCheckout( - dongleId, - subscribeInfo.sim_id, - plan, - ); + const resp = await Billing.getStripeCheckout(dongleId, subscribeInfo.sim_id, plan); window.location = resp.url; } catch (err) { // TODO show error messages @@ -266,12 +262,12 @@ class PrimeCheckout extends Component { } return Boolean( - device.eligible_features?.prime_data - && subscribeInfo - && subscribeInfo.sim_id - && subscribeInfo.is_prime_sim - && subscribeInfo.sim_usable !== false - && ['blue', 'magenta_new', 'webbing'].includes(subscribeInfo.sim_type), + device.eligible_features?.prime_data && + subscribeInfo && + subscribeInfo.sim_id && + subscribeInfo.is_prime_sim && + subscribeInfo.sim_usable !== false && + ['blue', 'magenta_new', 'webbing'].includes(subscribeInfo.sim_type), ); } @@ -307,9 +303,7 @@ class PrimeCheckout extends Component { const containerPadding = windowWidth > 520 ? { margin: '18px 24px' } : { margin: '6px 12px' }; const blockMargin = windowWidth > 520 ? { marginTop: 24 } : { marginTop: 8 }; - const paddingStyle = windowWidth > 520 - ? { paddingLeft: 7, paddingRight: 7 } - : { paddingLeft: 8, paddingRight: 8 }; + const paddingStyle = windowWidth > 520 ? { paddingLeft: 7, paddingRight: 7 } : { paddingLeft: 8, paddingRight: 8 }; const selectedStyle = { border: '2px solid white' }; const plansLoadingClass = !subscribeInfo ? classes.planInfoLoading : ''; const disabledDataPlan = Boolean(!subscribeInfo || !this.dataPlanAvailable()); @@ -326,122 +320,128 @@ class PrimeCheckout extends Component { } else if (!subscribeInfo.is_prime_sim) { disabledDataPlanText = 'Standard plan not available, detected a third-party SIM.'; } else if (!['blue', 'magenta_new', 'webbing'].includes(subscribeInfo.sim_type)) { - disabledDataPlanText = ['Standard plan not available, old SIM type detected, new SIM cards are available in the ', - shop]; + disabledDataPlanText = [ + 'Standard plan not available, old SIM type detected, new SIM cards are available in the ', + + shop + , + ]; } else if (subscribeInfo.sim_usable === false && subscribeInfo.sim_type === 'blue') { - disabledDataPlanText = ['Standard plan not available, SIM has been canceled and is therefore no longer usable, new SIM cards are available in the ', - shop]; + disabledDataPlanText = [ + 'Standard plan not available, SIM has been canceled and is therefore no longer usable, new SIM cards are available in the ', + + shop + , + ]; } else if (subscribeInfo.sim_usable === false) { - disabledDataPlanText = ['Standard plan not available, SIM is no longer usable, new SIM cards are available in the ', - shop]; + disabledDataPlanText = [ + 'Standard plan not available, SIM is no longer usable, new SIM cards are available in the ', + + shop + , + ]; } } return ( -
+
-
- navigate(`/${dongleId}`) }> +
+ navigate(`/${dongleId}`)}> -
+
{deviceNamePretty(device)} {`(${device.dongle_id})`}
-

comma prime

-
-
-
+

comma prime

+
+
+

24/7 connectivity

-
+

Take pictures remotely

-
+

1 year storage of drive videos

-
+

Simple SSH for developers

-
-
+
+
this.setState({ selectedPlan: 'nodata' }) : null } + className={`${classes.plan} ${plansLoadingClass}`} + style={selectedPlan === 'nodata' ? selectedStyle : {}} + onClick={subscribeInfo ? () => this.setState({ selectedPlan: 'nodata' }) : null} > -

lite

-

$10/month

-

+

lite

+

$10/month

+

bring your own
sim card

this.setState({ selectedPlan: 'data' }) : null } + className={`${classes.plan} ${disabledDataPlan ? classes.planDisabled : ''} ${plansLoadingClass}`} + style={selectedPlan === 'data' ? selectedStyle : {}} + onClick={!disabledDataPlan ? () => this.setState({ selectedPlan: 'data' }) : null} > -

standard

-

$24/month

-

+

standard

+

$24/month

+

including data plan
only offered in the U.S.

- { !subscribeInfo - && ( -
- + {!subscribeInfo && ( +
+ Fetching SIM data
- )} -
- { disabledDataPlanText && ( -
- - { disabledDataPlanText } + )}
- ) } -
- + {disabledDataPlanText && ( +
+ + {disabledDataPlanText} +
+ )} +
+ {'Learn more about comma prime from our '} - FAQ + + FAQ +
- { error && ( -
- - { error } -
- ) } -
-
- { chargeText - && ( -
- { chargeText } + {chargeText && ( +
+ {chargeText}
- )} + )}
); } diff --git a/src/components/Prime/PrimeManage.jsx b/src/components/Prime/PrimeManage.jsx index 61cd809a..2989cae3 100644 --- a/src/components/Prime/PrimeManage.jsx +++ b/src/components/Prime/PrimeManage.jsx @@ -16,19 +16,19 @@ import ResizeHandler from '../ResizeHandler'; const styles = (theme) => ({ linkHighlight: { '&:link': { - textDecoration: "underline", + textDecoration: 'underline', color: Colors.green300, }, '&:visited': { - textDecoration: "underline", + textDecoration: 'underline', color: Colors.green300, }, '&:active': { - textDecoration: "underline", + textDecoration: 'underline', color: Colors.green300, }, '&:hover': { - textDecoration: "underline", + textDecoration: 'underline', color: Colors.green400, }, }, @@ -209,11 +209,13 @@ class PrimeManage extends Component { componentDidUpdate(prevProps, prevState) { if (!prevProps.stripeSuccess && this.props.stripeSuccess) { - this.setState({ - stripeStatus: { sessionId: this.props.stripeSuccess, loading: true, paid: null }, - }, this.fetchStripeSession); + this.setState( + { + stripeStatus: { sessionId: this.props.stripeSuccess, loading: true, paid: null }, + }, + this.fetchStripeSession, + ); } - } componentWillUnmount() { @@ -222,19 +224,21 @@ class PrimeManage extends Component { cancelPrime() { this.setState({ canceling: true }); - Billing.cancelPrime(this.props.dongleId).then((resp) => { - if (resp.success) { - this.setState({ canceling: false, cancelError: null, cancelSuccess: 'Cancelled subscription.' }); - this.fetchSubscription(); - } else if (resp.error) { - this.setState({ canceling: false, cancelError: resp.description }); - } else { + Billing.cancelPrime(this.props.dongleId) + .then((resp) => { + if (resp.success) { + this.setState({ canceling: false, cancelError: null, cancelSuccess: 'Cancelled subscription.' }); + this.fetchSubscription(); + } else if (resp.error) { + this.setState({ canceling: false, cancelError: resp.description }); + } else { + this.setState({ canceling: false, cancelError: 'Could not cancel due to unknown error. Please try again.' }); + } + }) + .catch((err) => { + Sentry.captureException(err, { fingerprint: 'primemanage_cancel_prime' }); this.setState({ canceling: false, cancelError: 'Could not cancel due to unknown error. Please try again.' }); - } - }).catch((err) => { - Sentry.captureException(err, { fingerprint: 'primemanage_cancel_prime' }); - this.setState({ canceling: false, cancelError: 'Could not cancel due to unknown error. Please try again.' }); - }); + }); } async gotoUpdate() { @@ -258,11 +262,13 @@ class PrimeManage extends Component { try { const resp = await Billing.getStripeSession(dongleId, stripeStatus.sessionId); const status = resp.payment_status; - this.setState({ stripeStatus: { - ...stripeStatus, - paid: status, - loading: status !== 'paid', - } }); + this.setState({ + stripeStatus: { + ...stripeStatus, + paid: status, + loading: status !== 'paid', + }, + }); if (status === 'paid') { this.fetchSubscription(true); } else { @@ -344,32 +350,26 @@ class PrimeManage extends Component { comma prime {stripeStatus && ( <> - {stripeStatus.paid !== 'paid' - && ( -
- - Waiting for confirmed payment -
- )} - {Boolean(stripeStatus.paid === 'paid' && !hasPrimeSub) - && ( -
- - Processing subscription -
- )} - {Boolean(stripeStatus.paid === 'paid' && hasPrimeSub) - && ( -
- comma prime activated - {subscription.is_prime_sim && ( - - Connectivity will be enabled as soon as activation propagates to your - local cell tower. Rebooting your device may help. - - )} -
- )} + {stripeStatus.paid !== 'paid' && ( +
+ + Waiting for confirmed payment +
+ )} + {Boolean(stripeStatus.paid === 'paid' && !hasPrimeSub) && ( +
+ + Processing subscription +
+ )} + {Boolean(stripeStatus.paid === 'paid' && hasPrimeSub) && ( +
+ comma prime activated + {subscription.is_prime_sim && ( + Connectivity will be enabled as soon as activation propagates to your local cell tower. Rebooting your device may help. + )} +
+ )} )}
@@ -394,25 +394,21 @@ class PrimeManage extends Component { Joined {joinDate}
- {!hasCancelAt - && ( -
- Next payment - {nextPaymentDate} -
- )} - {hasCancelAt - && ( -
- Subscription end - {cancelAtDate} -
- )} + {!hasCancelAt && ( +
+ Next payment + {nextPaymentDate} +
+ )} + {hasCancelAt && ( +
+ Subscription end + {cancelAtDate} +
+ )}
Amount - - {`$${(subscription.amount / 100).toFixed(2)}`} - + {`$${(subscription.amount / 100).toFixed(2)}`}
{this.state.error && (
@@ -429,50 +425,43 @@ class PrimeManage extends Component { > {hasCancelAt ? 'Renew subscription' : 'Update payment method'} - {!hasCancelAt - && ( - - )} -
- {hasPrimeSub && subscription.requires_migration - && ( -
- - - Your prime subscription will be canceled on May 15th unless you replace the - SIM - card in your device. A new SIM card can be ordered from the - shop - . - Use discount code SIMSWAP at checkout to receive a free SIM card. - -
- )} - {hasCancelAt && !device.eligible_features?.prime_data && subscription.plan === 'data' - && ( -
- - - Standard comma prime discontinued for - {deviceTypePretty(device.device_type)} - -
+ {!hasCancelAt && ( + )} +
+ {hasPrimeSub && subscription.requires_migration && ( +
+ + + Your prime subscription will be canceled on May 15th unless you replace the SIM card in your device. A new SIM card can be ordered from the + + shop + + . Use discount code SIMSWAP at checkout to receive a free SIM card. + +
+ )} + {hasCancelAt && !device.eligible_features?.prime_data && subscription.plan === 'data' && ( +
+ + + Standard comma prime discontinued for + {deviceTypePretty(device.device_type)} + +
+ )} )}
- this.setState({ cancelModal: false })} - > + this.setState({ cancelModal: false })}> Cancel prime subscription {this.state.cancelError && ( @@ -485,30 +474,18 @@ class PrimeManage extends Component { {this.state.cancelSuccess}
)} - - {`Device: ${alias} (${dongleId})`} - - - We're sorry to see you go. - - - Your subscription will be cancelled immediately and can be resumed at any time. - + {`Device: ${alias} (${dongleId})`} + We're sorry to see you go. + Your subscription will be cancelled immediately and can be resumed at any time. - diff --git a/src/components/Prime/index.jsx b/src/components/Prime/index.jsx index 6ec1e01f..26879405 100644 --- a/src/components/Prime/index.jsx +++ b/src/components/Prime/index.jsx @@ -19,12 +19,12 @@ const Prime = () => { } if (!device.is_owner && !profile.superuser) { - return (No access); + return No access; } if (device.prime || stripeSuccess) { - return (); + return ; } - return (); + return ; }; export default Prime; diff --git a/src/components/ScrollIntoView/index.jsx b/src/components/ScrollIntoView/index.jsx index 8996201c..7e53de6c 100644 --- a/src/components/ScrollIntoView/index.jsx +++ b/src/components/ScrollIntoView/index.jsx @@ -8,14 +8,14 @@ const ScrollIntoView = ({ onInView, children }) => { const options = { root: null, // relative to the viewport rootMargin: '0px', - threshold: 0.1 // 10% of the target's visibility + threshold: 0.1, // 10% of the target's visibility }; const observer = new IntersectionObserver((entries) => { - entries.forEach(entry => { + entries.forEach((entry) => { if (entry.isIntersecting && !hasDispatched.current) { onInView(); - hasDispatched.current = true + hasDispatched.current = true; } }); }, options); @@ -31,11 +31,7 @@ const ScrollIntoView = ({ onInView, children }) => { }; }, [onInView]); - return ( -
- {children} -
- ); + return
{children}
; }; export default ScrollIntoView; diff --git a/src/components/TimeDisplay/index.jsx b/src/components/TimeDisplay/index.jsx index bcf6c2b1..c4b5f905 100644 --- a/src/components/TimeDisplay/index.jsx +++ b/src/components/TimeDisplay/index.jsx @@ -15,15 +15,7 @@ import { pause, play, seek } from '../../timeline/playback'; import { getSegmentNumber } from '../../utils'; import { isIos } from '../../utils/browser.js'; -const timerSteps = [ - 0.1, - 0.25, - 0.5, - 1, - 2, - 4, - 8, -]; +const timerSteps = [0.1, 0.25, 0.5, 1, 2, 4, 8]; const styles = (theme) => ({ base: { @@ -206,81 +198,50 @@ const TimeDisplay = ({ classes, isThin, onMuteToggle, isMuted, hasAudio }) => { const isThinCls = isThin ? 'isThin' : ''; return ( -
-
- jumpBack(10000) } - aria-label="Jump back 10 seconds" - > +
+
+ jumpBack(10000)} aria-label="Jump back 10 seconds">
-
- jumpForward(10000) } - aria-label="Jump forward 10 seconds" - > +
+ jumpForward(10000)} aria-label="Jump forward 10 seconds">
- { !isThin && ( + {!isThin && ( CURRENT PLAYBACK TIME )} - { getDisplayTime() } + {getDisplayTime()} {!isIos() && ( -
- +
+ - {desiredPlaySpeed} - × + {desiredPlaySpeed}× - +
)} -
- +
+
- - {isMuted - ? () - : ()} + + {isMuted ? : }
-
- - {isPaused - ? () - : ()} +
+ + {isPaused ? : }
diff --git a/src/components/TimeSelect/index.jsx b/src/components/TimeSelect/index.jsx index 6e18dca5..c17d084b 100644 --- a/src/components/TimeSelect/index.jsx +++ b/src/components/TimeSelect/index.jsx @@ -63,22 +63,13 @@ const TimeSelect = (props) => { const changeStart = useCallback((event) => { if (event.target.valueAsDate) { - setStart(new Date( - event.target.valueAsDate.getUTCFullYear(), - event.target.valueAsDate.getUTCMonth(), - event.target.valueAsDate.getUTCDate() - ).getTime()); + setStart(new Date(event.target.valueAsDate.getUTCFullYear(), event.target.valueAsDate.getUTCMonth(), event.target.valueAsDate.getUTCDate()).getTime()); } }, []); const changeEnd = useCallback((event) => { if (event.target.valueAsDate) { - setEnd(new Date( - event.target.valueAsDate.getUTCFullYear(), - event.target.valueAsDate.getUTCMonth(), - event.target.valueAsDate.getUTCDate(), - 23, 59, 59 - ).getTime()); + setEnd(new Date(event.target.valueAsDate.getUTCFullYear(), event.target.valueAsDate.getUTCMonth(), event.target.valueAsDate.getUTCDate(), 23, 59, 59).getTime()); } }, []); @@ -94,48 +85,29 @@ const TimeSelect = (props) => { const endDate = dayjs(end || filter.end).format('YYYY-MM-DD'); return ( - - -
- Start date: - -
-
- End date: - -
- -
- -   - -
-
-
- ); + + +
+ Start date: + +
+
+ End date: + +
+ +
+ +   + +
+
+
+ ); }; export default withStyles(styles)(TimeSelect); diff --git a/src/components/Timeline/index.jsx b/src/components/Timeline/index.jsx index abdd5eb0..496ff727 100644 --- a/src/components/Timeline/index.jsx +++ b/src/components/Timeline/index.jsx @@ -61,7 +61,8 @@ const styles = () => ({ background: theme.palette.states.alertRed, }, }, - '&.bookmark, &.flag': { // TODO: remove flag selector once 14 days expires old events caches + '&.bookmark, &.flag': { + // TODO: remove flag selector once 14 days expires old events caches background: theme.palette.states.userBookmark, zIndex: 1, }, @@ -132,11 +133,7 @@ const styles = () => ({ }, }); -const AlertStatusCodes = [ - 'normal', - 'userPrompt', - 'critical', -]; +const AlertStatusCodes = ['normal', 'userPrompt', 'critical']; function percentFromPointerEvent(ev) { const boundingBox = ev.currentTarget.getBoundingClientRect(); @@ -285,13 +282,7 @@ const Timeline = ({ classes, hasRuler, className, route, thumbnailsVisible, zoom minWidth: '1px', }; const statusCls = event.data.alertStatus ? `${AlertStatusCodes[event.data.alertStatus]}` : ''; - return ( -
- ); + return
; }); }; @@ -302,7 +293,7 @@ const Timeline = ({ classes, hasRuler, className, route, thumbnailsVisible, zoom } const zoomDuration = zoom.end - zoom.start; - const startPerc = (100 * (-zoom.start)) / zoomDuration; + const startPerc = (100 * -zoom.start) / zoomDuration; const widthPerc = (100 * route.duration) / zoomDuration; const style = { @@ -311,7 +302,7 @@ const Timeline = ({ classes, hasRuler, className, route, thumbnailsVisible, zoom }; return (
- { renderRouteEvents(route) } + {renderRouteEvents(route)}
); }; @@ -354,8 +345,8 @@ const Timeline = ({ classes, hasRuler, className, route, thumbnailsVisible, zoom rulerBounds = rulerRef.current.getBoundingClientRect(); } - let hoverString; let - hoverStyle; + let hoverString; + let hoverStyle; if (rulerBounds && hoverX) { const hoverOffset = percentToOffset((hoverX - rulerBounds.x) / rulerBounds.width); hoverStyle = { left: Math.max(-10, Math.min(rulerBounds.width - 70, hoverX - rulerBounds.x - 40)) }; @@ -380,26 +371,18 @@ const Timeline = ({ classes, hasRuler, className, route, thumbnailsVisible, zoom return (
-
-
- { route && renderRoute() } -
+
+
+ {route && renderRoute()} +
-
- { thumbnailsVisible && ( - - ) } +
+ {thumbnailsVisible && }
- { hasRuler && ( + {hasRuler && ( <>
- { draggerStyle &&
} + {draggerStyle &&
}
- { hoverString && ( + {hoverString && (
- { hoverString } + {hoverString}
- ) } + )} - ) } + )}
); diff --git a/src/components/Timeline/thumbnails.jsx b/src/components/Timeline/thumbnails.jsx index b1c866b2..718c83b6 100644 --- a/src/components/Timeline/thumbnails.jsx +++ b/src/components/Timeline/thumbnails.jsx @@ -1,4 +1,3 @@ - import { getSegmentNumber } from '../../utils'; export default function Thumbnails(props) { @@ -72,8 +71,8 @@ export default function Thumbnails(props) { imgArr.push(currSegment); } - return imgArr.map((data, i) => (data.blank - ? ( + return imgArr.map((data, i) => + data.blank ? (
- ) - : ( + ) : (
- ))); -} \ No newline at end of file + ), + ); +} diff --git a/src/components/Timeline/thumbnails.test.js b/src/components/Timeline/thumbnails.test.js index 795de0d5..b8dae529 100644 --- a/src/components/Timeline/thumbnails.test.js +++ b/src/components/Timeline/thumbnails.test.js @@ -19,7 +19,7 @@ const thumbnailBounds = { left: gutter, right: screenWidth - gutter, - width: screenWidth - (gutter * 2), + width: screenWidth - gutter * 2, height: 100, }; @@ -32,13 +32,7 @@ describe('timeline thumbnails', () => { }); it('should check the segment for every image', () => { - render( - , - ); + render(); expect(percentToOffsetMock.mock.calls.length).toBe(10); const imageEntries = screen.getAllByRole('img'); @@ -55,7 +49,7 @@ describe('timeline thumbnails', () => { }); }); - it('doesn\'t render before bounds are set', () => { + it("doesn't render before bounds are set", () => { render( { segment_offsets: Array.from(Array(4).keys()).map((i) => i * 60), }; - render( - , - ); + render(); expect(percentToOffsetMock.mock.calls.length).toBe(10); const imageEntries = screen.getAllByRole('img'); @@ -105,7 +93,7 @@ describe('timeline thumbnails', () => { }); }); - it('works when it\'s supermegaskinny', () => { + it("works when it's supermegaskinny", () => { render( { const prevVisibleCall = useRef(0); const intervalHandle = useRef(null); - const onVisibilityEvent = useCallback((visible) => { - const newDate = Date.now() / 1000; - const dt = newDate - prevVisibleCall.current; - if (visible && (!minInterval || dt > minInterval)) { - prevVisibleCall.current = newDate; - onVisible(); - } + const onVisibilityEvent = useCallback( + (visible) => { + const newDate = Date.now() / 1000; + const dt = newDate - prevVisibleCall.current; + if (visible && (!minInterval || dt > minInterval)) { + prevVisibleCall.current = newDate; + onVisible(); + } - if (!visible && resetOnHidden) { - prevVisibleCall.current = newDate; - } - }, [minInterval, onVisible, resetOnHidden]); + if (!visible && resetOnHidden) { + prevVisibleCall.current = newDate; + } + }, + [minInterval, onVisible, resetOnHidden], + ); const debouncedVisibilityEvent = useRef(debounce(onVisibilityEvent, 1000, true)); diff --git a/src/components/anonymous.jsx b/src/components/anonymous.jsx index be3e3224..c0159282 100644 --- a/src/components/anonymous.jsx +++ b/src/components/anonymous.jsx @@ -1,7 +1,6 @@ /* global AppleID */ - -import {config as AuthConfig, storage as AuthStorage} from '@commaai/my-comma-auth'; +import { config as AuthConfig, storage as AuthStorage } from '@commaai/my-comma-auth'; import { withStyles } from '@material-ui/core/styles'; import Typography from '@material-ui/core/Typography'; import { Component } from 'react'; @@ -125,7 +124,9 @@ class AnonymousLanding extends Component { const { classes } = this.props; const loginAsDemoUser = () => { - AuthStorage.setCommaAccessToken('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEwMzg5NTgwNzM1LCJuYmYiOjE3NDk1ODA3MzUsImlhdCI6MTc0OTU4MDczNSwiaWRlbnRpdHkiOiIwZGVjZGRjZmRmMjQxYTYwIn0.KsDzqJxgkYhAs4tCgrMJIdORyxO0CQNb0gHXIf8aUT0'); + AuthStorage.setCommaAccessToken( + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEwMzg5NTgwNzM1LCJuYmYiOjE3NDk1ODA3MzUsImlhdCI6MTc0OTU4MDczNSwiaWRlbnRpdHkiOiIwZGVjZGRjZmRmMjQxYTYwIn0.KsDzqJxgkYhAs4tCgrMJIdORyxO0CQNb0gHXIf8aUT0', + ); window.location = window.location.origin; }; @@ -137,9 +138,7 @@ class AnonymousLanding extends Component {
 
comma connect - - Manage your comma device, view your drives, and use comma prime features - + Manage your comma device, view your drives, and use comma prime features Sign in with Google @@ -153,12 +152,10 @@ class AnonymousLanding extends Component { Sign in with GitHub - - Make sure to sign in with the same account if you have previously - paired your comma device. - + Make sure to sign in with the same account if you have previously paired your comma device. - Try the demo diff --git a/src/components/explorer.jsx b/src/components/explorer.jsx index 05cb7120..279b5390 100644 --- a/src/components/explorer.jsx +++ b/src/components/explorer.jsx @@ -177,13 +177,11 @@ class ExplorerApp extends Component { const { classes, currentRoute, devices, dongleId } = this.props; const { drawerIsOpen, pairLoading, pairError, pairDongleId, windowWidth } = this.state; - const noDevicesUpsell = (devices?.length === 0 && !dongleId); + const noDevicesUpsell = devices?.length === 0 && !dongleId; const isLarge = noDevicesUpsell || windowWidth > 1080; const sidebarWidth = noDevicesUpsell ? 0 : Math.max(280, windowWidth * 0.2); - const headerHeight = this.state.headerRef - ? this.state.headerRef.getBoundingClientRect().height - : (windowWidth < 640 ? 111 : 66); + const headerHeight = this.state.headerRef ? this.state.headerRef.getBoundingClientRect().height : windowWidth < 640 ? 111 : 66; let containerStyles = { minHeight: `calc(100vh - ${headerHeight}px)`, }; @@ -201,42 +199,33 @@ class ExplorerApp extends Component { return (
- this.setState({ windowWidth: ww }) } /> + this.setState({ windowWidth: ww })} /> - -
- { noDevicesUpsell - ? - : (currentRoute ? : )} + +
+ {noDevicesUpsell ? : currentRoute ? : }
- + Pairing device - { pairLoading && } - { pairDongleId - && ( + {pairLoading && } + {pairDongleId && ( {'Successfully paired device '} - { pairDongleId } + {pairDongleId} - )} - { pairError && { pairError } } - @@ -250,13 +239,11 @@ import { getSegmentRange } from '../url'; const stateToProps = (state, ownProps) => { const seg = getSegmentRange(ownProps.location?.pathname || '/'); - const currentRoute = seg && state.routes && state.routes.find((r) => r.log_id === seg.log_id) || null; + const currentRoute = (seg && state.routes && state.routes.find((r) => r.log_id === seg.log_id)) || null; let zoom = null; if (currentRoute) { const hasTimes = typeof seg.start === 'number' && typeof seg.end === 'number' && !Number.isNaN(seg.start) && !Number.isNaN(seg.end); - zoom = hasTimes - ? { start: seg.start - currentRoute.start_time_utc_millis, end: seg.end - currentRoute.start_time_utc_millis } - : { start: 0, end: currentRoute.duration }; + zoom = hasTimes ? { start: seg.start - currentRoute.start_time_utc_millis, end: seg.end - currentRoute.start_time_utc_millis } : { start: 0, end: currentRoute.duration }; } return { zoom, diff --git a/src/components/utils/InfoTooltip.jsx b/src/components/utils/InfoTooltip.jsx index 265b2438..73a0e83c 100644 --- a/src/components/utils/InfoTooltip.jsx +++ b/src/components/utils/InfoTooltip.jsx @@ -71,10 +71,7 @@ class InfoTooltip extends Component { } render() { - const { - classes, - title, - } = this.props; + const { classes, title } = this.props; const { arrowRef, open } = this.state; return ( @@ -90,12 +87,12 @@ class InfoTooltip extends Component { }, }, }} - title={( + title={ <> {title} - )} + } onOpen={this.onTooltipOpen} onClose={this.onTooltipClose} open={open} diff --git a/src/components/utils/SwitchLoading.jsx b/src/components/utils/SwitchLoading.jsx index 81e36f3d..bff7127a 100644 --- a/src/components/utils/SwitchLoading.jsx +++ b/src/components/utils/SwitchLoading.jsx @@ -12,14 +12,15 @@ const styles = () => ({ }, switchThumbLoading: { '&::before': { - content: '\'\'', + content: "''", display: 'inline-block', height: '100%', width: '100%', - backgroundImage: 'url(\'data:image/svg+xml;utf8,' - + '' - + '\')', + backgroundImage: + "url('data:image/svg+xml;utf8," + + '' + + '\')', strokeDasharray: '80px, 200px', animation: 'circular-rotate 1s linear infinite', }, @@ -90,38 +91,25 @@ class SwitchLoading extends Component { const { classes, checked, label, loading, tooltip } = this.props; const isChecked = this.state.checked !== null ? this.state.checked : checked; - const loadingCls = (loading || this.state.loading) ? { icon: classes.switchThumbLoading } : {}; + const loadingCls = loading || this.state.loading ? { icon: classes.switchThumbLoading } : {}; - const switchEl = ( - - ); + const switchEl = ; return ( -
- - { tooltip && } - { Boolean(this.state.error) && ( - <> - this.setState({ errorPopper: null }) } - onMouseEnter={ (ev) => this.setState({ errorPopper: ev.target }) } - /> - - { this.state.error } - - +
+ + {tooltip && } + {Boolean(this.state.error) && ( + <> + this.setState({ errorPopper: null })} + onMouseEnter={(ev) => this.setState({ errorPopper: ev.target })} + /> + + {this.state.error} + + )}
); diff --git a/src/devtools.js b/src/devtools.js index 531ffe84..8c17ffd4 100644 --- a/src/devtools.js +++ b/src/devtools.js @@ -1,11 +1,7 @@ import { compose } from 'redux'; function getComposeEnhancers() { - if ( - import.meta.env.VITE_APP_DEVTOOLS && - typeof window !== 'undefined' && - window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ - ) { + if (import.meta.env.VITE_APP_DEVTOOLS && typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) { return window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__; } return compose; diff --git a/src/history.js b/src/history.js index 2de80a22..a1c586c7 100644 --- a/src/history.js +++ b/src/history.js @@ -2,4 +2,3 @@ import { createBrowserHistory } from 'history'; export const history = createBrowserHistory(); export default history; - diff --git a/src/icons/index.jsx b/src/icons/index.jsx index cfd42b79..3e58d8ab 100644 --- a/src/icons/index.jsx +++ b/src/icons/index.jsx @@ -7,12 +7,7 @@ import AuthGithubIcon from './auth_github.png'; import AuthGoogleIcon from './auth_google.png'; import IosShareIcon from './ios_share.png'; -export { - AuthAppleIcon, - AuthGithubIcon, - AuthGoogleIcon, - IosShareIcon, -}; +export { AuthAppleIcon, AuthGithubIcon, AuthGoogleIcon, IosShareIcon }; export const ArrowBackBold = (props) => ( @@ -124,21 +119,9 @@ function chevronPath(rotation = 270) { ); } -export const ChevronIcon = (props) => ( - - {chevronPath(270)} - -); +export const ChevronIcon = (props) => {chevronPath(270)}; export const DownArrow = ChevronIcon; -export const UpArrow = (props) => ( - - {chevronPath(90)} - -); +export const UpArrow = (props) => {chevronPath(90)}; -export const RightArrow = (props) => ( - - {chevronPath(180)} - -); +export const RightArrow = (props) => {chevronPath(180)}; diff --git a/src/index.css b/src/index.css index d12286c9..b4dab9a8 100644 --- a/src/index.css +++ b/src/index.css @@ -5,7 +5,7 @@ */ -@import url('https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap'); +@import url("https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap"); @tailwind base; @tailwind components; @@ -32,8 +32,8 @@ html { } body { - background: #16181A; - font-family: 'Inter', sans-serif; + background: #16181a; + font-family: "Inter", sans-serif; scrollbar-gutter: stable; overflow-y: scroll; margin: 0; diff --git a/src/index.jsx b/src/index.jsx index cf532f68..88383d00 100644 --- a/src/index.jsx +++ b/src/index.jsx @@ -24,12 +24,12 @@ if (import.meta.env.VITE_APP_GIT_TIMESTAMP) { console.info('commit date:', import.meta.env.VITE_APP_GIT_TIMESTAMP || 'unknown'); } -ReactDOM.createRoot(document.getElementById('root')).render(( +ReactDOM.createRoot(document.getElementById('root')).render( - -)); + , +); // Install router -> store sync installHistorySync(store, history); diff --git a/src/initialState.js b/src/initialState.js index a08339ac..5560a40a 100644 --- a/src/initialState.js +++ b/src/initialState.js @@ -5,7 +5,7 @@ export function getDefaultFilter() { d.setHours(d.getHours() + 1, 0, 0, 0); return { - start: (new Date(d.getTime() - 1000 * 60 * 60 * 24 * 14)).getTime(), + start: new Date(d.getTime() - 1000 * 60 * 60 * 24 * 14).getTime(), end: d.getTime(), }; } @@ -13,10 +13,10 @@ export function getDefaultFilter() { export default { dongleId: getDongleID(window.location.pathname), - desiredPlaySpeed: 1, // speed set by user + desiredPlaySpeed: 1, // speed set by user isBufferingVideo: true, // if we're currently buffering for more data - offset: null, // in milliseconds, relative to current loop start or 0 - startTime: Date.now(), // millisecond timestamp in which play began + offset: null, // in milliseconds, relative to current loop start or 0 + startTime: Date.now(), // millisecond timestamp in which play began routes: null, routesMeta: { diff --git a/src/navigation.js b/src/navigation.js index c2c15aff..78334c21 100644 --- a/src/navigation.js +++ b/src/navigation.js @@ -9,4 +9,3 @@ export function replace(path) { } export default { navigate, replace }; - diff --git a/src/reducers/globalState.js b/src/reducers/globalState.js index 47e39aa5..4a658847 100644 --- a/src/reducers/globalState.js +++ b/src/reducers/globalState.js @@ -103,9 +103,7 @@ export default function reducer(_state, action) { case Types.ACTION_UPDATE_DEVICES: state = { ...state, - devices: action.devices - .map(populateFetchedAt) - .sort(deviceCompareFn), + devices: action.devices.map(populateFetchedAt).sort(deviceCompareFn), }; if (state.dongleId) { const newDevice = state.devices.find((d) => d.dongle_id === state.dongleId); @@ -145,7 +143,7 @@ export default function reducer(_state, action) { eventsMap[action.fullname] = { events: action.events, videoStartOffset, - } + }; if (state.routes) { state.routes = state.routes.map((route) => { const ev = eventsMap[route.fullname]; @@ -165,7 +163,7 @@ export default function reducer(_state, action) { locationMap[action.fullname] = { location: action.location, locationKey: action.locationKey, - } + }; if (state.routes) { state.routes = state.routes.map((route) => { const loc = locationMap[route.fullname]; @@ -230,7 +228,8 @@ export default function reducer(_state, action) { } break; case Types.ACTION_PRIME_SUBSCRIPTION: - if (action.dongleId !== state.dongleId) { // ignore outdated info + if (action.dongleId !== state.dongleId) { + // ignore outdated info break; } state = { @@ -281,21 +280,26 @@ export default function reducer(_state, action) { .map((id) => state.filesUploading[id].fileName); state.files = Object.keys(state.files) .filter((fileName) => !cancelFileNames.includes(fileName)) - .reduce((obj, fileName) => { obj[fileName] = state.files[fileName]; return obj; }, {}); + .reduce((obj, fileName) => { + obj[fileName] = state.files[fileName]; + return obj; + }, {}); } state.filesUploading = Object.keys(state.filesUploading) .filter((id) => !action.ids.includes(id)) - .reduce((obj, id) => { obj[id] = state.filesUploading[id]; return obj; }, {}); + .reduce((obj, id) => { + obj[id] = state.filesUploading[id]; + return obj; + }, {}); break; case Types.ACTION_ROUTES_METADATA: // merge existing routes' event and location info with new routes state.routes = action.routes.map((route) => { - const existingRoute = state.lastRoutes ? - state.lastRoutes.find((r) => r.fullname === route.fullname) : {}; + const existingRoute = state.lastRoutes ? state.lastRoutes.find((r) => r.fullname === route.fullname) : {}; return { ...existingRoute, ...route, - } + }; }); state.routesMeta = { dongleId: action.dongleId, diff --git a/src/selectors/route.js b/src/selectors/route.js index 96f7f4fb..a94b289a 100644 --- a/src/selectors/route.js +++ b/src/selectors/route.js @@ -38,7 +38,7 @@ export function selectRouteZoom(state) { export function selectCurrentRoute(state) { const seg = getSegmentRange(selectPathname()); if (!seg) return null; - return state.routes && state.routes.find((r) => r.log_id === seg.log_id) || null; + return (state.routes && state.routes.find((r) => r.log_id === seg.log_id)) || null; } export function selectIsViewingRoute(state) { diff --git a/src/store.js b/src/store.js index ea664a1a..796a6ee1 100644 --- a/src/store.js +++ b/src/store.js @@ -5,13 +5,7 @@ import { history } from './history'; import initialState from './initialState'; import rootReducer from './reducers'; -const store = Redux.createStore( - rootReducer, - initialState, - composeEnhancers(Redux.applyMiddleware( - thunk, - )), -); +const store = Redux.createStore(rootReducer, initialState, composeEnhancers(Redux.applyMiddleware(thunk))); export { history }; export default store; diff --git a/src/timeline/index.js b/src/timeline/index.js index 22724754..4efd115e 100644 --- a/src/timeline/index.js +++ b/src/timeline/index.js @@ -17,7 +17,7 @@ export function currentOffset(state = null) { offset = state.loop.startTime; } else { const playSpeed = state.isBufferingVideo ? 0 : state.desiredPlaySpeed; - offset = state.offset + ((Date.now() - state.startTime) * playSpeed); + offset = state.offset + (Date.now() - state.startTime) * playSpeed; } if (offset !== null && state.loop?.startTime) { @@ -30,4 +30,4 @@ export function currentOffset(state = null) { } } return offset; -} \ No newline at end of file +} diff --git a/src/timeline/playback.js b/src/timeline/playback.js index 84438b30..df7858e3 100644 --- a/src/timeline/playback.js +++ b/src/timeline/playback.js @@ -20,7 +20,7 @@ export function reducer(_state, action) { if (loopOffset !== null) { if (state.offset < loopOffset) { state.offset = loopOffset; - } else if (state.offset > (loopOffset + state.loop.duration)) { + } else if (state.offset > loopOffset + state.loop.duration) { state.offset = loopOffset + state.loop.duration; } } @@ -74,8 +74,7 @@ export function reducer(_state, action) { break; } - if (state.currentRoute && state.currentRoute.videoStartOffset && state.loop - && state.loop.startTime === 0) { + if (state.currentRoute && state.currentRoute.videoStartOffset && state.loop && state.loop.startTime === 0) { const loopRouteOffset = state.loop.startTime; if (state.currentRoute.videoStartOffset > loopRouteOffset) { state.loop = { diff --git a/src/timeline/playback.test.js b/src/timeline/playback.test.js index f363f208..4279751c 100644 --- a/src/timeline/playback.test.js +++ b/src/timeline/playback.test.js @@ -76,10 +76,7 @@ describe('playback', () => { // set up loop state = reducer(state, play()); - state = reducer(state, selectLoop( - 1000, - 2000, - )); + state = reducer(state, selectLoop(1000, 2000)); expect(state.loop.startTime).toEqual(1000); // seek past loop end boundary a @@ -94,10 +91,7 @@ describe('playback', () => { // set up loop state = reducer(state, play()); - state = reducer(state, selectLoop( - 1000, - 2000, - )); + state = reducer(state, selectLoop(1000, 2000)); expect(state.loop.startTime).toEqual(1000); // seek past loop end boundary a @@ -131,4 +125,4 @@ describe('playback', () => { expect(state.desiredPlaySpeed).toEqual(2); }); -}); \ No newline at end of file +}); diff --git a/src/timeline/segments.js b/src/timeline/segments.js index 88aa4660..80c192fc 100644 --- a/src/timeline/segments.js +++ b/src/timeline/segments.js @@ -6,8 +6,7 @@ export function hasRoutesData(state) { // new users without devices won't have segment metadata return true; } - if (!state.routesMeta || !state.routesMeta.dongleId || state.routesMeta.start === null - || state.routesMeta.end === null) { + if (!state.routesMeta || !state.routesMeta.dongleId || state.routesMeta.start === null || state.routesMeta.end === null) { console.debug('No routes data at all'); return false; } @@ -30,4 +29,4 @@ export function hasRoutesData(state) { } return true; -} \ No newline at end of file +} diff --git a/src/timeline/segments.test.js b/src/timeline/segments.test.js index 4f5c253b..af71d87a 100644 --- a/src/timeline/segments.test.js +++ b/src/timeline/segments.test.js @@ -5,27 +5,34 @@ import { hasRoutesData } from './segments'; export const SEGMENT_LENGTH = 1000 * 60; -const routes = [{ - fullname: '99c94dc769b5d96e|2018-04-09--10-10-00', - offset: 36600000, - duration: 2558000, - segment_numbers: Array.from(Array(43).keys()), - segment_offsets: Array.from(Array(43).keys()).map((i) => i * SEGMENT_LENGTH + 36600000), - events: [{ - time: 36600123, - type: 'event', - }], -}, { - fullname: '99c94dc769b5d96e|2018-04-09--11-29-08', - offset: 41348000, - duration: 214000, - segment_numbers: Array.from(Array(4).keys()), - segment_offsets: Array.from(Array(4).keys()).map((i) => i * SEGMENT_LENGTH + 41348000), - events: [{ - time: 41348123, - type: 'event', - }], -}]; +const routes = [ + { + fullname: '99c94dc769b5d96e|2018-04-09--10-10-00', + offset: 36600000, + duration: 2558000, + segment_numbers: Array.from(Array(43).keys()), + segment_offsets: Array.from(Array(43).keys()).map((i) => i * SEGMENT_LENGTH + 36600000), + events: [ + { + time: 36600123, + type: 'event', + }, + ], + }, + { + fullname: '99c94dc769b5d96e|2018-04-09--11-29-08', + offset: 41348000, + duration: 214000, + segment_numbers: Array.from(Array(4).keys()), + segment_offsets: Array.from(Array(4).keys()).map((i) => i * SEGMENT_LENGTH + 41348000), + events: [ + { + time: 41348123, + type: 'event', + }, + ], + }, +]; describe('segments', () => { it('finds current segment', async () => { @@ -36,66 +43,78 @@ describe('segments', () => { it('can check if it has segment metadata', () => { expect(hasRoutesData()).toBe(false); expect(hasRoutesData({})).toBe(false); - expect(hasRoutesData({ - routesMeta: {}, - })).toBe(false); - expect(hasRoutesData({ - routes: [], - routesMeta: { - dongleId: 'asdfasdf', - }, - })).toBe(false); - expect(hasRoutesData({ - routes: [], - routesMeta: { + expect( + hasRoutesData({ + routesMeta: {}, + }), + ).toBe(false); + expect( + hasRoutesData({ + routes: [], + routesMeta: { + dongleId: 'asdfasdf', + }, + }), + ).toBe(false); + expect( + hasRoutesData({ + routes: [], + routesMeta: { + dongleId: 'asdfasdf', + start: 10, + end: 20, + }, + filter: { + start: 0, + end: 30, + }, dongleId: 'asdfasdf', - start: 10, - end: 20, - }, - filter: { - start: 0, - end: 30, - }, - dongleId: 'asdfasdf', - })).toBe(false); - expect(hasRoutesData({ - routes: [], - routesMeta: { + }), + ).toBe(false); + expect( + hasRoutesData({ + routes: [], + routesMeta: { + dongleId: 'asdfasdf', + start: 0, + end: 20, + }, + filter: { + start: 10, + end: 30, + }, dongleId: 'asdfasdf', - start: 0, - end: 20, - }, - filter: { - start: 10, - end: 30, - }, - dongleId: 'asdfasdf', - })).toBe(false); - expect(hasRoutesData({ - routes: [], - routesMeta: { + }), + ).toBe(false); + expect( + hasRoutesData({ + routes: [], + routesMeta: { + dongleId: 'asdfasdf', + start: 10, + end: 30, + }, + filter: { + start: 0, + end: 20, + }, dongleId: 'asdfasdf', - start: 10, - end: 30, - }, - filter: { - start: 0, - end: 20, - }, - dongleId: 'asdfasdf', - })).toBe(false); - expect(hasRoutesData({ - routes: [], - routesMeta: { + }), + ).toBe(false); + expect( + hasRoutesData({ + routes: [], + routesMeta: { + dongleId: 'asdfasdf', + start: 0, + end: 30, + }, + filter: { + start: 10, + end: 20, + }, dongleId: 'asdfasdf', - start: 0, - end: 30, - }, - filter: { - start: 10, - end: 20, - }, - dongleId: 'asdfasdf', - })).toBe(true); + }), + ).toBe(true); }); -}); \ No newline at end of file +}); diff --git a/src/utils/geocode.test.js b/src/utils/geocode.test.js index 6d2d32d8..c76ef806 100644 --- a/src/utils/geocode.test.js +++ b/src/utils/geocode.test.js @@ -3,11 +3,7 @@ import { priorityGetContext, reverseLookup } from './geocode'; describe('priorityGetContext', () => { it('should return the first context with a priority', () => { - const contexts = [ - { id: 'place.123' }, - { id: 'locality.123' }, - { id: 'district.123' }, - ]; + const contexts = [{ id: 'place.123' }, { id: 'locality.123' }, { id: 'district.123' }]; expect(priorityGetContext(contexts)).toEqual(contexts[0]); }); }); @@ -33,7 +29,7 @@ describe('reverseLookup', () => { // details: 'Washington, DC 20500, United States', // place: 'White House Lawn', // }); - expect(await reverseLookup([-0.106640, 51.514209], true)).toEqual({ + expect(await reverseLookup([-0.10664, 51.514209], true)).toEqual({ details: 'London, EC4A 2BB, United Kingdom', place: 'Fleet St', }); diff --git a/src/utils/index.js b/src/utils/index.js index 40effe53..e3f9437a 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -42,8 +42,8 @@ export function toBool(item) { } export function formatDriveDuration(duration) { - const hours = Math.floor((duration / (1000 * 60 * 60))) % 24; - const minutes = Math.floor((duration / (1000 * 60))) % 60; + const hours = Math.floor(duration / (1000 * 60 * 60)) % 24; + const minutes = Math.floor(duration / (1000 * 60)) % 60; return `${hours > 0 ? `${hours} hr ` : ''}${minutes} min`; } @@ -81,7 +81,7 @@ export function deviceIsOnline(device) { if (!device || !device.last_athena_ping) { return false; } - return device.last_athena_ping >= (device.fetched_at - 120); + return device.last_athena_ping >= device.fetched_at - 120; } export function deviceOnCellular(device) { @@ -190,5 +190,5 @@ export function getSegmentNumber(route, offset) { offset = currentOffset(); } - return Math.floor(offset / (60*1000)); + return Math.floor(offset / (60 * 1000)); } From 468f1f7021d041c32a69e8373f785c78b23ac7c1 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 2 Nov 2025 18:04:29 -0800 Subject: [PATCH 15/26] fix tests --- .github/workflows/test.yaml | 6 ++--- AGENTS.md | 5 ++-- .../Dashboard/DriveListItem.test.js | 26 ++++++++++--------- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index b9c14d81..15c013b0 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -26,10 +26,10 @@ jobs: run: bun run lint - name: Run unit tests - run: bun run test + run: bun run jest - - name: Run end-to-end tests - run: bun run test-puppeteer-build + #- name: Run end-to-end tests + # run: bun run test-puppeteer-build # bundle_size: # runs-on: ubuntu-latest diff --git a/AGENTS.md b/AGENTS.md index cb28e24b..a42db598 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -11,8 +11,9 @@ your loop is: for all changes, make sure to: -- run the tests -- run the linter and formatter ("bun lint") +- run the tests: bun run jest +- run the linter: bun lint +- run the formatter: bun format some more tips: - always prioritize the simple, straightforward changes over risky big ones. diff --git a/src/components/Dashboard/DriveListItem.test.js b/src/components/Dashboard/DriveListItem.test.js index 47769e2c..d2badf68 100644 --- a/src/components/Dashboard/DriveListItem.test.js +++ b/src/components/Dashboard/DriveListItem.test.js @@ -2,6 +2,7 @@ import { render, screen } from '@testing-library/react'; import * as Redux from 'redux'; +import { Provider } from 'react-redux'; import thunk from 'redux-thunk'; import DriveListItem from './DriveListItem'; @@ -21,18 +22,19 @@ const store = Redux.createStore((state) => { describe('drive list items', () => { it('has DriveEntry class', () => { render( - , + + + , ); expect(screen.getByRole('link')).toHaveClass('DriveEntry'); }); From 565d17a054274337d51e4feaf27368c806e09c1f Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 2 Nov 2025 18:19:00 -0800 Subject: [PATCH 16/26] lil more --- src/components/Dashboard/index.jsx | 4 +- src/components/IosPwaPopup/index.jsx | 137 ++++++++++++------------ src/components/TimeDisplay/index.jsx | 5 +- src/components/anonymous.jsx | 6 +- src/components/utils/InfoTooltip.jsx | 99 +++++++---------- src/components/utils/PullDownReload.jsx | 124 ++++++++++----------- src/components/utils/SwitchLoading.jsx | 96 +++++++---------- 7 files changed, 208 insertions(+), 263 deletions(-) diff --git a/src/components/Dashboard/index.jsx b/src/components/Dashboard/index.jsx index 2800953b..28787239 100644 --- a/src/components/Dashboard/index.jsx +++ b/src/components/Dashboard/index.jsx @@ -9,9 +9,9 @@ import DriveList from './DriveList'; const Prime = lazy(() => import('../Prime')); const DashboardLoading = () => ( - + - + ); diff --git a/src/components/IosPwaPopup/index.jsx b/src/components/IosPwaPopup/index.jsx index 48d3be08..340e68f7 100644 --- a/src/components/IosPwaPopup/index.jsx +++ b/src/components/IosPwaPopup/index.jsx @@ -2,8 +2,8 @@ import MyCommaAuth from '@commaai/my-comma-auth'; import { Typography, withStyles } from '@material-ui/core'; import { Clear } from '@material-ui/icons'; import localforage from 'localforage'; -import { Component } from 'react'; -import { withRouter } from 'react-router'; +import { useCallback, useEffect, useRef, useState } from 'react'; +import { useLocation } from 'react-router'; import Colors from '../../colors'; import { IosShareIcon } from '../../icons'; @@ -47,87 +47,82 @@ const styles = () => ({ }, }); -class IosPwaPopup extends Component { - constructor(props) { - super(props); +const IosPwaPopup = ({ classes }) => { + const [show, setShow] = useState(false); + const windowEventsRef = useRef(0); + const location = useLocation(); - this.state = { - show: false, - }; - - this.hide = this.hide.bind(this); - this.onWindowClick = this.onWindowClick.bind(this); + const hide = useCallback(() => { + try { + localforage.setItem('hideIosPwaPopup', true); + } catch (_err) { + // pass + } + setShow(false); + }, []); - this.windowEvents = 0; - } + const onWindowClick = useCallback(() => { + windowEventsRef.current += 1; + if (windowEventsRef.current >= 3) { + hide(); + } + }, [hide]); - async componentDidMount() { - if (window && window.navigator) { - const isStandalone = window.navigator.standalone === true; - if (isIos() && !isStandalone && MyCommaAuth.isAuthenticated()) { - let isHidden; - try { - isHidden = await localforage.getItem('hideIosPwaPopup'); - } catch (_err) { - isHidden = true; + // Check if popup should be shown on mount + useEffect(() => { + const checkShowPopup = async () => { + if (window && window.navigator) { + const isStandalone = window.navigator.standalone === true; + if (isIos() && !isStandalone && MyCommaAuth.isAuthenticated()) { + let isHidden; + try { + isHidden = await localforage.getItem('hideIosPwaPopup'); + } catch (_err) { + isHidden = true; + } + setShow(!isHidden); } - this.setState({ show: !isHidden }); } - } - } + }; - async componentDidUpdate(prevProps, prevState) { - if (!prevState.show && this.state.show) { - window.addEventListener('click', this.onWindowClick); - } else if (prevState.show && !this.state.show) { - window.removeEventListener('click', this.onWindowClick); - } + checkShowPopup(); + }, []); - if (prevProps.location?.pathname !== this.props.location?.pathname) { - this.hide(); + // Add/remove window click listener based on show state + useEffect(() => { + if (show) { + window.addEventListener('click', onWindowClick); + return () => { + window.removeEventListener('click', onWindowClick); + }; } - } - - componentWillUnmount() { - window.removeEventListener('click', this.onWindowClick); - } + }, [show, onWindowClick]); - onWindowClick() { - this.windowEvents += 1; - if (this.windowEvents >= 3) { - this.hide(); + // Hide on route change (after initial mount) + const prevPathnameRef = useRef(location.pathname); + useEffect(() => { + if (prevPathnameRef.current !== location.pathname) { + hide(); } - } + prevPathnameRef.current = location.pathname; + }, [location.pathname, hide]); - hide() { - try { - localforage.setItem('hideIosPwaPopup', true); - } catch (_err) { - // pass - } - this.setState({ show: false }); + if (!show) { + return null; } - render() { - const { classes } = this.props; - const { show } = this.state; - if (!show) { - return null; - } - - return ( -
-
- - Add to home screen - - Install this webapp on your home screen:
- tap share and then ‘Add to Home Screen’ -
-
+ return ( +
+
+ + Add to home screen + + Install this webapp on your home screen:
+ tap share and then ‘Add to Home Screen’ +
- ); - } -} +
+ ); +}; -export default withRouter(withStyles(styles)(IosPwaPopup)); +export default withStyles(styles)(IosPwaPopup); diff --git a/src/components/TimeDisplay/index.jsx b/src/components/TimeDisplay/index.jsx index c4b5f905..9074880f 100644 --- a/src/components/TimeDisplay/index.jsx +++ b/src/components/TimeDisplay/index.jsx @@ -88,6 +88,9 @@ const styles = (theme) => ({ display: 'block', flexGrow: 1, }, + playbackLabel: { + paddingTop: 4, + }, }); const TimeDisplay = ({ classes, isThin, onMuteToggle, isMuted, hasAudio }) => { @@ -210,7 +213,7 @@ const TimeDisplay = ({ classes, isThin, onMuteToggle, isMuted, hasAudio }) => {
{!isThin && ( - + CURRENT PLAYBACK TIME )} diff --git a/src/components/anonymous.jsx b/src/components/anonymous.jsx index c0159282..19199059 100644 --- a/src/components/anonymous.jsx +++ b/src/components/anonymous.jsx @@ -88,14 +88,14 @@ const styles = () => ({ }); class AnonymousLanding extends Component { - UNSAFE_componentWillMount() { + componentDidMount() { + // Set default redirectURL from pathname if not already set if (typeof window !== 'undefined' && typeof window.sessionStorage !== 'undefined' && sessionStorage.getItem('redirectURL') === null) { const { pathname } = this.props; sessionStorage.setItem('redirectURL', pathname); } - } - componentDidMount() { + // Override with query param 'r' if present const q = typeof window !== 'undefined' ? new URLSearchParams(window.location.search) : new URLSearchParams(''); if (q.has('r')) { sessionStorage.setItem('redirectURL', q.get('r')); diff --git a/src/components/utils/InfoTooltip.jsx b/src/components/utils/InfoTooltip.jsx index 73a0e83c..aed49b52 100644 --- a/src/components/utils/InfoTooltip.jsx +++ b/src/components/utils/InfoTooltip.jsx @@ -1,5 +1,5 @@ import { ClickAwayListener, Tooltip, Typography, withStyles } from '@material-ui/core'; -import { Component } from 'react'; +import { useState } from 'react'; import { InfoOutline } from '../../icons'; @@ -42,68 +42,51 @@ const styles = (theme) => ({ }, }); -class InfoTooltip extends Component { - constructor(props) { - super(props); +const InfoTooltip = ({ classes, title }) => { + const [arrowRef, setArrowRef] = useState(null); + const [open, setOpen] = useState(false); - this.state = { - arrowRef: null, - open: false, - }; + const handleArrowRef = (node) => { + setArrowRef(node); + }; - this.handleArrowRef = this.handleArrowRef.bind(this); - this.onTooltipOpen = this.onTooltipOpen.bind(this); - this.onTooltipClose = this.onTooltipClose.bind(this); - } + const onTooltipOpen = () => { + setOpen(true); + }; - handleArrowRef(node) { - this.setState({ - arrowRef: node, - }); - } + const onTooltipClose = () => { + setOpen(false); + }; - onTooltipOpen() { - this.setState({ open: true }); - } - - onTooltipClose() { - this.setState({ open: false }); - } - - render() { - const { classes, title } = this.props; - const { arrowRef, open } = this.state; - - return ( - - + - {title} - - - } - onOpen={this.onTooltipOpen} - onClose={this.onTooltipClose} - open={open} - classes={{ tooltip: classes.tooltip, popper: classes.arrowPopper }} - placement="top" - > - - - - ); - } -} + }, + }} + title={ + <> + {title} + + + } + onOpen={onTooltipOpen} + onClose={onTooltipClose} + open={open} + classes={{ tooltip: classes.tooltip, popper: classes.arrowPopper }} + placement="top" + > + + + + ); +}; export default withStyles(styles)(InfoTooltip); diff --git a/src/components/utils/PullDownReload.jsx b/src/components/utils/PullDownReload.jsx index 5a782817..bc742a4c 100644 --- a/src/components/utils/PullDownReload.jsx +++ b/src/components/utils/PullDownReload.jsx @@ -1,6 +1,6 @@ import { withStyles } from '@material-ui/core'; import ReplayIcon from '@material-ui/icons/Replay'; -import React, { Component } from 'react'; +import { useCallback, useEffect, useRef, useState } from 'react'; import Colors from '../../colors'; import { isIos } from '../../utils/browser.js'; @@ -21,93 +21,79 @@ const styles = () => ({ }, }); -class PullDownReload extends Component { - constructor(props) { - super(props); +const PullDownReload = ({ classes }) => { + const [startY, setStartY] = useState(null); + const [reloading, setReloading] = useState(false); + const dragEl = useRef(null); - this.state = { - startY: null, - reloading: false, - }; - - this.dragEl = React.createRef(null); - - this.touchStart = this.touchStart.bind(this); - this.touchMove = this.touchMove.bind(this); - this.touchEnd = this.touchEnd.bind(this); - } - - async componentDidMount() { - if (window && window.navigator) { - const isStandalone = window.navigator.standalone === true; - if (isIos() && isStandalone) { - document.addEventListener('touchstart', this.touchStart, { passive: false }); - document.addEventListener('touchmove', this.touchMove, { passive: false }); - document.addEventListener('touchend', this.touchEnd, { passive: false }); - } - } - } - - componentWillUnmount() { - document.removeEventListener('touchstart', this.touchStart); - document.removeEventListener('touchmove', this.touchMove); - document.removeEventListener('touchend', this.touchEnd); - } - - touchStart(ev) { + const touchStart = useCallback((ev) => { if (document.scrollingElement.scrollTop !== 0 || ev.defaultPrevented) { return; } - this.setState({ startY: ev.touches[0].pageY }); - } + setStartY(ev.touches[0].pageY); + }, []); - touchMove(ev) { - const { startY } = this.state; - const { current: el } = this.dragEl; - if (startY === null || !el) { - return; - } + const touchMove = useCallback( + (ev) => { + const el = dragEl.current; + if (startY === null || !el) { + return; + } - const top = Math.min((ev.touches[0].pageY - startY) / 2 - 48, 32); - el.style.transition = 'unset'; - el.style.top = `${top}px`; - if (ev.touches[0].pageY - startY > 0) { - ev.preventDefault(); - } else { - this.setState({ startY: null }); - el.style.transition = 'top 0.1s'; - el.style.top = '-48px'; - } - } + const top = Math.min((ev.touches[0].pageY - startY) / 2 - 48, 32); + el.style.transition = 'unset'; + el.style.top = `${top}px`; + if (ev.touches[0].pageY - startY > 0) { + ev.preventDefault(); + } else { + setStartY(null); + el.style.transition = 'top 0.1s'; + el.style.top = '-48px'; + } + }, + [startY], + ); - touchEnd() { - const { reloading, startY } = this.state; - const { current: el } = this.dragEl; + const touchEnd = useCallback(() => { + const el = dragEl.current; if (startY === null || !el) { return; } const top = parseInt(el.style.top.substring(0, el.style.top.length - 2), 10); if (top >= 32 && !reloading) { - this.setState({ reloading: true }); + setReloading(true); window.location.reload(); } else { - this.setState({ startY: null }); + setStartY(null); el.style.transition = 'top 0.1s'; el.style.top = '-48px'; } - } + }, [startY, reloading]); - render() { - const { classes } = this.props; - - return ( -
- -
- ); - } -} + useEffect(() => { + if (window && window.navigator) { + const isStandalone = window.navigator.standalone === true; + if (isIos() && isStandalone) { + document.addEventListener('touchstart', touchStart, { passive: false }); + document.addEventListener('touchmove', touchMove, { passive: false }); + document.addEventListener('touchend', touchEnd, { passive: false }); + + return () => { + document.removeEventListener('touchstart', touchStart); + document.removeEventListener('touchmove', touchMove); + document.removeEventListener('touchend', touchEnd); + }; + } + } + }, [touchStart, touchMove, touchEnd]); + + return ( +
+ +
+ ); +}; export default withStyles(styles)(PullDownReload); diff --git a/src/components/utils/SwitchLoading.jsx b/src/components/utils/SwitchLoading.jsx index bff7127a..ac66bd2f 100644 --- a/src/components/utils/SwitchLoading.jsx +++ b/src/components/utils/SwitchLoading.jsx @@ -1,5 +1,5 @@ import { FormControlLabel, Popper, Switch, Typography, withStyles } from '@material-ui/core'; -import { Component } from 'react'; +import { useState } from 'react'; import Colors from '../../colors'; import { ErrorOutline } from '../../icons'; @@ -45,75 +45,53 @@ const styles = () => ({ }, }); -class SwitchLoading extends Component { - constructor(props) { - super(props); +const SwitchLoading = ({ classes, checked, label, loading, tooltip, onChange: propsOnChange }) => { + const [internalLoading, setInternalLoading] = useState(false); + const [internalChecked, setInternalChecked] = useState(null); + const [error, setError] = useState(null); + const [errorPopper, setErrorPopper] = useState(null); - this.state = { - loading: false, - checked: null, - error: null, - errorPopper: null, - }; - - this.onChange = this.onChange.bind(this); - } - - async onChange(ev) { - if (this.state.loading) { + const onChange = async (ev) => { + if (internalLoading) { return; } - this.setState({ - loading: true, - checked: ev.target.checked, - error: null, - }); + setInternalLoading(true); + setInternalChecked(ev.target.checked); + setError(null); - const res = await this.props.onChange(ev); + const res = await propsOnChange(ev); if (res?.error) { - this.setState({ - loading: false, - checked: null, - error: res.error, - }); + setInternalLoading(false); + setInternalChecked(null); + setError(res.error); return; } - this.setState({ - loading: false, - checked: null, - error: null, - }); - } - - render() { - const { classes, checked, label, loading, tooltip } = this.props; + setInternalLoading(false); + setInternalChecked(null); + setError(null); + }; - const isChecked = this.state.checked !== null ? this.state.checked : checked; - const loadingCls = loading || this.state.loading ? { icon: classes.switchThumbLoading } : {}; + const isChecked = internalChecked !== null ? internalChecked : checked; + const loadingCls = loading || internalLoading ? { icon: classes.switchThumbLoading } : {}; - const switchEl = ; + const switchEl = ; - return ( -
- - {tooltip && } - {Boolean(this.state.error) && ( - <> - this.setState({ errorPopper: null })} - onMouseEnter={(ev) => this.setState({ errorPopper: ev.target })} - /> - - {this.state.error} - - - )} -
- ); - } -} + return ( +
+ + {tooltip && } + {Boolean(error) && ( + <> + setErrorPopper(null)} onMouseEnter={(ev) => setErrorPopper(ev.target)} /> + + {error} + + + )} +
+ ); +}; export default withStyles(styles)(SwitchLoading); From f308558e49d8f31f879b51d14827f4ec7f9a3382 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 2 Nov 2025 18:32:59 -0800 Subject: [PATCH 17/26] lil more --- src/components/Dashboard/AddDevice.jsx | 455 +++++++++--------- .../Dashboard/DeviceSettingsModal.jsx | 435 ++++++++--------- src/components/Prime/PrimeCheckout.jsx | 230 ++++----- src/components/Prime/PrimeManage.jsx | 282 ++++++----- 4 files changed, 673 insertions(+), 729 deletions(-) diff --git a/src/components/Dashboard/AddDevice.jsx b/src/components/Dashboard/AddDevice.jsx index 857a88a1..8554eb7f 100644 --- a/src/components/Dashboard/AddDevice.jsx +++ b/src/components/Dashboard/AddDevice.jsx @@ -3,8 +3,8 @@ import { Button, CircularProgress, Divider, Modal, Paper, Typography, withStyles import AddCircleOutlineIcon from '@material-ui/icons/AddCircleOutline'; import * as Sentry from '@sentry/react'; import QrScanner from 'qr-scanner'; -import { Component } from 'react'; -import { connect } from 'react-redux'; +import { useCallback, useEffect, useRef, useState } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; import { selectDevice, updateDevice } from '../../actions'; import Colors from '../../colors'; import { pairErrorToMessage, verifyPairToken } from '../../utils'; @@ -95,65 +95,147 @@ const styles = (theme) => ({ }, }); -class AddDevice extends Component { - constructor(props) { - super(props); +const AddDevice = ({ classes, buttonText, buttonStyle, buttonIcon }) => { + const dispatch = useDispatch(); + const devices = useSelector((state) => state.devices); - this.state = { - modalOpen: false, - hasCamera: null, - pairLoading: false, - pairError: null, - pairDongleId: null, - canvasWidth: null, - canvasHeight: null, - }; - - this.videoRef = null; - this.qrScanner = null; - - this.componentDidUpdate = this.componentDidUpdate.bind(this); - this.onVideoRef = this.onVideoRef.bind(this); - this.onCanvasRef = this.onCanvasRef.bind(this); - this.modalClose = this.modalClose.bind(this); - this.onQrRead = this.onQrRead.bind(this); - this.restart = this.restart.bind(this); - this.onOpenModal = this.onOpenModal.bind(this); - } + const [modalOpen, setModalOpen] = useState(false); + const [hasCamera, setHasCamera] = useState(null); + const [pairLoading, setPairLoading] = useState(false); + const [pairError, setPairError] = useState(null); + const [pairDongleId, setPairDongleId] = useState(null); + const [canvasWidth, setCanvasWidth] = useState(null); + const [canvasHeight, setCanvasHeight] = useState(null); - async componentDidMount() { - this.componentDidUpdate({}, {}); - } + const videoRef = useRef(null); + const canvasRef = useRef(null); + const qrScannerRef = useRef(null); - async componentDidUpdate() { - const { modalOpen, pairLoading, pairError, pairDongleId } = this.state; - let { hasCamera } = this.state; + // Check for camera availability + useEffect(() => { if (hasCamera === null) { - hasCamera = await QrScanner.hasCamera(); - this.setState({ hasCamera }); + QrScanner.hasCamera().then((hasCam) => setHasCamera(hasCam)); } + }, [hasCamera]); + + // QR scanner callback + const onQrRead = useCallback( + async (result) => { + if (pairLoading || pairError || pairDongleId || !result) { + return; + } + + Sentry.captureMessage('qr scanned', { extra: { result } }); + const fromUrl = result.startsWith('https://'); + let pairToken; + if (fromUrl) { + try { + pairToken = new URLSearchParams(result.split('?')[1]).get('pair'); + if (!pairToken) { + throw new Error('empty pairToken from url qr code'); + } + } catch (err) { + setPairLoading(false); + setPairDongleId(null); + setPairError('Error: could not parse pair token from detected url'); + console.error(err); + return; + } + } else { + try { + // eslint-disable-next-line prefer-destructuring + pairToken = result.split('--')[2]; + if (!pairToken) { + throw new Error('empty pairToken from qr code'); + } + } catch (err) { + setPairLoading(false); + setPairDongleId(null); + setPairError('Error: invalid QR code detected'); + console.error(err); + return; + } + } + + if (videoRef.current) { + videoRef.current.pause(); + } + if (qrScannerRef.current) { + qrScannerRef.current._active = false; + } + setPairLoading(true); + setPairDongleId(null); + setPairError(null); - if (modalOpen && this.videoRef && !this.qrScanner && hasCamera && !pairDongleId) { - this.videoRef.addEventListener('play', this.componentDidUpdate); - this.videoRef.addEventListener('loadeddata', this.componentDidUpdate); - this.qrScanner = new QrScanner(this.videoRef, this.onQrRead); + try { + verifyPairToken(pairToken, fromUrl, 'adddevice_verify_pairtoken'); + } catch (err) { + setPairLoading(false); + setPairDongleId(null); + setPairError(`Error: ${err.message}`); + return; + } + + try { + const resp = await Devices.pilotPair(pairToken); + if (resp.dongle_id) { + const device = await Devices.fetchDevice(resp.dongle_id); + if (devices.length > 0) { + // state change from no device to a device requires reload. + dispatch(updateDevice(device)); + } + setPairLoading(false); + setPairDongleId(resp.dongle_id); + setPairError(null); + } else { + setPairLoading(false); + setPairDongleId(null); + setPairError('Error: could not pair'); + Sentry.captureMessage('qr scan failed', { extra: { resp } }); + } + } catch (err) { + const msg = pairErrorToMessage(err, 'adddevice_pair_qr'); + setPairLoading(false); + setPairDongleId(null); + setPairError(`Error: ${msg}`); + } + }, + [pairLoading, pairError, pairDongleId, devices, dispatch], + ); + + // Setup and cleanup QR scanner + useEffect(() => { + if (modalOpen && videoRef.current && !qrScannerRef.current && hasCamera && !pairDongleId) { + qrScannerRef.current = new QrScanner(videoRef.current, onQrRead); } - if (this.canvasRef && this.videoRef && this.videoRef.srcObject) { - const { canvasWidth, canvasHeight } = this.state; - const { width, height } = this.canvasRef.getBoundingClientRect(); + return () => { + if (qrScannerRef.current) { + qrScannerRef.current._active = true; + qrScannerRef.current.stop(); + qrScannerRef.current.destroy(); + qrScannerRef.current = null; + } + }; + }, [modalOpen, hasCamera, pairDongleId, onQrRead]); + + // Draw canvas overlay + useEffect(() => { + if (canvasRef.current && videoRef.current && videoRef.current.srcObject) { + const { width, height } = canvasRef.current.getBoundingClientRect(); if (canvasWidth !== width || canvasHeight !== height) { - this.setState({ canvasWidth: width, canvasHeight: height }); + setCanvasWidth(width); + setCanvasHeight(height); const size = Math.min(width, height); const x = (width - size) / 2 + size / 6; const y = (height - size) / 2 + size / 6; const rect = size * (2 / 3); const stroke = size / 6; - this.canvasRef.width = width; - this.canvasRef.height = height; + canvasRef.current.width = width; + canvasRef.current.height = height; - const ctx = this.canvasRef.getContext('2d'); + const ctx = canvasRef.current.getContext('2d'); ctx.clearRect(0, 0, width, height); ctx.strokeStyle = 'white'; @@ -182,202 +264,117 @@ class AddDevice extends Component { ctx.stroke(); } } - - if (!pairLoading && !pairError && !pairDongleId && this.qrScanner && modalOpen && hasCamera) { - try { - await this.qrScanner.start(); - } catch (err) { - if (err === 'Camera not found.') { - this.setState({ hasCamera: false }); - } else { - console.error(err); + }, [canvasWidth, canvasHeight]); + + // Start QR scanner + useEffect(() => { + const startScanner = async () => { + if (!pairLoading && !pairError && !pairDongleId && qrScannerRef.current && modalOpen && hasCamera) { + try { + await qrScannerRef.current.start(); + } catch (err) { + if (err === 'Camera not found.') { + setHasCamera(false); + } else { + console.error(err); + } } } - } - } - - async componentWillUnmount() { - if (this.videoRef) { - this.videoRef.removeEventListener('play', this.componentDidUpdate); - this.videoRef.removeEventListener('loadeddata', this.componentDidUpdate); - } - } - - async onVideoRef(ref) { - this.videoRef = ref; - this.componentDidUpdate(); - } + }; - async onCanvasRef(ref) { - this.canvasRef = ref; - this.componentDidUpdate(); - } + startScanner(); + }, [modalOpen, hasCamera, pairLoading, pairError, pairDongleId]); - restart() { - this.setState({ pairLoading: false, pairError: null, pairDongleId: null }); - if (this.videoRef) { - this.videoRef.play(); + const restart = () => { + setPairLoading(false); + setPairError(null); + setPairDongleId(null); + if (videoRef.current) { + videoRef.current.play(); } - if (this.qrScanner) { - this.qrScanner.start(); + if (qrScannerRef.current) { + qrScannerRef.current.start(); } - } - - modalClose() { - const { pairDongleId } = this.state; - if (this.qrScanner) { - this.qrScanner._active = true; - this.qrScanner.stop(); - this.qrScanner.destroy(); - this.qrScanner = null; + }; + + const modalClose = () => { + if (qrScannerRef.current) { + qrScannerRef.current._active = true; + qrScannerRef.current.stop(); + qrScannerRef.current.destroy(); + qrScannerRef.current = null; } - if (pairDongleId && this.props.devices.length === 0) { + if (pairDongleId && devices.length === 0) { window.location = `${window.location.origin}/${pairDongleId}`; return; } - this.setState({ modalOpen: false, pairLoading: false, pairError: null, pairDongleId: null }); + setModalOpen(false); + setPairLoading(false); + setPairError(null); + setPairDongleId(null); if (pairDongleId) { - this.props.dispatch(selectDevice(pairDongleId)); - } - } - - async onQrRead(result) { - const { pairDongleId, pairError, pairLoading } = this.state; - if (pairLoading || pairError || pairDongleId || !result) { - return; - } - - Sentry.captureMessage('qr scanned', { extra: { result } }); - const fromUrl = result.startsWith('https://'); - let pairToken; - if (fromUrl) { - try { - pairToken = new URLSearchParams(result.split('?')[1]).get('pair'); - if (!pairToken) { - throw new Error('empty pairToken from url qr code'); - } - } catch (err) { - this.setState({ pairLoading: false, pairDongleId: null, pairError: 'Error: could not parse pair token from detected url' }); - console.error(err); - return; - } - } else { - try { - // eslint-disable-next-line prefer-destructuring - pairToken = result.split('--')[2]; - if (!pairToken) { - throw new Error('empty pairToken from qr code'); - } - } catch (err) { - this.setState({ pairLoading: false, pairDongleId: null, pairError: 'Error: invalid QR code detected' }); - console.error(err); - return; - } - } - - if (this.videoRef) { - this.videoRef.pause(); - } - if (this.qrScanner) { - this.qrScanner._active = false; - } - this.setState({ pairLoading: true, pairDongleId: null, pairError: null }); - - try { - verifyPairToken(pairToken, fromUrl, 'adddevice_verify_pairtoken'); - } catch (err) { - this.setState({ pairLoading: false, pairDongleId: null, pairError: `Error: ${err.message}` }); - return; - } - - const { devices, dispatch } = this.props; - try { - const resp = await Devices.pilotPair(pairToken); - if (resp.dongle_id) { - const device = await Devices.fetchDevice(resp.dongle_id); - if (devices.length > 0) { - // state change from no device to a device requires reload. - dispatch(updateDevice(device)); - } - this.setState({ pairLoading: false, pairDongleId: resp.dongle_id, pairError: null }); - } else { - this.setState({ pairLoading: false, pairDongleId: null, pairError: 'Error: could not pair' }); - Sentry.captureMessage('qr scan failed', { extra: { resp } }); - } - } catch (err) { - const msg = pairErrorToMessage(err, 'adddevice_pair_qr'); - this.setState({ pairLoading: false, pairDongleId: null, pairError: `Error: ${msg}` }); + dispatch(selectDevice(pairDongleId)); } - } - - onOpenModal() { - this.setState({ modalOpen: true }); - } - - render() { - const { classes, buttonText, buttonStyle, buttonIcon } = this.props; - const { modalOpen, hasCamera, pairLoading, pairDongleId, pairError } = this.state; - - const videoContainerOverlay = pairLoading || pairDongleId || pairError ? classes.videoContainerOverlay : ''; - - return ( - <> - - - -
- Pair device - scan QR code -
- - {hasCamera === false ? ( - <> - Camera not found, please enable camera access. - You can also scan the QR code on your comma device using any other QR code reader application. - - ) : ( -
- -
- {pairLoading && } - {pairError && ( - <> - {pairError} - - - )} - {pairDongleId && ( - <> - - {'Successfully paired device '} - {pairDongleId} - - - - )} -
-
- + return ( + <> + + +
+ Device settings + {device.dongle_id} +
+ +
+ + +
+
+ +
+
+ {error && ( +
+ {error} +
+ )} +
+ callOnEnter(setDeviceAliasAction, ev)} + /> + {(device.alias !== deviceAlias || hasSavedAlias) && ( +
+ + {hasSavedAlias ? : } + + {loadingDeviceAlias && } +
+ )}
-
- {this.state.error && ( -
- {this.state.error} +
+ callOnEnter(shareDevice, ev)} + helperText="give another user read access to this device" + /> + {(shareEmail.length > 0 || hasShared) && ( +
+ + {hasShared ? : } + + {loadingDeviceShare && }
)} -
- this.callOnEnter(this.setDeviceAlias, ev)} - /> - {(this.props.device.alias !== this.state.deviceAlias || this.state.hasSavedAlias) && ( -
- - {this.state.hasSavedAlias ? : } - - {this.state.loadingDeviceAlias && } -
- )} -
-
- this.callOnEnter(this.shareDevice, ev)} - helperText="give another user read access to this device" - /> - {(this.state.shareEmail.length > 0 || this.state.hasShared) && ( -
- - {this.state.hasShared ? : } - - {this.state.loadingDeviceShare && } -
- )} -
-
- +
+
+ +
+ + + + +
+ Unpair device + {device.dongle_id} +
+ + {unpairError && ( +
+ + {unpairError}
-
-
- - -
- Unpair device - {device.dongle_id} + )} + {device.prime && ( +
+ + Unpairing will also cancel the comma prime subscription for this device.
- - {this.state.unpairError && ( -
- - {this.state.unpairError} -
- )} - {this.props.device.prime && ( -
- - Unpairing will also cancel the comma prime subscription for this device. -
- )} -
- + {unpaired ? ( + Unpaired + ) : ( + - {this.state.unpaired ? ( - Unpaired - ) : ( - - )} -
- - - this.setState({ uploadModal: false })} device={device} /> - - ); - } -} - -const stateToProps = (state, ownProps) => { - const device = state.devices.find((d) => d.dongle_id === ownProps.dongleId) || (state.device && state.device.dongle_id === ownProps.dongleId ? state.device : null); - return { - subscription: state.subscription, - device, - globalDongleId: state.dongleId, - }; + )} +
+
+
+ setUploadModal(false)} device={device} /> + + ); }; -export default connect(stateToProps)(withStyles(styles)(DeviceSettingsModal)); +export default withStyles(styles)(DeviceSettingsModal); diff --git a/src/components/Prime/PrimeCheckout.jsx b/src/components/Prime/PrimeCheckout.jsx index 4be90e86..5b7ae61a 100644 --- a/src/components/Prime/PrimeCheckout.jsx +++ b/src/components/Prime/PrimeCheckout.jsx @@ -4,8 +4,8 @@ import CheckIcon from '@material-ui/icons/Check'; import KeyboardBackspaceIcon from '@material-ui/icons/KeyboardBackspace'; import * as Sentry from '@sentry/react'; import dayjs from 'dayjs'; -import { Component } from 'react'; -import { connect } from 'react-redux'; +import { useCallback, useEffect, useState } from 'react'; +import { useSelector } from 'react-redux'; import Colors from '../../colors'; import { ErrorOutline, InfoOutline } from '../../icons'; import { navigate } from '../../navigation'; @@ -203,60 +203,19 @@ const styles = () => ({ }, }); -class PrimeCheckout extends Component { - constructor(props) { - super(props); +const PrimeCheckout = ({ classes }) => { + const dongleId = useSelector((state) => state.dongleId); + const device = useSelector((state) => state.device); + const subscribeInfo = useSelector((state) => state.subscribeInfo); + const stripeCancelled = useSelector((state) => state.stripeCancelled); - this.state = { - error: null, - loadingCheckout: false, - selectedPlan: null, - windowWidth: window.innerWidth, - windowHeight: window.innerHeight, - }; + const [error, setError] = useState(null); + const [loadingCheckout, setLoadingCheckout] = useState(false); + const [selectedPlan, setSelectedPlan] = useState(null); + const [windowWidth, setWindowWidth] = useState(window.innerWidth); + const [windowHeight, setWindowHeight] = useState(window.innerHeight); - this.gotoCheckout = this.gotoCheckout.bind(this); - this.trialClaimable = this.trialClaimable.bind(this); - this.dataPlanAvailable = this.dataPlanAvailable.bind(this); - this.onResize = this.onResize.bind(this); - } - - componentDidMount() { - this.componentDidUpdate({}); - } - - componentDidUpdate(prevProps) { - const { stripeCancelled, subscribeInfo } = this.props; - if (!prevProps.stripeCancelled && stripeCancelled) { - this.setState({ error: 'Checkout cancelled' }); - } - - if (this.state.selectedPlan === null && subscribeInfo) { - const plan = this.dataPlanAvailable() ? 'data' : 'nodata'; - this.setState({ selectedPlan: plan }); - } - } - - onResize(windowWidth, windowHeight) { - this.setState({ windowWidth, windowHeight }); - } - - async gotoCheckout() { - const { dongleId, subscribeInfo } = this.props; - this.setState({ loadingCheckout: true }); - try { - const { selectedPlan: plan } = this.state; - const resp = await Billing.getStripeCheckout(dongleId, subscribeInfo.sim_id, plan); - window.location = resp.url; - } catch (err) { - // TODO show error messages - console.error(err); - Sentry.captureException(err, { fingerprint: 'prime_goto_stripe_checkout' }); - } - } - - dataPlanAvailable() { - const { device, subscribeInfo } = this.props; + const dataPlanAvailable = useCallback(() => { if (!device || !subscribeInfo) { return null; } @@ -269,11 +228,9 @@ class PrimeCheckout extends Component { subscribeInfo.sim_usable !== false && ['blue', 'magenta_new', 'webbing'].includes(subscribeInfo.sim_type), ); - } + }, [device, subscribeInfo]); - trialClaimable() { - const { subscribeInfo } = this.props; - const { selectedPlan } = this.state; + const trialClaimable = () => { if (!subscribeInfo) { return null; } @@ -284,68 +241,96 @@ class PrimeCheckout extends Component { return Boolean(subscribeInfo.trial_end_nodata); } return Boolean(subscribeInfo.trial_end_data && subscribeInfo.trial_end_nodata); - } + }; + + const onResize = (width, height) => { + setWindowWidth(width); + setWindowHeight(height); + }; + + const gotoCheckout = async () => { + setLoadingCheckout(true); + try { + const resp = await Billing.getStripeCheckout(dongleId, subscribeInfo.sim_id, selectedPlan); + window.location = resp.url; + } catch (err) { + // TODO show error messages + console.error(err); + Sentry.captureException(err, { fingerprint: 'prime_goto_stripe_checkout' }); + } + }; - render() { - const { classes, device, subscribeInfo } = this.props; - const { windowWidth, windowHeight, error, loadingCheckout, selectedPlan } = this.state; + // Handle stripe cancellation + useEffect(() => { + if (stripeCancelled) { + setError('Checkout cancelled'); + } + }, [stripeCancelled]); - let chargeText = null; - if (selectedPlan && this.trialClaimable()) { - let trialEndDate = null; - if (selectedPlan === 'data') { - trialEndDate = dayjs(subscribeInfo.trial_end_data * 1000).format('MMMM D'); - } else if (selectedPlan === 'nodata') { - trialEndDate = dayjs(subscribeInfo.trial_end_nodata * 1000).format('MMMM D'); - } - chargeText = `Your first charge will be on ${trialEndDate}, then monthly thereafter.`; + // Set default plan when subscribeInfo loads + useEffect(() => { + if (selectedPlan === null && subscribeInfo) { + const plan = dataPlanAvailable() ? 'data' : 'nodata'; + setSelectedPlan(plan); + } + }, [subscribeInfo, selectedPlan, dataPlanAvailable]); + + let chargeText = null; + if (selectedPlan && trialClaimable()) { + let trialEndDate = null; + if (selectedPlan === 'data') { + trialEndDate = dayjs(subscribeInfo.trial_end_data * 1000).format('MMMM D'); + } else if (selectedPlan === 'nodata') { + trialEndDate = dayjs(subscribeInfo.trial_end_nodata * 1000).format('MMMM D'); } + chargeText = `Your first charge will be on ${trialEndDate}, then monthly thereafter.`; + } - const containerPadding = windowWidth > 520 ? { margin: '18px 24px' } : { margin: '6px 12px' }; - const blockMargin = windowWidth > 520 ? { marginTop: 24 } : { marginTop: 8 }; - const paddingStyle = windowWidth > 520 ? { paddingLeft: 7, paddingRight: 7 } : { paddingLeft: 8, paddingRight: 8 }; - const selectedStyle = { border: '2px solid white' }; - const plansLoadingClass = !subscribeInfo ? classes.planInfoLoading : ''; - const disabledDataPlan = Boolean(!subscribeInfo || !this.dataPlanAvailable()); - const boxHeight = windowHeight > 600 ? { height: 140 } : { height: 110 }; + const containerPadding = windowWidth > 520 ? { margin: '18px 24px' } : { margin: '6px 12px' }; + const blockMargin = windowWidth > 520 ? { marginTop: 24 } : { marginTop: 8 }; + const paddingStyle = windowWidth > 520 ? { paddingLeft: 7, paddingRight: 7 } : { paddingLeft: 8, paddingRight: 8 }; + const selectedStyle = { border: '2px solid white' }; + const plansLoadingClass = !subscribeInfo ? classes.planInfoLoading : ''; + const disabledDataPlan = Boolean(!subscribeInfo || !dataPlanAvailable()); + const boxHeight = windowHeight > 600 ? { height: 140 } : { height: 110 }; - let disabledDataPlanText; - if (subscribeInfo && disabledDataPlan) { - if (!device.eligible_features?.prime_data) { - disabledDataPlanText = 'Standard plan is not available for your device.'; - } else if (!subscribeInfo.sim_id && subscribeInfo.device_online) { - disabledDataPlanText = 'Standard plan not available, no SIM was detected. Ensure SIM is securely inserted and try again.'; - } else if (!subscribeInfo.sim_id) { - disabledDataPlanText = 'Standard plan not available, device could not be reached. Connect device to the internet and try again.'; - } else if (!subscribeInfo.is_prime_sim) { - disabledDataPlanText = 'Standard plan not available, detected a third-party SIM.'; - } else if (!['blue', 'magenta_new', 'webbing'].includes(subscribeInfo.sim_type)) { - disabledDataPlanText = [ - 'Standard plan not available, old SIM type detected, new SIM cards are available in the ', - - shop - , - ]; - } else if (subscribeInfo.sim_usable === false && subscribeInfo.sim_type === 'blue') { - disabledDataPlanText = [ - 'Standard plan not available, SIM has been canceled and is therefore no longer usable, new SIM cards are available in the ', -
- shop - , - ]; - } else if (subscribeInfo.sim_usable === false) { - disabledDataPlanText = [ - 'Standard plan not available, SIM is no longer usable, new SIM cards are available in the ', - - shop - , - ]; - } + let disabledDataPlanText; + if (subscribeInfo && disabledDataPlan) { + if (!device.eligible_features?.prime_data) { + disabledDataPlanText = 'Standard plan is not available for your device.'; + } else if (!subscribeInfo.sim_id && subscribeInfo.device_online) { + disabledDataPlanText = 'Standard plan not available, no SIM was detected. Ensure SIM is securely inserted and try again.'; + } else if (!subscribeInfo.sim_id) { + disabledDataPlanText = 'Standard plan not available, device could not be reached. Connect device to the internet and try again.'; + } else if (!subscribeInfo.is_prime_sim) { + disabledDataPlanText = 'Standard plan not available, detected a third-party SIM.'; + } else if (!['blue', 'magenta_new', 'webbing'].includes(subscribeInfo.sim_type)) { + disabledDataPlanText = [ + 'Standard plan not available, old SIM type detected, new SIM cards are available in the ', + + shop + , + ]; + } else if (subscribeInfo.sim_usable === false && subscribeInfo.sim_type === 'blue') { + disabledDataPlanText = [ + 'Standard plan not available, SIM has been canceled and is therefore no longer usable, new SIM cards are available in the ', + + shop + , + ]; + } else if (subscribeInfo.sim_usable === false) { + disabledDataPlanText = [ + 'Standard plan not available, SIM is no longer usable, new SIM cards are available in the ', + + shop + , + ]; } + } - return ( -
- + return ( +
+
navigate(`/${dongleId}`)}> @@ -381,7 +366,7 @@ class PrimeCheckout extends Component {
this.setState({ selectedPlan: 'nodata' }) : null} + onClick={subscribeInfo ? () => setSelectedPlan('nodata') : null} >

lite

$10/month

@@ -394,7 +379,7 @@ class PrimeCheckout extends Component {
this.setState({ selectedPlan: 'data' }) : null} + onClick={!disabledDataPlan ? () => setSelectedPlan('data') : null} >

standard

$24/month

@@ -433,8 +418,8 @@ class PrimeCheckout extends Component {
)}
-
{chargeText && ( @@ -444,13 +429,6 @@ class PrimeCheckout extends Component { )}
); - } -} - -const stateToProps = (state) => ({ - dongleId: state.dongleId, - device: state.device, - subscribeInfo: state.subscribeInfo, -}); +}; -export default connect(stateToProps)(withStyles(styles)(PrimeCheckout)); +export default withStyles(styles)(PrimeCheckout); diff --git a/src/components/Prime/PrimeManage.jsx b/src/components/Prime/PrimeManage.jsx index 2989cae3..199ed254 100644 --- a/src/components/Prime/PrimeManage.jsx +++ b/src/components/Prime/PrimeManage.jsx @@ -4,8 +4,8 @@ import KeyboardBackspaceIcon from '@material-ui/icons/KeyboardBackspace'; import PriorityHighIcon from '@material-ui/icons/PriorityHigh'; import * as Sentry from '@sentry/react'; import dayjs from 'dayjs'; -import { Component } from 'react'; -import { connect } from 'react-redux'; +import { useCallback, useEffect, useRef, useState } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; import { primeGetSubscription } from '../../actions'; import Colors from '../../colors'; import { ErrorOutline, InfoOutline } from '../../icons'; @@ -183,163 +183,156 @@ const styles = (theme) => ({ }, }); -class PrimeManage extends Component { - constructor(props) { - super(props); - this.state = { - error: null, - cancelError: null, - cancelModal: false, - canceling: false, - stripeStatus: null, - windowWidth: window.innerWidth, - }; - - this.cancelPrime = this.cancelPrime.bind(this); - this.fetchStripeSession = this.fetchStripeSession.bind(this); - this.gotoUpdate = this.gotoUpdate.bind(this); - this.fetchSubscription = this.fetchSubscription.bind(this); - this.onResize = this.onResize.bind(this); - } +const PrimeManage = ({ classes }) => { + const dispatch = useDispatch(); + const dongleId = useSelector((state) => state.dongleId); + const device = useSelector((state) => state.device); + const subscription = useSelector((state) => state.subscription); + const stripeSuccess = useSelector((state) => state.stripeSuccess); - componentDidMount() { - this.componentDidUpdate({}, {}); - this.mounted = true; - } + const [error] = useState(null); + const [cancelError, setCancelError] = useState(null); + const [cancelSuccess, setCancelSuccess] = useState(null); + const [cancelModal, setCancelModal] = useState(false); + const [canceling, setCanceling] = useState(false); + const [stripeStatus, setStripeStatus] = useState(null); + const [windowWidth, setWindowWidth] = useState(window.innerWidth); - componentDidUpdate(prevProps, prevState) { - if (!prevProps.stripeSuccess && this.props.stripeSuccess) { - this.setState( - { - stripeStatus: { sessionId: this.props.stripeSuccess, loading: true, paid: null }, - }, - this.fetchStripeSession, - ); - } - } + const mounted = useRef(false); - componentWillUnmount() { - this.mounted = false; - } + const onResize = (width) => { + setWindowWidth(width); + }; - cancelPrime() { - this.setState({ canceling: true }); - Billing.cancelPrime(this.props.dongleId) - .then((resp) => { - if (resp.success) { - this.setState({ canceling: false, cancelError: null, cancelSuccess: 'Cancelled subscription.' }); - this.fetchSubscription(); - } else if (resp.error) { - this.setState({ canceling: false, cancelError: resp.description }); + const fetchSubscription = useCallback( + async (repeat = false) => { + if (!mounted.current) { + return; + } + try { + const subscriptionData = await Billing.getSubscription(dongleId); + if (subscriptionData.user_id) { + dispatch(primeGetSubscription(dongleId, subscriptionData)); } else { - this.setState({ canceling: false, cancelError: 'Could not cancel due to unknown error. Please try again.' }); + setTimeout(() => fetchSubscription(true), 2000); } - }) - .catch((err) => { - Sentry.captureException(err, { fingerprint: 'primemanage_cancel_prime' }); - this.setState({ canceling: false, cancelError: 'Could not cancel due to unknown error. Please try again.' }); - }); - } - - async gotoUpdate() { - try { - const resp = await Billing.getStripePortal(this.props.dongleId); - window.location = resp.url; - } catch (err) { - // TODO show error messages - console.error(err); - Sentry.captureException(err, { fingerprint: 'prime_goto_stripe_update' }); - } - } + } catch (err) { + if (err.message && err.message.indexOf('404') === 0) { + if (repeat) { + setTimeout(() => fetchSubscription(true), 2000); + } + } else { + console.error(err); + Sentry.captureException(err, { fingerprint: 'prime_fetch_subscription' }); + } + } + }, + [dongleId, dispatch], + ); - async fetchStripeSession() { - const { dongleId } = this.props; - const { stripeStatus } = this.state; - if (!stripeStatus || !this.mounted) { + const fetchStripeSession = useCallback(async () => { + if (!stripeStatus || !mounted.current) { return; } try { const resp = await Billing.getStripeSession(dongleId, stripeStatus.sessionId); const status = resp.payment_status; - this.setState({ - stripeStatus: { - ...stripeStatus, - paid: status, - loading: status !== 'paid', - }, + setStripeStatus({ + ...stripeStatus, + paid: status, + loading: status !== 'paid', }); if (status === 'paid') { - this.fetchSubscription(true); + fetchSubscription(true); } else { - setTimeout(this.fetchStripeSession, 2000); + setTimeout(fetchStripeSession, 2000); } } catch (err) { // TODO error handling console.error(err); Sentry.captureException(err, { fingerprint: 'prime_fetch_stripe_session' }); } - } + }, [dongleId, stripeStatus, fetchSubscription]); - async fetchSubscription(repeat = false) { - const { dongleId } = this.props; - if (!this.mounted) { - return; - } + const cancelPrime = () => { + setCanceling(true); + Billing.cancelPrime(dongleId) + .then((resp) => { + if (resp.success) { + setCanceling(false); + setCancelError(null); + setCancelSuccess('Cancelled subscription.'); + fetchSubscription(); + } else if (resp.error) { + setCanceling(false); + setCancelError(resp.description); + } else { + setCanceling(false); + setCancelError('Could not cancel due to unknown error. Please try again.'); + } + }) + .catch((err) => { + Sentry.captureException(err, { fingerprint: 'primemanage_cancel_prime' }); + setCanceling(false); + setCancelError('Could not cancel due to unknown error. Please try again.'); + }); + }; + + const gotoUpdate = async () => { try { - const subscription = await Billing.getSubscription(dongleId); - if (subscription.user_id) { - this.props.dispatch(primeGetSubscription(dongleId, subscription)); - } else { - setTimeout(() => this.fetchSubscription(true), 2000); - } + const resp = await Billing.getStripePortal(dongleId); + window.location = resp.url; } catch (err) { - if (err.message && err.message.indexOf('404') === 0) { - if (repeat) { - setTimeout(() => this.fetchSubscription(true), 2000); - } - } else { - console.error(err); - Sentry.captureException(err, { fingerprint: 'prime_fetch_subscription' }); - } + // TODO show error messages + console.error(err); + Sentry.captureException(err, { fingerprint: 'prime_goto_stripe_update' }); } - } + }; - onResize(windowWidth) { - this.setState({ windowWidth }); - } + // Set mounted ref + useEffect(() => { + mounted.current = true; + return () => { + mounted.current = false; + }; + }, []); - render() { - const { dongleId, subscription, classes, device } = this.props; - const { windowWidth, stripeStatus } = this.state; + // Handle stripe success + useEffect(() => { + if (stripeSuccess) { + setStripeStatus({ sessionId: stripeSuccess, loading: true, paid: null }); + fetchStripeSession(); + } + }, [stripeSuccess, fetchStripeSession]); - const hasPrimeSub = subscription && subscription.user_id; + const hasPrimeSub = subscription && subscription.user_id; - if (!hasPrimeSub && !stripeStatus) { - return null; - } + if (!hasPrimeSub && !stripeStatus) { + return null; + } - let joinDate; - let nextPaymentDate; - let cancelAtDate; - let planName; - let planSubtext; - if (hasPrimeSub) { - joinDate = dayjs(subscription.subscribed_at ? subscription.subscribed_at * 1000 : 0).format('MMMM D, YYYY'); - nextPaymentDate = dayjs(subscription.next_charge_at ? subscription.next_charge_at * 1000 : 0).format('MMMM D, YYYY'); - cancelAtDate = dayjs(subscription.cancel_at ? subscription.cancel_at * 1000 : 0).format('MMMM D, YYYY'); - planName = subscription.plan === 'nodata' ? 'Lite' : 'Standard'; - planSubtext = subscription.plan === 'nodata' ? '(without data plan)' : '(with data plan)'; - } + let joinDate; + let nextPaymentDate; + let cancelAtDate; + let planName; + let planSubtext; + if (hasPrimeSub) { + joinDate = dayjs(subscription.subscribed_at ? subscription.subscribed_at * 1000 : 0).format('MMMM D, YYYY'); + nextPaymentDate = dayjs(subscription.next_charge_at ? subscription.next_charge_at * 1000 : 0).format('MMMM D, YYYY'); + cancelAtDate = dayjs(subscription.cancel_at ? subscription.cancel_at * 1000 : 0).format('MMMM D, YYYY'); + planName = subscription.plan === 'nodata' ? 'Lite' : 'Standard'; + planSubtext = subscription.plan === 'nodata' ? '(without data plan)' : '(with data plan)'; + } - const hasCancelAt = Boolean(hasPrimeSub && subscription.cancel_at && subscription.cancel_at <= subscription.next_charge_at); - const alias = deviceNamePretty(device); - const containerPadding = windowWidth > 520 ? 36 : 16; - const buttonSmallStyle = windowWidth < 514 ? { width: '100%' } : {}; + const hasCancelAt = Boolean(hasPrimeSub && subscription.cancel_at && subscription.cancel_at <= subscription.next_charge_at); + const alias = deviceNamePretty(device); + const containerPadding = windowWidth > 520 ? 36 : 16; + const buttonSmallStyle = windowWidth < 514 ? { width: '100%' } : {}; - return ( - <> - + return ( + <> +
navigate(`/${dongleId}`)}> @@ -410,17 +403,17 @@ class PrimeManage extends Component { Amount {`$${(subscription.amount / 100).toFixed(2)}`}
- {this.state.error && ( + {error && (
- {this.state.error} + {error}
)}
- this.setState({ cancelModal: false })}> + setCancelModal(false)}> Cancel prime subscription - {this.state.cancelError && ( + {cancelError && (
- {this.state.cancelError} + {cancelError}
)} - {this.state.cancelSuccess && ( + {cancelSuccess && (
- {this.state.cancelSuccess} + {cancelSuccess}
)} {`Device: ${alias} (${dongleId})`} @@ -480,25 +473,18 @@ class PrimeManage extends Component { -
); - } -} - -const stateToProps = (state) => ({ - dongleId: state.dongleId, - device: state.device, - subscription: state.subscription, -}); +}; -export default connect(stateToProps)(withStyles(styles)(PrimeManage)); +export default withStyles(styles)(PrimeManage); From c187b0c4d1b7a10c659aa9c401f3eb26ebe9d38c Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 2 Nov 2025 19:33:51 -0800 Subject: [PATCH 18/26] we're cookin' --- src/App.jsx | 120 ++-- src/components/DeviceInfo/index.jsx | 282 ++++----- src/components/DriveVideo/index.jsx | 374 ++++++------ src/components/DriveView/Media.jsx | 586 +++++++++---------- src/components/DriveView/index.jsx | 100 ++-- src/components/Files/UploadQueue.jsx | 337 +++++------ src/components/Navigation/index.jsx | 770 ++++++++++++------------- src/components/Prime/PrimeCheckout.jsx | 176 +++--- src/components/Prime/PrimeManage.jsx | 271 +++++---- src/components/anonymous.jsx | 99 ++-- src/components/explorer.jsx | 317 +++++----- 11 files changed, 1640 insertions(+), 1792 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 3a32d1a9..8bf1d51f 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -3,7 +3,7 @@ import MyCommaAuth, { config as AuthConfig, storage as AuthStorage } from '@comm import { CircularProgress, Grid } from '@material-ui/core'; import * as Sentry from '@sentry/react'; import localforage from 'localforage'; -import { Component, lazy, Suspense } from 'react'; +import { lazy, Suspense, useCallback, useEffect, useState } from 'react'; import { Provider } from 'react-redux'; import { Redirect, Route, Router, Switch } from 'react-router'; import ErrorFallback from './components/ErrorFallback'; @@ -14,14 +14,11 @@ import { getSegmentRange, getZoom } from './url'; const Explorer = lazy(() => import('./components/explorer')); const AnonymousLanding = lazy(() => import('./components/anonymous')); -class App extends Component { - constructor(props) { - super(props); - - this.state = { - initialized: false, - }; +const App = () => { + const [initialized, setInitialized] = useState(false); + // Handle pair token from URL + useEffect(() => { let pairToken; if (window.location) { pairToken = new URLSearchParams(window.location.search).get('pair'); @@ -34,63 +31,68 @@ class App extends Component { console.error(err); } } - } + }, []); - apiErrorResponseCallback(resp) { + const apiErrorResponseCallback = useCallback((resp) => { if (resp.status === 401) { MyCommaAuth.logOut(); } - } - - async componentDidMount() { - if (window.location) { - if (window.location.pathname === AuthConfig.AUTH_PATH) { - try { - const params = new URLSearchParams(window.location.search); - const code = params.get('code'); - const provider = params.get('provider'); - const token = await Auth.refreshAccessToken(code, provider); - if (token) { - AuthStorage.setCommaAccessToken(token); + }, []); + + // Initialize authentication and API + useEffect(() => { + const initialize = async () => { + if (window.location) { + if (window.location.pathname === AuthConfig.AUTH_PATH) { + try { + const params = new URLSearchParams(window.location.search); + const code = params.get('code'); + const provider = params.get('provider'); + const token = await Auth.refreshAccessToken(code, provider); + if (token) { + AuthStorage.setCommaAccessToken(token); + } + } catch (err) { + console.error(err); + Sentry.captureException(err, { fingerprint: 'app_auth_refresh_token' }); } - } catch (err) { - console.error(err); - Sentry.captureException(err, { fingerprint: 'app_auth_refresh_token' }); } } - } - const token = await MyCommaAuth.init(); - if (token) { - Request.configure(token, this.apiErrorResponseCallback); - Billing.configure(token, this.apiErrorResponseCallback); - Athena.configure(token, this.apiErrorResponseCallback); - } + const token = await MyCommaAuth.init(); + if (token) { + Request.configure(token, apiErrorResponseCallback); + Billing.configure(token, apiErrorResponseCallback); + Athena.configure(token, apiErrorResponseCallback); + } - this.setState({ initialized: true }); - } + setInitialized(true); + }; + + initialize(); + }, [apiErrorResponseCallback]); - redirectLink() { + const redirectLink = () => { let url = '/'; if (typeof window.sessionStorage !== 'undefined' && sessionStorage.getItem('redirectURL') !== null) { url = sessionStorage.getItem('redirectURL'); sessionStorage.removeItem('redirectURL'); } return url; - } + }; - authRoutes() { + const authRoutes = () => { return ( - + ); - } + }; - anonymousRoutes() { + const anonymousRoutes = () => { return ( @@ -99,9 +101,9 @@ class App extends Component { ); - } + }; - renderLoading() { + const renderLoading = () => { return ( @@ -109,27 +111,25 @@ class App extends Component { ); - } - - render() { - if (!this.state.initialized) { - return this.renderLoading(); - } + }; - const showLogin = !MyCommaAuth.isAuthenticated() && !getZoom(window.location.pathname) && !getSegmentRange(window.location.pathname); - let content = {showLogin ? this.anonymousRoutes() : this.authRoutes()}; + if (!initialized) { + return renderLoading(); + } - // Use ErrorBoundary in production only - if (import.meta.env.PROD) { - content = }>{content}; - } + const showLogin = !MyCommaAuth.isAuthenticated() && !getZoom(window.location.pathname) && !getSegmentRange(window.location.pathname); + let content = {showLogin ? anonymousRoutes() : authRoutes()}; - return ( - - {content} - - ); + // Use ErrorBoundary in production only + if (import.meta.env.PROD) { + content = }>{content}; } -} + + return ( + + {content} + + ); +}; export default App; diff --git a/src/components/DeviceInfo/index.jsx b/src/components/DeviceInfo/index.jsx index c66765a6..3cdea402 100644 --- a/src/components/DeviceInfo/index.jsx +++ b/src/components/DeviceInfo/index.jsx @@ -3,8 +3,8 @@ import { Button, CircularProgress, Popper, Tooltip, Typography, withStyles } fro import AccessTime from '@material-ui/icons/AccessTime'; import * as Sentry from '@sentry/react'; import dayjs from 'dayjs'; -import React, { Component } from 'react'; -import { connect } from 'react-redux'; +import { useCallback, useEffect, useRef, useState } from 'react'; +import { useSelector } from 'react-redux'; import Colors from '../../colors'; import { deviceIsOnline, deviceNamePretty } from '../../utils'; import { isMetric, KM_PER_MI } from '../../utils/conversions'; @@ -187,92 +187,65 @@ const styles = (theme) => ({ }, }); -class DeviceInfo extends Component { - constructor(props) { - super(props); - this.mounted = null; - this.state = { - deviceStats: {}, - carHealth: {}, - snapshot: {}, - windowWidth: window.innerWidth, - isTimeSelectOpen: false, - }; - - this.snapshotButtonRef = React.createRef(); - - this.onResize = this.onResize.bind(this); - this.onVisible = this.onVisible.bind(this); - this.fetchDeviceInfo = this.fetchDeviceInfo.bind(this); - this.fetchDeviceCarHealth = this.fetchDeviceCarHealth.bind(this); - this.takeSnapshot = this.takeSnapshot.bind(this); - this.snapshotType = this.snapshotType.bind(this); - this.renderButtons = this.renderButtons.bind(this); - this.renderStats = this.renderStats.bind(this); - this.renderSnapshotImage = this.renderSnapshotImage.bind(this); - this.onOpenTimeSelect = this.onOpenTimeSelect.bind(this); - this.onCloseTimeSelect = this.onCloseTimeSelect.bind(this); - } +const DeviceInfo = ({ classes }) => { + const dongleId = useSelector((state) => state.dongleId); + const device = useSelector((state) => state.device); - componentDidMount() { - this.mounted = true; - } + const [deviceStats, setDeviceStats] = useState({}); + const [carHealth, setCarHealth] = useState({}); + const [snapshot, setSnapshot] = useState({}); + const [windowWidth, setWindowWidth] = useState(window.innerWidth); + const [isTimeSelectOpen, setIsTimeSelectOpen] = useState(false); - componentDidUpdate(prevProps) { - const { dongleId } = this.props; + const snapshotButtonRef = useRef(null); + const mounted = useRef(false); - if (prevProps.dongleId !== dongleId) { - this.setState({ - deviceStats: {}, - carHealth: {}, - snapshot: {}, - windowWidth: window.innerWidth, - }); + // Set mounted on initial mount + useEffect(() => { + mounted.current = true; + return () => { + mounted.current = false; + }; + }, []); + + // Reset state when dongleId changes + useEffect(() => { + if (dongleId) { + setDeviceStats({}); + setCarHealth({}); + setSnapshot({}); + setWindowWidth(window.innerWidth); } - } - - componentWillUnmount() { - this.mounted = false; - } + }, [dongleId]); - onResize(windowWidth) { - this.setState({ windowWidth }); - } + const onResize = (newWindowWidth) => { + setWindowWidth(newWindowWidth); + }; - onVisible() { - const { device } = this.props; - if (!device.shared) { - this.fetchDeviceInfo(); - this.fetchDeviceCarHealth(); - } - } - - async fetchDeviceInfo() { - const { dongleId, device } = this.props; + const fetchDeviceInfo = useCallback(async () => { if (device.shared) { return; } - this.setState({ deviceStats: { fetching: true } }); + setDeviceStats({ fetching: true }); try { const resp = await Devices.fetchDeviceStats(dongleId); - if (this.mounted && dongleId === this.props.dongleId) { - this.setState({ deviceStats: { result: resp } }); + if (mounted.current) { + setDeviceStats({ result: resp }); } } catch (err) { console.error(err); Sentry.captureException(err, { fingerprint: 'device_info_device_stats' }); - this.setState({ deviceStats: { error: err.message } }); + setDeviceStats({ error: err.message }); } - } + }, [dongleId, device.shared]); - async fetchDeviceCarHealth() { - const { dongleId, device } = this.props; + const fetchDeviceCarHealth = useCallback(async () => { if (!deviceIsOnline(device)) { - this.setState({ carHealth: {} }); + setCarHealth({}); return; } - this.setState({ carHealth: { fetching: true } }); + setCarHealth({ fetching: true }); try { const payload = { method: 'getMessage', @@ -281,24 +254,29 @@ class DeviceInfo extends Component { id: 0, }; const resp = await Athena.postJsonRpcPayload(dongleId, payload); - if (this.mounted && dongleId === this.props.dongleId) { - this.setState({ carHealth: resp }); + if (mounted.current) { + setCarHealth(resp); } } catch (err) { - if (this.mounted && dongleId === this.props.dongleId) { + if (mounted.current) { if (!err.message || err.message.indexOf('Device not registered') === -1) { console.error(err); Sentry.captureException(err, { fingerprint: 'device_info_athena_pandastate' }); } - this.setState({ carHealth: { error: err.message } }); + setCarHealth({ error: err.message }); } } - } + }, [dongleId, device]); + + const onVisible = useCallback(() => { + if (!device.shared) { + fetchDeviceInfo(); + fetchDeviceCarHealth(); + } + }, [device.shared, fetchDeviceInfo, fetchDeviceCarHealth]); - async takeSnapshot() { - const { dongleId } = this.props; - const { snapshot } = this.state; - this.setState({ snapshot: { ...snapshot, error: null, fetching: true } }); + const takeSnapshot = async () => { + setSnapshot((prev) => ({ ...prev, error: null, fetching: true })); try { const payload = { method: 'takeSnapshot', @@ -312,9 +290,7 @@ class DeviceInfo extends Component { if (resp.result && !resp.result.jpegBack && !resp.result.jpegFront) { throw new Error('unable to fetch snapshot'); } - if (dongleId === this.props.dongleId) { - this.setState({ snapshot: resp }); - } + setSnapshot(resp); } catch (err) { let error = err.message; if (error.indexOf('Device not registered') !== -1) { @@ -330,74 +306,19 @@ class DeviceInfo extends Component { } } } - this.setState({ snapshot: { error } }); + setSnapshot({ error }); } - } - - snapshotType(showFront) { - const { snapshot } = this.state; - this.setState({ snapshot: { ...snapshot, showFront } }); - } - - onOpenTimeSelect() { - this.setState({ isTimeSelectOpen: true }); - } - - onCloseTimeSelect() { - this.setState({ isTimeSelectOpen: false }); - } + }; - render() { - const { classes, device } = this.props; - const { snapshot, deviceStats, windowWidth } = this.state; - - const containerPadding = windowWidth > 520 ? 36 : 16; - const largeSnapshotPadding = windowWidth > 1440 ? '12px 0' : 0; - - return ( - <> - - -
- {windowWidth >= 768 ? ( -
- {deviceNamePretty(device)} -
{this.renderStats()}
-
{this.renderButtons()}
-
- ) : ( - <> -
- {deviceNamePretty(device)} -
-
{this.renderButtons()}
- {deviceStats.result &&
{this.renderStats()}
} - - )} -
- {snapshot.result && ( -
- {windowWidth >= 640 ? ( -
-
{this.renderSnapshotImage(snapshot.result.jpegBack, false)}
-
{this.renderSnapshotImage(snapshot.result.jpegFront, true)}
-
- ) : ( -
-
{this.renderSnapshotImage(snapshot.result.jpegBack, false)}
-
{this.renderSnapshotImage(snapshot.result.jpegFront, true)}
-
- )} -
- )} - - ); - } + const onOpenTimeSelect = () => { + setIsTimeSelectOpen(true); + }; - renderStats() { - const { classes } = this.props; - const { deviceStats } = this.state; + const onCloseTimeSelect = () => { + setIsTimeSelectOpen(false); + }; + const renderStats = () => { if (!deviceStats.result) { return ( <> @@ -433,12 +354,9 @@ class DeviceInfo extends Component {
); - } - - renderButtons() { - const { classes, device } = this.props; - const { snapshot, carHealth, windowWidth, isTimeSelectOpen } = this.state; + }; + const renderButtons = () => { let batteryVoltage; let batteryBackground = Colors.grey400; if (deviceIsOnline(device) && carHealth?.result && carHealth.result.peripheralState && carHealth.result.peripheralState.voltage) { @@ -476,26 +394,25 @@ class DeviceInfo extends Component { )}
- - + {error} - + ); - } + }; - renderSnapshotImage(src, isFront) { - const { classes } = this.props; + const renderSnapshotImage = (src, isFront) => { if (!src) { return (
@@ -506,12 +423,49 @@ class DeviceInfo extends Component { } return ; - } -} - -const stateToProps = (state) => ({ - dongleId: state.dongleId, - device: state.device, -}); + }; + + const containerPadding = windowWidth > 520 ? 36 : 16; + const largeSnapshotPadding = windowWidth > 1440 ? '12px 0' : 0; + + return ( + <> + + +
+ {windowWidth >= 768 ? ( +
+ {deviceNamePretty(device)} +
{renderStats()}
+
{renderButtons()}
+
+ ) : ( + <> +
+ {deviceNamePretty(device)} +
+
{renderButtons()}
+ {deviceStats.result &&
{renderStats()}
} + + )} +
+ {snapshot.result && ( +
+ {windowWidth >= 640 ? ( +
+
{renderSnapshotImage(snapshot.result.jpegBack, false)}
+
{renderSnapshotImage(snapshot.result.jpegFront, true)}
+
+ ) : ( +
+
{renderSnapshotImage(snapshot.result.jpegBack, false)}
+
{renderSnapshotImage(snapshot.result.jpegFront, true)}
+
+ )} +
+ )} + + ); +}; -export default connect(stateToProps)(withStyles(styles)(DeviceInfo)); +export default withStyles(styles)(DeviceInfo); diff --git a/src/components/DriveVideo/index.jsx b/src/components/DriveVideo/index.jsx index 26c70125..7824d937 100644 --- a/src/components/DriveVideo/index.jsx +++ b/src/components/DriveVideo/index.jsx @@ -3,9 +3,9 @@ import { video as Video } from '@commaai/api'; import { CircularProgress, Typography } from '@material-ui/core'; import debounce from 'debounce'; -import React, { Component } from 'react'; +import { useCallback, useEffect, useRef, useState } from 'react'; import ReactPlayer from 'react-player/file'; -import { connect } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; import Colors from '../../colors'; import { ErrorOutline } from '../../icons'; import { selectCurrentRoute } from '../../selectors/route'; @@ -53,158 +53,132 @@ const getVideoState = (videoPlayer) => { }; }; -class DriveVideo extends Component { - constructor(props) { - super(props); +const DriveVideo = ({ playSpeed, onAudioStatusChange, isMuted }) => { + const dispatch = useDispatch(); + const desiredPlaySpeed = useSelector((state) => state.desiredPlaySpeed); + const isBufferingVideo = useSelector((state) => state.isBufferingVideo); + const currentRoute = useSelector(selectCurrentRoute); - this.onVideoBuffering = this.onVideoBuffering.bind(this); - this.onHlsError = this.onHlsError.bind(this); - this.onVideoError = this.onVideoError.bind(this); - this.onVideoResume = this.onVideoResume.bind(this); - this.syncVideo = debounce(this.syncVideo.bind(this), 200, true); - this.firstSeek = true; + const [src, setSrc] = useState(null); + const [videoError, setVideoError] = useState(null); - this.videoPlayer = React.createRef(); + const videoPlayer = useRef(null); + const firstSeek = useRef(true); + const videoSyncIntv = useRef(null); + const prevRouteFullname = useRef(null); - this.state = { - src: null, - videoError: null, - }; - } + const currentVideoTime = useCallback( + (offset = currentOffset()) => { + if (!currentRoute) { + return 0; + } - componentDidMount() { - const { playSpeed } = this.props; - if (this.videoPlayer.current) { - this.videoPlayer.current.playbackRate = playSpeed || 1; - } - this.updateVideoSource({}); - this.syncVideo(); - this.videoSyncIntv = setInterval(this.syncVideo, 500); - } + if (currentRoute.videoStartOffset) { + offset -= currentRoute.videoStartOffset; + } - componentDidUpdate(prevProps) { - this.updateVideoSource(prevProps); - this.syncVideo(); - } + offset /= 1000; - componentWillUnmount() { - if (this.videoSyncIntv) { - clearTimeout(this.videoSyncIntv); - this.videoSyncIntv = null; - } - } + return Math.max(0, offset); + }, + [currentRoute], + ); - onVideoBuffering() { - const { dispatch, currentRoute } = this.props; - const videoPlayer = this.videoPlayer.current; - if (!videoPlayer || !currentRoute || !videoPlayer.getDuration()) { + const onVideoBuffering = useCallback(() => { + const player = videoPlayer.current; + if (!player || !currentRoute || !player.getDuration()) { dispatch(bufferVideo(true)); } - if (this.firstSeek) { - this.firstSeek = false; - videoPlayer.seekTo(this.currentVideoTime(), 'seconds'); + if (firstSeek.current) { + firstSeek.current = false; + player.seekTo(currentVideoTime(), 'seconds'); } - const { hasLoaded } = getVideoState(videoPlayer); - const { readyState } = videoPlayer.getInternalPlayer(); + const { hasLoaded } = getVideoState(player); + const { readyState } = player.getInternalPlayer(); if (!hasLoaded || readyState < 2) { dispatch(bufferVideo(true)); } - } + }, [dispatch, currentRoute, currentVideoTime]); /** * @param {Error} e */ - onHlsError(e) { - const { dispatch } = this.props; - dispatch(bufferVideo(true)); + const onHlsError = useCallback( + (e) => { + dispatch(bufferVideo(true)); - if (e.type === 'mediaError' && (e.details === 'bufferStalledError' || e.details === 'bufferNudgeOnStall')) { - // buffer but no error - return; - } + if (e.type === 'mediaError' && (e.details === 'bufferStalledError' || e.details === 'bufferNudgeOnStall')) { + // buffer but no error + return; + } - if (e.type === 'networkError' && e.response?.code === 404) { - this.setState({ videoError: 'This video segment has not uploaded yet or has been deleted.' }); - } else { - this.setState({ videoError: 'Unable to load video' }); - } - } + if (e.type === 'networkError' && e.response?.code === 404) { + setVideoError('This video segment has not uploaded yet or has been deleted.'); + } else { + setVideoError('Unable to load video'); + } + }, + [dispatch], + ); /** * @param {Error} e * @param {any} [data] */ - onVideoError(e, data) { - if (!e) { - console.warn('Unknown video error', { e, data }); - return; - } - - if (e === 'hlsError') { - this.onHlsError(data); - return; - } - - if (e.name === 'AbortError') { - // ignore - return; - } - - if (e.target?.src?.startsWith(window.location.origin) && e.target.src.endsWith('undefined')) { - // TODO: figure out why the src isn't set properly - // Sometimes an error will be thrown because we try to play - // src: "https://connect.comma.ai/.../undefined" - console.warn('Video error with undefined src, ignoring', { e, data }); - return; - } + const onVideoError = useCallback( + (e, data) => { + if (!e) { + console.warn('Unknown video error', { e, data }); + return; + } - const { dispatch } = this.props; - dispatch(bufferVideo(true)); + if (e === 'hlsError') { + onHlsError(data); + return; + } - if (e.type === 'networkError') { - console.error('Network error', { e, data }); - this.setState({ videoError: 'Unable to load video. Check network connection.' }); - return; - } + if (e.name === 'AbortError') { + // ignore + return; + } - const videoError = e.response?.code === 404 ? 'This video segment has not uploaded yet or has been deleted.' : e.response?.text || 'Unable to load video'; - this.setState({ videoError }); - } + if (e.target?.src?.startsWith(window.location.origin) && e.target.src.endsWith('undefined')) { + // TODO: figure out why the src isn't set properly + // Sometimes an error will be thrown because we try to play + // src: "https://connect.comma.ai/.../undefined" + console.warn('Video error with undefined src, ignoring', { e, data }); + return; + } - onVideoResume() { - const { videoError } = this.state; - if (videoError) this.setState({ videoError: null }); - } + dispatch(bufferVideo(true)); - updateVideoSource(prevProps) { - let { src } = this.state; - const { currentRoute } = this.props; - if (!currentRoute) { - if (src !== '') { - this.setState({ src: '', videoError: null }); + if (e.type === 'networkError') { + console.error('Network error', { e, data }); + setVideoError('Unable to load video. Check network connection.'); + return; } - return; - } - if (src === '' || !prevProps.currentRoute || prevProps.currentRoute?.fullname !== currentRoute.fullname) { - src = Video.getQcameraStreamUrl(currentRoute.fullname, currentRoute.share_exp, currentRoute.share_sig); - this.setState({ src, videoError: null }); - this.syncVideo(); - } - } + const error = e.response?.code === 404 ? 'This video segment has not uploaded yet or has been deleted.' : e.response?.text || 'Unable to load video'; + setVideoError(error); + }, + [dispatch, onHlsError], + ); - syncVideo() { - const { dispatch, isBufferingVideo, isMuted } = this.props; - const videoPlayer = this.videoPlayer.current; - if (!videoPlayer || !videoPlayer.getInternalPlayer() || !videoPlayer.getDuration()) { + const onVideoResume = useCallback(() => { + if (videoError) setVideoError(null); + }, [videoError]); + + const syncVideo = useCallback(() => { + const player = videoPlayer.current; + if (!player || !player.getInternalPlayer() || !player.getDuration()) { return; } - let { desiredPlaySpeed: newPlaybackRate } = this.props; - const desiredVideoTime = this.currentVideoTime(); - const curVideoTime = videoPlayer.getCurrentTime(); + let newPlaybackRate = desiredPlaySpeed; + const desiredVideoTime = currentVideoTime(); + const curVideoTime = player.getCurrentTime(); const timeDiff = desiredVideoTime - curVideoTime; if (Math.abs(timeDiff) <= Math.max(0.1, 0.5 * newPlaybackRate)) { @@ -212,18 +186,18 @@ class DriveVideo extends Component { if (!isIos()) { newPlaybackRate = Math.max(0, newPlaybackRate + Math.round(timeDiff * 10) / 10); } - } else if (desiredVideoTime === 0 && timeDiff < 0 && curVideoTime !== videoPlayer.getDuration()) { + } else if (desiredVideoTime === 0 && timeDiff < 0 && curVideoTime !== player.getDuration()) { // logs start earlier than video, so skip to video ts 0 dispatch(seek(currentOffset() - timeDiff * 1000)); } else { - videoPlayer.seekTo(desiredVideoTime, 'seconds'); + player.seekTo(desiredVideoTime, 'seconds'); } // most browsers don't support more than 16x playback rate, firefox mutes audio above 8x causing audio to cut in and out with timeDiff rate shifts newPlaybackRate = Math.max(0, Math.min(isFirefox() && !isMuted ? 8 : 16, newPlaybackRate)); - const internalPlayer = videoPlayer.getInternalPlayer(); + const internalPlayer = player.getInternalPlayer(); - const { hasLoaded } = getVideoState(videoPlayer); + const { hasLoaded } = getVideoState(player); if (isBufferingVideo && internalPlayer.readyState >= 4) { dispatch(bufferVideo(false)); } else if (isBufferingVideo || !hasLoaded || internalPlayer.readyState < 2) { @@ -233,7 +207,7 @@ class DriveVideo extends Component { newPlaybackRate = 0; // in some circumstances, iOS won't update readyState unless temporarily paused } - if (videoPlayer.getInternalPlayer('hls')) { + if (player.getInternalPlayer('hls')) { if (!internalPlayer.paused && newPlaybackRate === 0) { internalPlayer.pause(); } else if (internalPlayer.playbackRate !== newPlaybackRate && newPlaybackRate !== 0) { @@ -249,86 +223,98 @@ class DriveVideo extends Component { // TODO: fix iOS bug where video doesn't stop buffering while paused internalPlayer.playbackRate = newPlaybackRate; } - } + }, [dispatch, desiredPlaySpeed, isBufferingVideo, isMuted, currentVideoTime]); + + const syncVideoDebounced = useRef(debounce(syncVideo, 200, true)); - currentVideoTime(offset = currentOffset()) { - const { currentRoute } = this.props; + // Update video source when route changes + useEffect(() => { if (!currentRoute) { - return 0; + if (src !== '') { + setSrc(''); + setVideoError(null); + } + return; } - if (currentRoute.videoStartOffset) { - offset -= currentRoute.videoStartOffset; + if (src === '' || prevRouteFullname.current !== currentRoute.fullname) { + const newSrc = Video.getQcameraStreamUrl(currentRoute.fullname, currentRoute.share_exp, currentRoute.share_sig); + setSrc(newSrc); + setVideoError(null); + prevRouteFullname.current = currentRoute.fullname; + syncVideoDebounced.current(); } + }, [currentRoute, src]); - offset /= 1000; - - return Math.max(0, offset); - } - - render() { - const { desiredPlaySpeed, isBufferingVideo, currentRoute, onAudioStatusChange, isMuted } = this.props; - const { src, videoError } = this.state; + // Setup video sync interval and initial playback rate + useEffect(() => { + if (videoPlayer.current) { + videoPlayer.current.playbackRate = playSpeed || 1; + } + syncVideoDebounced.current(); + videoSyncIntv.current = setInterval(() => syncVideoDebounced.current(), 500); - const onPlayerReady = (player) => { - if (isIos()) { - // ios does not support hls.js and on other browsers hls.js does not directly play the m3u8 so audioTracks are not visible - const videoElement = player.getInternalPlayer(); - if (videoElement && videoElement.audioTracks && videoElement.audioTracks.length > 0) { + return () => { + if (videoSyncIntv.current) { + clearInterval(videoSyncIntv.current); + videoSyncIntv.current = null; + } + }; + }, [playSpeed]); + + // Sync video on updates + useEffect(() => { + syncVideoDebounced.current(); + }); + + const onPlayerReady = (player) => { + if (isIos()) { + // ios does not support hls.js and on other browsers hls.js does not directly play the m3u8 so audioTracks are not visible + const videoElement = player.getInternalPlayer(); + if (videoElement && videoElement.audioTracks && videoElement.audioTracks.length > 0) { + if (onAudioStatusChange) { + onAudioStatusChange(true); + } + } + } else { + // on other platforms, inspect audio tracks before hls.js changes things + const hlsPlayer = player.getInternalPlayer('hls'); + if (hlsPlayer) { + hlsPlayer.on('hlsBufferCodecs', (event, data) => { if (onAudioStatusChange) { - onAudioStatusChange(true); + onAudioStatusChange(!!data.audio); } - } - } else { - // on other platforms, inspect audio tracks before hls.js changes things - const hlsPlayer = player.getInternalPlayer('hls'); - if (hlsPlayer) { - hlsPlayer.on('hlsBufferCodecs', (event, data) => { - if (onAudioStatusChange) { - onAudioStatusChange(!!data.audio); - } - }); - } + }); } - }; + } + }; - return ( -
- - -
- ); - } -} - -const stateToProps = (state) => ({ - dongleId: state.dongleId, - desiredPlaySpeed: state.desiredPlaySpeed, - offset: state.offset, - startTime: state.startTime, - isBufferingVideo: state.isBufferingVideo, - routes: state.routes, - currentRoute: selectCurrentRoute(state), -}); - -export default connect(stateToProps)(DriveVideo); + return ( +
+ + +
+ ); +}; + +export default DriveVideo; diff --git a/src/components/DriveView/Media.jsx b/src/components/DriveView/Media.jsx index 3d27d7b7..6a78509d 100644 --- a/src/components/DriveView/Media.jsx +++ b/src/components/DriveView/Media.jsx @@ -4,13 +4,14 @@ import ContentCopyIcon from '@material-ui/icons/ContentCopy'; import ShareIcon from '@material-ui/icons/Share'; import WarningIcon from '@material-ui/icons/Warning'; import * as Sentry from '@sentry/react'; -import { Component } from 'react'; -import { connect } from 'react-redux'; +import { useCallback, useEffect, useRef, useState } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; import { updateRoute } from '../../actions'; import { fetchEvents } from '../../actions/cached'; import { doUpload, FILE_NAMES, fetchAthenaQueue, fetchFiles, fetchUploadUrls, setRouteViewed, updateFiles } from '../../actions/files'; import Colors from '../../colors'; import { InfoOutline } from '../../icons'; +import { selectCurrentRoute } from '../../selectors/route'; import { bufferVideo } from '../../timeline/playback'; import { deviceIsOnline, deviceOnCellular, getSegmentNumber } from '../../utils'; import DriveMap from '../DriveMap'; @@ -204,105 +205,50 @@ const MediaType = { MAP: 'map', }; -class Media extends Component { - constructor(props) { - super(props); - - this.state = { - inView: MediaType.VIDEO, - windowWidth: window.innerWidth, - downloadMenu: null, - moreInfoMenu: null, - uploadModal: false, - dcamUploadInfo: null, - routePreserved: null, - isMuted: true, - hasAudio: false, - }; - - this.handleMuteToggle = this.handleMuteToggle.bind(this); - this.handleAudioStatusChange = this.handleAudioStatusChange.bind(this); - this.renderMediaOptions = this.renderMediaOptions.bind(this); - this.renderMenus = this.renderMenus.bind(this); - this.renderUploadMenuItem = this.renderUploadMenuItem.bind(this); - this.copySegmentName = this.copySegmentName.bind(this); - this.openInUseradmin = this.openInUseradmin.bind(this); - this.shareCurrentRoute = this.shareCurrentRoute.bind(this); - this.uploadFile = this.uploadFile.bind(this); - this.uploadFilesAll = this.uploadFilesAll.bind(this); - this.getUploadStats = this.getUploadStats.bind(this); - this._uploadStats = this._uploadStats.bind(this); - this.downloadFile = this.downloadFile.bind(this); - this.onPublicToggle = this.onPublicToggle.bind(this); - this.fetchRoutePreserved = this.fetchRoutePreserved.bind(this); - this.onPreserveToggle = this.onPreserveToggle.bind(this); - - this.routeViewed = false; - } - - handleMuteToggle() { - this.setState((prevState) => ({ isMuted: !prevState.isMuted })); - } - - handleAudioStatusChange(hasAudio) { - this.setState({ hasAudio }); - } - - componentDidMount() { - this.componentDidUpdate({}, {}); - } - - componentDidUpdate(prevProps, prevState) { - const { windowWidth, inView, downloadMenu, moreInfoMenu, routePreserved } = this.state; - const showMapAlways = windowWidth >= 1536; - if (showMapAlways && inView === MediaType.MAP) { - this.setState({ inView: MediaType.VIDEO }); - } - - if (!showMapAlways && inView === MediaType.MAP && this.props.isBufferingVideo) { - this.props.dispatch(bufferVideo(false)); - } - - if (prevProps.currentRoute !== this.props.currentRoute && this.props.currentRoute) { - this.props.dispatch(fetchEvents(this.props.currentRoute)); - } - - if ( - this.props.currentRoute && - ((!prevState.downloadMenu && downloadMenu) || (!this.props.files && !prevState.moreInfoMenu && moreInfoMenu) || (!prevProps.currentRoute && (downloadMenu || moreInfoMenu))) - ) { - if ((this.props.device && !this.props.device.shared) || this.props.profile?.superuser) { - this.props.dispatch(fetchAthenaQueue(this.props.dongleId)); - } - this.props.dispatch(fetchFiles(this.props.currentRoute.fullname)); - } - - if ( - routePreserved === null && - (this.props.device?.is_owner || this.props.profile?.superuser) && - (!prevState.moreInfoMenu && !prevProps.currentRoute) !== (moreInfoMenu && this.props.currentRoute) - ) { - this.fetchRoutePreserved(); - } - - if (!this.routeViewed && this.props.currentRoute && ((this.props.device && !this.props.device.shared) || this.props.profile?.superuser)) { - this.props.dispatch(setRouteViewed(this.props.dongleId, this.props.currentRoute.fullname)); - this.routeViewed = true; - } - } - - async copySegmentName() { - const { currentRoute } = this.props; +const Media = ({ classes, menusOnly }) => { + // Redux state + const dispatch = useDispatch(); + const dongleId = useSelector((state) => state.dongleId); + const device = useSelector((state) => state.device); + const currentRoute = useSelector(selectCurrentRoute); + const loop = useSelector((state) => state.loop); + const files = useSelector((state) => state.files); + const profile = useSelector((state) => state.profile); + const isBufferingVideo = useSelector((state) => state.isBufferingVideo); + + // State + const [inView, setInView] = useState(MediaType.VIDEO); + const [windowWidth, setWindowWidth] = useState(window.innerWidth); + const [downloadMenu, setDownloadMenu] = useState(null); + const [moreInfoMenu, setMoreInfoMenu] = useState(null); + const [uploadModal, setUploadModal] = useState(false); + const [dcamUploadInfo, setDcamUploadInfo] = useState(null); + const [routePreserved, setRoutePreserved] = useState(null); + const [isMuted, setIsMuted] = useState(true); + const [hasAudio, setHasAudio] = useState(false); + + // Refs + const routeViewed = useRef(false); + const prevCurrentRoute = useRef(null); + + const handleMuteToggle = () => { + setIsMuted((prev) => !prev); + }; + + const handleAudioStatusChange = (audio) => { + setHasAudio(audio); + }; + + const copySegmentName = async () => { if (!currentRoute || !navigator.clipboard) { return; } await navigator.clipboard.writeText(`${currentRoute.fullname.replace('|', '/')}/${getSegmentNumber(currentRoute)}`); - this.setState({ moreInfoMenu: null }); - } + setMoreInfoMenu(null); + }; - openInUseradmin() { - const { currentRoute } = this.props; + const openInUseradmin = () => { if (!currentRoute) { return; } @@ -312,9 +258,9 @@ class Media extends Component { if (win.focus) { win.focus(); } - } + }; - async shareCurrentRoute() { + const shareCurrentRoute = async () => { try { await navigator.share({ title: 'comma connect', @@ -324,10 +270,9 @@ class Media extends Component { console.error(err); Sentry.captureException(err, { fingerprint: 'media_navigator_share' }); } - } + }; - async uploadFile(type) { - const { dongleId, currentRoute } = this.props; + const uploadFile = async (type) => { if (!currentRoute) { return; } @@ -337,7 +282,7 @@ class Media extends Component { const uploading = {}; uploading[fileName] = { requested: true }; - this.props.dispatch(updateFiles(uploading)); + dispatch(updateFiles(uploading)); const paths = []; const url_promises = []; @@ -351,12 +296,11 @@ class Media extends Component { const urls = await Promise.all(url_promises); if (urls) { - this.props.dispatch(doUpload(dongleId, paths, urls)); + dispatch(doUpload(dongleId, paths, urls)); } - } + }; - async uploadFilesAll(types) { - const { dongleId, currentRoute, loop, files } = this.props; + const uploadFilesAll = async (types) => { if (types === undefined) { types = ['logs', 'cameras', 'dcameras', 'ecameras']; } @@ -377,7 +321,7 @@ class Media extends Component { }); } } - this.props.dispatch(updateFiles(uploading)); + dispatch(updateFiles(uploading)); const paths = Object.keys(uploading).flatMap((fileName) => { const [seg, type] = fileName.split('/'); @@ -386,41 +330,46 @@ class Media extends Component { const urls = await fetchUploadUrls(dongleId, paths); if (urls) { - this.props.dispatch(doUpload(dongleId, paths, urls)); + dispatch(doUpload(dongleId, paths, urls)); } - } + }; - _uploadStats(types, count, uploaded, uploading, paused, requested) { - const { currentRoute, loop, files } = this.props; - const adjusted_start_time = currentRoute.start_time_utc_millis + loop.startTime; + const _uploadStats = useCallback( + (types, count, uploaded, uploading, paused, requested) => { + if (!currentRoute || !files) { + return [count, uploaded, uploading, paused, requested]; + } - for (let i = 0; i < currentRoute.segment_numbers.length; i++) { - if (currentRoute.segment_start_times[i] < adjusted_start_time + loop.duration && currentRoute.segment_end_times[i] > adjusted_start_time) { - for (let j = 0; j < types.length; j++) { - count += 1; - const log = files[`${currentRoute.fullname}--${currentRoute.segment_numbers[i]}/${types[j]}`]; - if (log) { - uploaded += Boolean(log.url || log.notFound); - uploading += Boolean(log.progress !== undefined); - paused += Boolean(log.paused); - requested += Boolean(log.requested); + const adjusted_start_time = currentRoute.start_time_utc_millis + loop.startTime; + + for (let i = 0; i < currentRoute.segment_numbers.length; i++) { + if (currentRoute.segment_start_times[i] < adjusted_start_time + loop.duration && currentRoute.segment_end_times[i] > adjusted_start_time) { + for (let j = 0; j < types.length; j++) { + count += 1; + const log = files[`${currentRoute.fullname}--${currentRoute.segment_numbers[i]}/${types[j]}`]; + if (log) { + uploaded += Boolean(log.url || log.notFound); + uploading += Boolean(log.progress !== undefined); + paused += Boolean(log.paused); + requested += Boolean(log.requested); + } } } } - } - return [count, uploaded, uploading, paused, requested]; - } + return [count, uploaded, uploading, paused, requested]; + }, + [currentRoute, loop, files], + ); - getUploadStats() { - const { currentRoute, files } = this.props; + const getUploadStats = useCallback(() => { if (!files || !currentRoute) { return null; } - const [countRlog, uploadedRlog, uploadingRlog, pausedRlog, requestedRlog] = this._uploadStats(['logs'], 0, 0, 0, 0, 0); + const [countRlog, uploadedRlog, uploadingRlog, pausedRlog, requestedRlog] = _uploadStats(['logs'], 0, 0, 0, 0, 0); const camTypes = ['cameras', 'dcameras', 'ecameras']; - const [countAll, uploadedAll, uploadingAll, pausedAll, requestedAll] = this._uploadStats(camTypes, countRlog, uploadedRlog, uploadingRlog, pausedRlog, requestedRlog); + const [countAll, uploadedAll, uploadingAll, pausedAll, requestedAll] = _uploadStats(camTypes, countRlog, uploadedRlog, uploadingRlog, pausedRlog, requestedRlog); return { canRequestAll: countAll - uploadedAll - uploadingAll - requestedAll, @@ -431,18 +380,18 @@ class Media extends Component { isUploadedRlog: !(countRlog - uploadedRlog), isPausedAll: Boolean(pausedAll > 0 && pausedAll === uploadingAll), }; - } + }, [files, currentRoute, _uploadStats]); - downloadFile(file, type) { + const downloadFile = (file, type) => { window.location.href = file.url; - } + }; - async onPublicToggle(ev) { + const onPublicToggle = async (ev) => { const isPublic = ev.target.checked; try { - const resp = await Drives.setRoutePublic(this.props.currentRoute.fullname, isPublic); - if (resp && resp.fullname === this.props.currentRoute.fullname) { - this.props.dispatch(updateRoute(this.props.currentRoute.fullname, { is_public: resp.is_public })); + const resp = await Drives.setRoutePublic(currentRoute.fullname, isPublic); + if (resp && resp.fullname === currentRoute.fullname) { + dispatch(updateRoute(currentRoute.fullname, { is_public: resp.is_public })); if (resp.is_public !== isPublic) { return { error: 'unable to update' }; } @@ -453,115 +402,102 @@ class Media extends Component { Sentry.captureException(err, { fingerprint: 'media_toggle_public' }); return { error: 'could not update' }; } - } + }; - async fetchRoutePreserved() { + const fetchRoutePreserved = useCallback(async () => { try { - const resp = await Drives.getPreservedRoutes(this.props.dongleId); - if (resp && Array.isArray(resp) && this.props.currentRoute) { - if (resp.find((r) => r.fullname === this.props.currentRoute.fullname)) { - this.setState({ routePreserved: true }); + const resp = await Drives.getPreservedRoutes(dongleId); + if (resp && Array.isArray(resp) && currentRoute) { + if (resp.find((r) => r.fullname === currentRoute.fullname)) { + setRoutePreserved(true); return; } - this.setState({ routePreserved: false }); + setRoutePreserved(false); } } catch (err) { console.error(err); Sentry.captureException(err, { fingerprint: 'media_fetch_preserved' }); } - } + }, [dongleId, currentRoute]); - async onPreserveToggle(ev) { + const onPreserveToggle = async (ev) => { const preserved = ev.target.checked; try { - const resp = await Drives.setRoutePreserved(this.props.currentRoute.fullname, preserved); + const resp = await Drives.setRoutePreserved(currentRoute.fullname, preserved); if (resp && resp.success) { - this.setState({ routePreserved: preserved }); + setRoutePreserved(preserved); return null; } - this.fetchRoutePreserved(); + fetchRoutePreserved(); return { error: 'unable to update' }; } catch (err) { console.error(err); Sentry.captureException(err, { fingerprint: 'media_toggle_preserved' }); - this.fetchRoutePreserved(); + fetchRoutePreserved(); return { error: 'could not update' }; } - } + }; - render() { - const { classes } = this.props; - const { inView, windowWidth, isMuted, hasAudio } = this.state; - - if (this.props.menusOnly) { - // for test - return this.renderMenus(true); - } - - const showMapAlways = windowWidth >= 1536; - const mediaContainerStyle = showMapAlways ? { width: '60%' } : { width: '100%' }; - const mapContainerStyle = showMapAlways ? { width: '40%', marginBottom: 62, marginTop: 46, paddingLeft: 24 } : { width: '100%' }; + const renderUploadMenuItem = ([file, name, type]) => { + const canUpload = device.is_owner || (profile && profile.superuser); + const uploadButtonWidth = windowWidth < 425 ? 80 : 120; - return ( -
- this.setState({ windowWidth: ww })} /> -
- {this.renderMediaOptions(showMapAlways)} - {inView === MediaType.VIDEO && } - {inView === MediaType.MAP && !showMapAlways && ( -
- -
- )} -
- -
+ let button; + if (!files) { + button = null; + } else if (file.url) { + button = ( + + ); + } else if (file.progress !== undefined) { + button = ( +
+ {file.current ? `${Math.floor(file.progress * 100)}%` : file.paused ? 'paused' : 'pending'}
- {inView === MediaType.VIDEO && showMapAlways && ( -
- -
- )} -
- ); - } + ); + } else if (file.requested) { + button = ( +
+ +
+ ); + } else if (file.notFound) { + button = ( +
setDcamUploadInfo(ev.target) : null} + onMouseLeave={type === 'dcameras' ? () => setDcamUploadInfo(null) : null} + > + not found + {type === 'dcameras' && } +
+ ); + } else if (!canUpload) { + button = ( + + ); + } else { + button = ( + + ); + } - renderMediaOptions(showMapAlways) { - const { classes } = this.props; - const { inView } = this.state; return ( - <> -
- {showMapAlways ? ( -
- ) : ( -
-
this.setState({ inView: MediaType.VIDEO })}> - Video -
-
this.setState({ inView: MediaType.MAP })}> - Map -
-
- )} -
-
this.setState({ downloadMenu: ev.target })}> - Files -
-
this.setState({ moreInfoMenu: ev.target })}> - More info -
-
-
- {this.renderMenus()} - + + {name} + {button} + ); - } - - renderMenus(alwaysOpen = false) { - const { currentRoute, device, classes, files, profile } = this.props; - const { downloadMenu, moreInfoMenu, uploadModal, windowWidth, dcamUploadInfo, routePreserved } = this.state; + }; + const renderMenus = (alwaysOpen = false) => { if (!device) { return null; } @@ -587,7 +523,7 @@ class Media extends Component { [rlog, 'Log data', 'logs'], ]; - const stats = this.getUploadStats(); + const stats = getUploadStats(); const rlogUploadDisabled = !stats || stats.isUploadedRlog || stats.isUploadingRlog || !stats.canRequestRlog; const allUploadDisabled = !stats || stats.isUploadedAll || stats.isUploadingAll || !stats.canRequestAll; @@ -597,7 +533,7 @@ class Media extends Component { id="menu-download" open={Boolean(alwaysOpen || downloadMenu)} anchorEl={downloadMenu} - onClose={() => this.setState({ downloadMenu: null })} + onClose={() => setDownloadMenu(null)} anchorOrigin={{ vertical: 'top', horizontal: 'right' }} transformOrigin={{ vertical: 'top', horizontal: 'right' }} > @@ -606,12 +542,12 @@ class Media extends Component {
)} - {buttons.filter((b) => Boolean(b)).map(this.renderUploadMenuItem)} + {buttons.filter((b) => Boolean(b)).map(renderUploadMenuItem)} All logs {Boolean(files && canUpload && !rlogUploadDisabled) && ( - )} @@ -624,7 +560,7 @@ class Media extends Component { All files {Boolean(files && canUpload && !allUploadDisabled) && ( - )} @@ -637,7 +573,14 @@ class Media extends Component { {deviceIsOnline(device) || !files ? ( this.setState({ uploadModal: true, downloadMenu: null }) : null} + onClick={ + files + ? () => { + setUploadModal(true); + setDownloadMenu(null); + } + : null + } style={files ? { pointerEvents: 'auto' } : { color: Colors.white60 }} className={classes.filesItem} disabled={!files} @@ -667,120 +610,149 @@ class Media extends Component { id="menu-info" open={Boolean(alwaysOpen || moreInfoMenu)} anchorEl={moreInfoMenu} - onClose={() => this.setState({ moreInfoMenu: null })} + onClose={() => setMoreInfoMenu(null)} transformOrigin={{ vertical: 'top', horizontal: windowWidth > 400 ? 260 : 300 }} > - 400 ? '0.8rem' : '0.7rem' }}> + 400 ? '0.8rem' : '0.7rem' }}>
{currentRoute ? `${currentRoute.fullname.replace('|', '/')}/${getSegmentNumber(currentRoute)}` : '---'}
{typeof navigator.share !== 'undefined' && ( - + Share this route )} - View in useradmin + View in useradmin {Boolean(device?.is_owner || (profile && profile.superuser)) && [ , - + , - + , ]} - this.setState({ uploadModal: false })} - update={Boolean(moreInfoMenu || uploadModal || downloadMenu)} - store={this.props.store} - device={device} - /> + setUploadModal(false)} update={Boolean(moreInfoMenu || uploadModal || downloadMenu)} device={device} /> make sure to enable the “Record and Upload Driver Camera” toggle ); - } + }; - renderUploadMenuItem([file, name, type]) { - const { device, classes, files, profile } = this.props; - const { windowWidth } = this.state; + const renderMediaOptions = (showMapAlways) => { + return ( + <> +
+ {showMapAlways ? ( +
+ ) : ( +
+
setInView(MediaType.VIDEO)}> + Video +
+
setInView(MediaType.MAP)}> + Map +
+
+ )} +
+
setDownloadMenu(ev.target)}> + Files +
+
setMoreInfoMenu(ev.target)}> + More info +
+
+
+ {renderMenus()} + + ); + }; - const canUpload = device.is_owner || (profile && profile.superuser); - const uploadButtonWidth = windowWidth < 425 ? 80 : 120; + // Reset inView to VIDEO when showMapAlways and inView is MAP + useEffect(() => { + const showMapAlways = windowWidth >= 1536; + if (showMapAlways && inView === MediaType.MAP) { + setInView(MediaType.VIDEO); + } + }, [windowWidth, inView]); - let button; - if (!files) { - button = null; - } else if (file.url) { - button = ( - - ); - } else if (file.progress !== undefined) { - button = ( -
- {file.current ? `${Math.floor(file.progress * 100)}%` : file.paused ? 'paused' : 'pending'} -
- ); - } else if (file.requested) { - button = ( -
- -
- ); - } else if (file.notFound) { - button = ( -
this.setState({ dcamUploadInfo: ev.target }) : null} - onMouseLeave={type === 'dcameras' ? () => this.setState({ dcamUploadInfo: null }) : null} - > - not found - {type === 'dcameras' && } -
- ); - } else if (!canUpload) { - button = ( - - ); - } else { - button = ( - - ); + // Stop buffering when not showMapAlways and inView is MAP + useEffect(() => { + const showMapAlways = windowWidth >= 1536; + if (!showMapAlways && inView === MediaType.MAP && isBufferingVideo) { + dispatch(bufferVideo(false)); } + }, [windowWidth, inView, isBufferingVideo, dispatch]); - return ( - - {name} - {button} - - ); - } -} + // Fetch events when currentRoute changes + useEffect(() => { + if (currentRoute && prevCurrentRoute.current !== currentRoute) { + dispatch(fetchEvents(currentRoute)); + prevCurrentRoute.current = currentRoute; + } + }, [currentRoute, dispatch]); -import { selectCurrentRoute } from '../../selectors/route'; + // Fetch files when certain menu conditions are met + useEffect(() => { + if (currentRoute && (downloadMenu || moreInfoMenu)) { + if ((device && !device.shared) || profile?.superuser) { + dispatch(fetchAthenaQueue(dongleId)); + } + dispatch(fetchFiles(currentRoute.fullname)); + } + }, [currentRoute, downloadMenu, moreInfoMenu, device, profile, dongleId, dispatch]); -const stateToProps = (state) => ({ - dongleId: state.dongleId, - device: state.device, - routes: state.routes, - currentRoute: selectCurrentRoute(state), - loop: state.loop, - filter: state.filter, - files: state.files, - profile: state.profile, - isBufferingVideo: state.isBufferingVideo, -}); + // Fetch route preserved status + useEffect(() => { + if (routePreserved === null && (device?.is_owner || profile?.superuser) && moreInfoMenu && currentRoute) { + fetchRoutePreserved(); + } + }, [routePreserved, device, profile, moreInfoMenu, currentRoute, fetchRoutePreserved]); + + // Set route viewed once + useEffect(() => { + if (!routeViewed.current && currentRoute && ((device && !device.shared) || profile?.superuser)) { + dispatch(setRouteViewed(dongleId, currentRoute.fullname)); + routeViewed.current = true; + } + }, [currentRoute, device, profile, dongleId, dispatch]); + + if (menusOnly) { + // for test + return renderMenus(true); + } + + const showMapAlways = windowWidth >= 1536; + const mediaContainerStyle = showMapAlways ? { width: '60%' } : { width: '100%' }; + const mapContainerStyle = showMapAlways ? { width: '40%', marginBottom: 62, marginTop: 46, paddingLeft: 24 } : { width: '100%' }; + + return ( +
+ setWindowWidth(ww)} /> +
+ {renderMediaOptions(showMapAlways)} + {inView === MediaType.VIDEO && } + {inView === MediaType.MAP && !showMapAlways && ( +
+ +
+ )} +
+ +
+
+ {inView === MediaType.VIDEO && showMapAlways && ( +
+ +
+ )} +
+ ); +}; -export default connect(stateToProps)(withStyles(styles)(Media)); +export default withStyles(styles)(Media); diff --git a/src/components/DriveView/index.jsx b/src/components/DriveView/index.jsx index a1023676..1b1941ae 100644 --- a/src/components/DriveView/index.jsx +++ b/src/components/DriveView/index.jsx @@ -1,72 +1,60 @@ import { IconButton, Typography } from '@material-ui/core'; import dayjs from 'dayjs'; -import { Component } from 'react'; -import { connect } from 'react-redux'; +import { useSelector } from 'react-redux'; import { ArrowBackBold, CloseBold } from '../../icons'; import { navigate } from '../../navigation'; import { selectCurrentRoute, selectRouteZoom } from '../../selectors/route'; import Timeline from '../Timeline'; import Media from './Media'; -class DriveView extends Component { - constructor(props) { - super(props); - this.close = this.close.bind(this); - } +const DriveView = () => { + const dongleId = useSelector((state) => state.dongleId); + const routes = useSelector((state) => state.routes); + const zoom = useSelector(selectRouteZoom); + const currentRoute = useSelector(selectCurrentRoute); - onBack(zoom, currentRoute) { + const onBack = (zoom, currentRoute) => { if (currentRoute) { - navigate(`/${this.props.dongleId}/${currentRoute.log_id}`); + navigate(`/${dongleId}/${currentRoute.log_id}`); } - } - - close() { - navigate(`/${this.props.dongleId}`); - } - - render() { - const { zoom, currentRoute, routes } = this.props; - - const currentRouteBoundsSelected = zoom.start === 0 && zoom.end === currentRoute?.duration; - const backButtonDisabled = currentRouteBoundsSelected; - - // FIXME: end time not always same day as start time - const start = currentRoute.start_time_utc_millis + zoom.start; - const startDateObj = dayjs(start); - const startDay = startDateObj.format('dddd'); - const startTime = startDateObj.format(`MMM D${dayjs().year() === startDateObj.year() ? '' : ', YYYY'} @ HH:mm`); - const endTime = dayjs(start + (zoom.end - zoom.start)).format('HH:mm'); - - return ( -
-
-
-
- this.onBack(zoom, currentRoute)} aria-label="Go Back" disabled={backButtonDisabled}> - - -
- {`${startDay} `} - {`${startTime} - ${endTime}`} -
- - - + }; + + const close = () => { + navigate(`/${dongleId}`); + }; + + const currentRouteBoundsSelected = zoom.start === 0 && zoom.end === currentRoute?.duration; + const backButtonDisabled = currentRouteBoundsSelected; + + // FIXME: end time not always same day as start time + const start = currentRoute.start_time_utc_millis + zoom.start; + const startDateObj = dayjs(start); + const startDay = startDateObj.format('dddd'); + const startTime = startDateObj.format(`MMM D${dayjs().year() === startDateObj.year() ? '' : ', YYYY'} @ HH:mm`); + const endTime = dayjs(start + (zoom.end - zoom.start)).format('HH:mm'); + + return ( +
+
+
+
+ onBack(zoom, currentRoute)} aria-label="Go Back" disabled={backButtonDisabled}> + + +
+ {`${startDay} `} + {`${startTime} - ${endTime}`}
- + + +
-
{routes && routes.length === 0 ? Route does not exist. : }
+
+
{routes && routes.length === 0 ? Route does not exist. : }
- ); - } -} - -const stateToProps = (state) => ({ - dongleId: state.dongleId, - routes: state.routes, - zoom: selectRouteZoom(state), - currentRoute: selectCurrentRoute(state), -}); +
+ ); +}; -export default connect(stateToProps)(DriveView); +export default DriveView; diff --git a/src/components/Files/UploadQueue.jsx b/src/components/Files/UploadQueue.jsx index 9a1ff340..e3b435f4 100644 --- a/src/components/Files/UploadQueue.jsx +++ b/src/components/Files/UploadQueue.jsx @@ -1,8 +1,8 @@ import { Button, CircularProgress, Divider, LinearProgress, Modal, Paper, Typography, withStyles } from '@material-ui/core'; import HighlightOffIcon from '@material-ui/icons/HighlightOff'; import WarningIcon from '@material-ui/icons/Warning'; -import { Component } from 'react'; -import { connect } from 'react-redux'; +import { useCallback, useEffect, useState } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; import { cancelFetchUploadQueue, cancelUploads, FILE_NAMES, fetchUploadQueue } from '../../actions/files'; import Colors from '../../colors'; @@ -109,54 +109,33 @@ const styles = (theme) => ({ }, }); -class UploadQueue extends Component { - constructor(props) { - super(props); +const UploadQueue = ({ classes, device, open, onClose, update }) => { + const dispatch = useDispatch(); + const filesUploading = useSelector((state) => state.filesUploading); + const filesUploadingMeta = useSelector((state) => state.filesUploadingMeta); - this.state = { - windowWidth: window.innerWidth, - windowHeight: window.innerHeight, - cancelQueue: [], - }; - - this.cancelUploading = this.cancelUploading.bind(this); - this.uploadQueue = this.uploadQueue.bind(this); - } - - componentDidMount() { - this.componentDidUpdate({}, {}); - } - - componentDidUpdate(prevProps) { - if (prevProps.update !== this.props.update) { - this.uploadQueue(this.props.update); - } else if (this.props.update && prevProps.device.dongle_id !== this.props.device.dongle_id) { - this.uploadQueue(true); - } else if (this.props.update && prevProps.filesUploading !== this.props.filesUploading) { - this.uploadQueue(Boolean(Object.keys(this.props.filesUploading).length)); - } - } + const [windowWidth, setWindowWidth] = useState(window.innerWidth); + const [windowHeight, setWindowHeight] = useState(window.innerHeight); + const [cancelQueue, setCancelQueue] = useState([]); - componentWillUnmount() { - this.uploadQueue(false); - } - - uploadQueue(enable) { - if (enable) { - this.props.dispatch(fetchUploadQueue(this.props.device.dongle_id)); - } else { - cancelFetchUploadQueue(); - } - } + const uploadQueue = useCallback( + (enable) => { + if (enable) { + dispatch(fetchUploadQueue(device.dongle_id)); + } else { + cancelFetchUploadQueue(); + } + }, + [dispatch, device.dongle_id], + ); - async cancelUploading(ids) { - const { device, dispatch, filesUploading } = this.props; + const cancelUploading = async (ids) => { if (ids === undefined) { ids = Object.keys(filesUploading); } ids = ids.filter((id) => filesUploading[id] && !filesUploading[id].current); - this.setState((prevState) => ({ cancelQueue: prevState.cancelQueue.concat(ids) })); + setCancelQueue((prevCancelQueue) => prevCancelQueue.concat(ids)); if (deviceVersionAtLeast(device, '0.8.13')) { dispatch(cancelUploads(device.dongle_id, ids)); @@ -165,140 +144,164 @@ class UploadQueue extends Component { ids.forEach((id) => dispatch(cancelUploads(device.dongle_id, id))); } - this.uploadQueue(true); - } + uploadQueue(true); + }; - render() { - const { device, classes, filesUploading, filesUploadingMeta } = this.props; - const { cancelQueue, windowWidth, windowHeight } = this.state; + // Initial mount and update polling + useEffect(() => { + if (update) { + uploadQueue(update); + } + }, [update, uploadQueue]); - const deviceOffline = !deviceIsOnline(device); - const hasData = filesUploadingMeta.dongleId === device.dongle_id; - const hasUploading = !deviceOffline && hasData && Object.keys(filesUploading).length > 0; - const logNameLength = windowWidth < 600 ? 4 : 64; - const segmentNameStyle = windowWidth < 450 ? { fontSize: windowWidth < 400 ? '0.8rem' : '0.9rem' } : {}; - const cellStyle = { padding: windowWidth < 400 ? '0 2px' : windowWidth < 450 ? '0 4px' : '0 8px' }; + // Handle device changes + useEffect(() => { + if (update && device.dongle_id) { + uploadQueue(true); + } + }, [device.dongle_id, update, uploadQueue]); - const uploadSorted = Object.entries(filesUploading); - if (uploadSorted.length && uploadSorted[uploadSorted.length - 1][1].current) { - const curr = uploadSorted.splice([uploadSorted.length - 1], 1); - uploadSorted.unshift(curr[0]); + // Handle filesUploading changes + useEffect(() => { + if (update) { + const hasUploads = Boolean(Object.keys(filesUploading).length); + uploadQueue(hasUploads); } + }, [filesUploading, update, uploadQueue]); + + // Cleanup on unmount + useEffect(() => { + return () => { + uploadQueue(false); + }; + }, [uploadQueue]); + + const deviceOffline = !deviceIsOnline(device); + const hasData = filesUploadingMeta.dongleId === device.dongle_id; + const hasUploading = !deviceOffline && hasData && Object.keys(filesUploading).length > 0; + const logNameLength = windowWidth < 600 ? 4 : 64; + const segmentNameStyle = windowWidth < 450 ? { fontSize: windowWidth < 400 ? '0.8rem' : '0.9rem' } : {}; + const cellStyle = { padding: windowWidth < 400 ? '0 2px' : windowWidth < 450 ? '0 4px' : '0 8px' }; - const allPaused = uploadSorted.every((upload) => upload.paused); + const uploadSorted = Object.entries(filesUploading); + if (uploadSorted.length && uploadSorted[uploadSorted.length - 1][1].current) { + const curr = uploadSorted.splice([uploadSorted.length - 1], 1); + uploadSorted.unshift(curr[0]); + } + + const allPaused = uploadSorted.every((upload) => upload.paused); - return ( - <> - this.setState({ windowWidth: ww, windowHeight: wh })} /> - - -
- Upload queue - - {device.dongle_id} - -
- -
- {hasUploading ? ( - <> - {deviceOnCellular(device) && allPaused && ( -
-
- - Connect to WiFi -
- uploading paused on cellular connection + return ( + <> + { + setWindowWidth(ww); + setWindowHeight(wh); + }} + /> + + +
+ Upload queue + + {device.dongle_id} + +
+ +
+ {hasUploading ? ( + <> + {deviceOnCellular(device) && allPaused && ( +
+
+ + Connect to WiFi
- )} - - - - - - - {windowWidth >= 600 && - - - {uploadSorted.map(([id, upload]) => { - const isCancelled = cancelQueue.includes(id); - const [seg, type] = upload.fileName.split('/'); - const prog = upload.progress * 100; - const segString = seg.split('|')[1]; - return ( - + uploading paused on cellular connection + + )} +
- segment - - type - - progress - } -
+ + + + + + {windowWidth >= 600 && + + + {uploadSorted.map(([id, upload]) => { + const isCancelled = cancelQueue.includes(id); + const [seg, type] = upload.fileName.split('/'); + const prog = upload.progress * 100; + const segString = seg.split('|')[1]; + return ( + + + + {upload.current ? ( - - {upload.current ? ( - - ) : ( - <> - {windowWidth >= 600 && ( - - )} - - - )} - - ); - })} - -
+ segment + + type + + progress + } +
+
+ {segString.substring(0, 12)} + {segString.substring(12)} +
+
+ {FILE_NAMES[type][0].split('.')[0].substring(0, logNameLength)} + -
- {segString.substring(0, 12)} - {segString.substring(12)} +
+
- {FILE_NAMES[type][0].split('.')[0].substring(0, logNameLength)} - -
- -
-
- {upload.paused ? 'paused' : 'pending'} - - {isCancelled ? ( - - ) : ( - - )} + ) : ( + <> + {windowWidth >= 600 && ( + + {upload.paused ? 'paused' : 'pending'}
- - ) : deviceOffline ? ( -

device offline

- ) : hasData ? ( -

no uploads

- ) : ( - - )} -
-
- - -
- - - - ); - } -} - -const stateToProps = (state) => ({ - filesUploading: state.filesUploading, - filesUploadingMeta: state.filesUploadingMeta, -}); + )} + + {isCancelled ? ( + + ) : ( + + )} + + + )} + + ); + })} + + + + ) : deviceOffline ? ( +

device offline

+ ) : hasData ? ( +

no uploads

+ ) : ( + + )} +
+
+ + +
+
+
+ + ); +}; -export default connect(stateToProps)(withStyles(styles)(UploadQueue)); +export default withStyles(styles)(UploadQueue); diff --git a/src/components/Navigation/index.jsx b/src/components/Navigation/index.jsx index 96ac1617..fc48949f 100644 --- a/src/components/Navigation/index.jsx +++ b/src/components/Navigation/index.jsx @@ -3,9 +3,9 @@ import { Button, Typography, withStyles } from '@material-ui/core'; import { Clear } from '@material-ui/icons'; import * as Sentry from '@sentry/react'; import dayjs from 'dayjs'; -import React, { Component } from 'react'; +import { useCallback, useEffect, useRef, useState } from 'react'; import ReactMapGL, { GeolocateControl, HTMLOverlay, Layer, Marker, Source, WebMercatorViewport } from 'react-map-gl'; -import { connect } from 'react-redux'; +import { useSelector } from 'react-redux'; import Colors from '../../colors'; import { PinCarIcon } from '../../icons'; import { navigate } from '../../navigation'; @@ -129,167 +129,54 @@ const styles = () => ({ }, }); -const initialState = { - hasFocus: false, - carLastLocation: null, - carLastLocationTime: null, - carNetworkLocation: null, - carNetworkLocationAccuracy: null, - geoLocateCoords: null, - searchSelect: null, - searchLooking: false, - noFly: false, - windowWidth: window.innerWidth, - showPrimeAd: true, -}; - -class Navigation extends Component { - constructor(props) { - super(props); - this.mounted = null; - this.state = { - ...initialState, - viewport: { - ...DEFAULT_LOCATION, - zoom: 5, - }, - mapError: null, - windowWidth: window.innerWidth, - }; - - this.mapContainerRef = React.createRef(); - this.searchSelectBoxRef = React.createRef(); - this.primeAdBoxRef = React.createRef(); - this.carPinTooltipRef = React.createRef(); - - this.checkWebGLSupport = this.checkWebGLSupport.bind(this); - this.flyToMarkers = this.flyToMarkers.bind(this); - this.renderSearchOverlay = this.renderSearchOverlay.bind(this); - this.renderPrimeAd = this.renderPrimeAd.bind(this); - this.onGeolocate = this.onGeolocate.bind(this); - this.onCarSelect = this.onCarSelect.bind(this); - this.focus = this.focus.bind(this); - this.updateDevice = this.updateDevice.bind(this); - this.onResize = this.onResize.bind(this); - this.toggleCarPinTooltip = this.toggleCarPinTooltip.bind(this); - this.itemLoc = this.itemLoc.bind(this); - this.itemLngLat = this.itemLngLat.bind(this); - this.viewportChange = this.viewportChange.bind(this); - this.getDeviceLastLocation = this.getDeviceLastLocation.bind(this); - this.getDeviceNetworkLocation = this.getDeviceNetworkLocation.bind(this); - this.getCarLocation = this.getCarLocation.bind(this); - this.carLocationCircle = this.carLocationCircle.bind(this); - this.clearSearchSelect = this.clearSearchSelect.bind(this); - this.onContainerRef = this.onContainerRef.bind(this); - } - - componentDidMount() { - this.mounted = true; - this.checkWebGLSupport(); - this.componentDidUpdate({}, {}); - } - - componentDidUpdate(prevProps, prevState) { - const { dongleId, device } = this.props; - const { geoLocateCoords, search, carLastLocation, carNetworkLocation, searchSelect } = this.state; - - if ( - (carLastLocation && !prevState.carLastLocation) || - (carNetworkLocation && !prevState.carNetworkLocation) || - (geoLocateCoords && !prevState.geoLocateCoords) || - (searchSelect && prevState.searchSelect !== searchSelect) || - (search && prevState.search !== search) - ) { - this.flyToMarkers(); - } - - if (prevProps.dongleId !== dongleId) { - this.setState({ - ...initialState, - windowWidth: window.innerWidth, - }); - } - - if (prevProps.device !== device) { - this.updateDevice(); - } - } - - componentWillUnmount() { - this.mounted = false; - } - - checkWebGLSupport() { - const canvas = document.createElement('canvas'); - const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl'); - if (!gl || !(gl instanceof WebGLRenderingContext)) { - this.setState({ mapError: 'Failed to get WebGL context, your browser or device may not support WebGL.' }); - } - } - - updateDevice() { - this.getDeviceLastLocation(); - this.getDeviceNetworkLocation(); - } - - async getDeviceLastLocation() { - const { dongleId, device } = this.props; - if (device.shared) { - return; - } - try { - const resp = await Devices.fetchLocation(dongleId); - if (this.mounted && dongleId === this.props.dongleId) { - this.setState( - { - carLastLocation: [resp.lng, resp.lat], - carLastLocationTime: resp.time, - }, - this.flyToMarkers, - ); - } - } catch (err) { - if (!err.message || err.message.indexOf('no_segments_uploaded') === -1) { - console.error(err); - Sentry.captureException(err, { fingerprint: 'nav_fetch_location' }); - } - } - } - - async getDeviceNetworkLocation() { - const { dongleId } = this.props; - - const payload = { - method: 'getNetworks', - jsonrpc: '2.0', - id: 0, - }; - try { - let resp = await Athena.postJsonRpcPayload(dongleId, payload); - if (!resp.result || Object.keys(resp.result).length === 0 || !this.mounted || dongleId !== this.props.dongleId) { - return; - } - resp = await networkPositioning(resp.result); - if (resp && this.mounted && dongleId === this.props.dongleId) { - this.setState( - { - carNetworkLocation: [resp.lng, resp.lat], - carNetworkLocationAccuracy: resp.accuracy, - }, - this.flyToMarkers, - ); - } - } catch (err) { - if (this.mounted && dongleId === this.props.dongleId && (!err.message || err.message.indexOf('{"error": "Device not registered"}') === -1)) { - console.error(err); - Sentry.captureException(err, { fingerprint: 'nav_fetch_network_location' }); - } +const Navigation = ({ classes }) => { + // Redux state + const dongleId = useSelector((state) => state.dongleId); + const device = useSelector((state) => state.device); + + // State + const [hasFocus, setHasFocus] = useState(false); + const [carLastLocation, setCarLastLocation] = useState(null); + const [carLastLocationTime, setCarLastLocationTime] = useState(null); + const [carNetworkLocation, setCarNetworkLocation] = useState(null); + const [carNetworkLocationAccuracy, setCarNetworkLocationAccuracy] = useState(null); + const [geoLocateCoords, setGeoLocateCoords] = useState(null); + const [searchSelect, setSearchSelect] = useState(null); + const [searchLooking, setSearchLooking] = useState(false); + const [noFly, setNoFly] = useState(false); + const [windowWidth, setWindowWidth] = useState(window.innerWidth); + const [showPrimeAd, setShowPrimeAd] = useState(true); + const [viewport, setViewport] = useState({ + ...DEFAULT_LOCATION, + zoom: 5, + }); + const [mapError, setMapError] = useState(null); + + // Refs + const mounted = useRef(false); + const mapContainerRef = useRef(null); + const searchSelectBoxRef = useRef(null); + const primeAdBoxRef = useRef(null); + const carPinTooltipRef = useRef(null); + + // Helper functions + const itemLoc = useCallback((item) => { + if (item.access && item.access.length) { + return item.access[0]; } - } + return item.position; + }, []); - getCarLocation() { - const { carLastLocation, carLastLocationTime, carNetworkLocation, carNetworkLocationAccuracy } = this.state; + const itemLngLat = useCallback( + (item, bounds = false) => { + const pos = itemLoc(item); + const res = [pos.lng, pos.lat]; + return bounds ? [res, res] : res; + }, + [itemLoc], + ); + const getCarLocation = useCallback(() => { if (carNetworkLocation && carNetworkLocationAccuracy <= 10000 && (carNetworkLocationAccuracy <= 100 || !carLastLocation)) { return { location: carNetworkLocation, @@ -305,64 +192,44 @@ class Navigation extends Component { }; } return null; - } + }, [carLastLocation, carLastLocationTime, carNetworkLocation, carNetworkLocationAccuracy]); - onGeolocate(pos) { - if (pos && pos.coords) { - this.setState({ geoLocateCoords: [pos.coords.longitude, pos.coords.latitude] }); - } - } + const carLocationCircle = useCallback((carLocation) => { + const points = 128; + const km = carLocation.accuracy / 1000; - onCarSelect(carLocation) { - this.focus(); - - const [lng, lat] = carLocation.location; - const item = { - address: { - label: '', - }, - position: { - lng, - lat, - }, - resultType: 'car', - title: '', - }; + const distanceX = km / (111.32 * Math.cos(carLocation.location[1] * (Math.PI / 180))); + const distanceY = km / 110.574; - this.setState({ - noFly: false, - searchSelect: item, - searchLooking: false, - }); + const res = []; + let theta; + let x; + let y; + for (let i = 0; i < points; i++) { + theta = (i / points) * (2 * Math.PI); + x = distanceX * Math.cos(theta); + y = distanceY * Math.sin(theta); - reverseLookup(carLocation.location, true).then((location) => { - if (!location) { - return; - } + res.push([carLocation.location[0] + x, carLocation.location[1] + y]); + } + res.push(res[0]); - this.setState((prevState) => ({ - searchSelect: { - ...prevState.searchSelect, - address: { - label: location.details, + return { + type: 'FeatureCollection', + features: [ + { + type: 'Feature', + geometry: { + type: 'Polygon', + coordinates: [res], }, - title: location.place, }, - })); - }); - } - - clearSearchSelect() { - this.setState({ - noFly: false, - searchSelect: null, - searchLooking: false, - }); - } + ], + }; + }, []); - flyToMarkers() { - const { noFly, geoLocateCoords, search, searchSelect, windowWidth, viewport } = this.state; - const carLocation = this.getCarLocation(); + const flyToMarkers = useCallback(() => { + const carLocation = getCarLocation(); if (noFly) { return; @@ -376,10 +243,7 @@ class Navigation extends Component { bounds.push([carLocation.location, carLocation.location]); } if (searchSelect) { - bounds.push(this.itemLngLat(searchSelect, true)); - } else if (search) { - // biome-ignore lint/suspicious/useIterableCallbackReturn: push intentionally returns array length, forEach usage is correct for side effects - search.forEach((item) => bounds.push(this.itemLngLat(item, true))); + bounds.push(itemLngLat(searchSelect, true)); } if (bounds.length) { @@ -415,12 +279,12 @@ class Navigation extends Component { bbox[1][1] += 0.01; } - const bottomBoxHeight = this.searchSelectBoxRef.current && viewport.height > 200 ? this.searchSelectBoxRef.current.getBoundingClientRect().height + 10 : 0; + const bottomBoxHeight = searchSelectBoxRef.current && viewport.height > 200 ? searchSelectBoxRef.current.getBoundingClientRect().height + 10 : 0; let rightBoxWidth = 0; let topBoxHeight = 0; - const primeAdBox = this.primeAdBoxRef.current; + const primeAdBox = primeAdBoxRef.current; if (primeAdBox) { if (windowWidth < 600) { topBoxHeight = Math.max(topBoxHeight, primeAdBox.getBoundingClientRect().height + 10); @@ -430,7 +294,7 @@ class Navigation extends Component { } const padding = { - left: windowWidth < 600 || !search ? 20 : 390, + left: 20, right: rightBoxWidth + 20, top: topBoxHeight + 20, bottom: bottomBoxHeight + 20, @@ -438,209 +302,165 @@ class Navigation extends Component { if (viewport.width) { try { const newVp = new WebMercatorViewport(viewport).fitBounds(bbox, { padding, maxZoom: 10 }); - this.setState({ viewport: newVp }); + setViewport(newVp); } catch (err) { console.error(err); Sentry.captureException(err, { fingerprint: 'nav_flymarkers_viewport' }); } } } - } + }, [noFly, geoLocateCoords, searchSelect, windowWidth, viewport, itemLngLat, getCarLocation]); - focus(ev) { - if (!this.state.hasFocus && (!ev || !ev.srcEvent || !ev.srcEvent.path || !this.mapContainerRef.current || ev.srcEvent.path.includes(this.mapContainerRef.current))) { - this.setState({ hasFocus: true }); + const checkWebGLSupport = useCallback(() => { + const canvas = document.createElement('canvas'); + const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl'); + if (!gl || !(gl instanceof WebGLRenderingContext)) { + setMapError('Failed to get WebGL context, your browser or device may not support WebGL.'); } - } + }, []); - itemLoc(item) { - if (item.access && item.access.length) { - return item.access[0]; + const getDeviceLastLocation = useCallback(async () => { + if (device.shared) { + return; } - return item.position; - } - - itemLngLat(item, bounds = false) { - const pos = this.itemLoc(item); - const res = [pos.lng, pos.lat]; - return bounds ? [res, res] : res; - } - - onResize(windowWidth) { - this.setState({ windowWidth }); - } + try { + const resp = await Devices.fetchLocation(dongleId); + if (mounted.current) { + setCarLastLocation([resp.lng, resp.lat]); + setCarLastLocationTime(resp.time); + } + } catch (err) { + if (!err.message || err.message.indexOf('no_segments_uploaded') === -1) { + console.error(err); + Sentry.captureException(err, { fingerprint: 'nav_fetch_location' }); + } + } + }, [dongleId, device.shared]); - toggleCarPinTooltip(visible) { - const tooltip = this.carPinTooltipRef.current; - if (tooltip) { - tooltip.style.display = visible ? 'block' : 'none'; + const getDeviceNetworkLocation = useCallback(async () => { + const payload = { + method: 'getNetworks', + jsonrpc: '2.0', + id: 0, + }; + try { + let resp = await Athena.postJsonRpcPayload(dongleId, payload); + if (!resp.result || Object.keys(resp.result).length === 0 || !mounted.current) { + return; + } + resp = await networkPositioning(resp.result); + if (resp && mounted.current) { + setCarNetworkLocation([resp.lng, resp.lat]); + setCarNetworkLocationAccuracy(resp.accuracy); + } + } catch (err) { + if (mounted.current && (!err.message || err.message.indexOf('{"error": "Device not registered"}') === -1)) { + console.error(err); + Sentry.captureException(err, { fingerprint: 'nav_fetch_network_location' }); + } } - } + }, [dongleId]); - viewportChange(viewport, interactionState) { - const { search, searchSelect, searchLooking } = this.state; - this.setState({ viewport }); + const updateDevice = useCallback(() => { + getDeviceLastLocation(); + getDeviceNetworkLocation(); + }, [getDeviceLastLocation, getDeviceNetworkLocation]); - if (interactionState.isPanning || interactionState.isZooming || interactionState.isRotating) { - this.focus(); + const onGeolocate = (pos) => { + if (pos && pos.coords) { + setGeoLocateCoords([pos.coords.longitude, pos.coords.latitude]); + } + }; - if (search && !searchSelect && !searchLooking) { - this.setState({ searchLooking: true, noFly: true }); + const focus = useCallback( + (ev) => { + if (!hasFocus && (!ev || !ev.srcEvent || !ev.srcEvent.path || !mapContainerRef.current || ev.srcEvent.path.includes(mapContainerRef.current))) { + setHasFocus(true); } - } - } + }, + [hasFocus], + ); - carLocationCircle(carLocation) { - const points = 128; - const km = carLocation.accuracy / 1000; + const onCarSelect = useCallback( + (carLocation) => { + focus(); - const distanceX = km / (111.32 * Math.cos(carLocation.location[1] * (Math.PI / 180))); - const distanceY = km / 110.574; + const [lng, lat] = carLocation.location; + const item = { + address: { + label: '', + }, + position: { + lng, + lat, + }, + resultType: 'car', + title: '', + }; - const res = []; - let theta; - let x; - let y; - for (let i = 0; i < points; i++) { - theta = (i / points) * (2 * Math.PI); - x = distanceX * Math.cos(theta); - y = distanceY * Math.sin(theta); + setNoFly(false); + setSearchSelect(item); + setSearchLooking(false); - res.push([carLocation.location[0] + x, carLocation.location[1] + y]); - } - res.push(res[0]); + reverseLookup(carLocation.location, true).then((location) => { + if (!location) { + return; + } - return { - type: 'FeatureCollection', - features: [ - { - type: 'Feature', - geometry: { - type: 'Polygon', - coordinates: [res], + setSearchSelect((prevSearchSelect) => ({ + ...prevSearchSelect, + address: { + label: location.details, }, - }, - ], - }; - } + title: location.place, + })); + }); + }, + [focus], + ); - onContainerRef(el) { - this.mapContainerRef.current = el; - if (el) { - el.addEventListener('touchstart', (ev) => ev.stopPropagation()); + const clearSearchSelect = () => { + setNoFly(false); + setSearchSelect(null); + setSearchLooking(false); + }; + + const onResize = (newWindowWidth) => { + setWindowWidth(newWindowWidth); + }; + + const toggleCarPinTooltip = (visible) => { + const tooltip = carPinTooltipRef.current; + if (tooltip) { + tooltip.style.display = visible ? 'block' : 'none'; } - } + }; - render() { - const { classes, device } = this.props; - const { mapError, hasFocus, searchSelect, viewport, windowWidth, showPrimeAd } = this.state; - const carLocation = this.getCarLocation(); + const viewportChange = useCallback( + (newViewport, interactionState) => { + setViewport(newViewport); - const cardStyle = - windowWidth < 600 - ? { zIndex: 4, width: 'auto', height: 'auto', top: 'auto', bottom: 'auto', left: 10, right: 10 } - : { zIndex: 4, width: 360, height: 'auto', top: 'auto', bottom: 'auto', left: 10 }; + if (interactionState.isPanning || interactionState.isZooming || interactionState.isRotating) { + focus(); - let carPinTooltipStyle = { transform: 'translate(calc(-50% + 10px), -4px)' }; - if (carLocation) { - const pixelsAvailable = viewport.height - new WebMercatorViewport(viewport).project(carLocation.location)[1]; - if (pixelsAvailable < 50) { - carPinTooltipStyle = { transform: 'translate(calc(-50% + 10px), -81px)' }; + if (!searchSelect && !searchLooking) { + setSearchLooking(true); + setNoFly(true); + } } - } - - return ( -
- - - {mapError && ( -
- Could not initialize map. - {mapError} -
- )} - this.setState({ mapError: err.error.message })} - > - {}} - /> - {carLocation && ( - - this.toggleCarPinTooltip(true)} - onMouseLeave={() => this.toggleCarPinTooltip(false)} - alt="car-location" - onClick={() => this.onCarSelect(carLocation)} - /> -
- {dayjs(carLocation.time).format('h:mm A')} - , -
- {timeFromNow(carLocation.time)} -
-
- )} - {carLocation && Boolean(carLocation.accuracy) && ( - - - - )} - {searchSelect && ( - - )} - {showPrimeAd && !device.prime && device.is_owner && ( - - )} -
-
- ); - } + }, + [focus, searchSelect, searchLooking], + ); - renderSearchOverlay() { - const { classes, device } = this.props; - const { searchSelect } = this.state; + const onContainerRef = (el) => { + mapContainerRef.current = el; + if (el) { + el.addEventListener('touchstart', (ev) => ev.stopPropagation()); + } + }; - const carLocation = this.getCarLocation(); + const renderSearchOverlay = () => { + const carLocation = getCarLocation(); const title = device.alias; const { lat, lng } = searchSelect.position; @@ -653,8 +473,8 @@ class Navigation extends Component { } return ( -
- +
+
{title} @@ -672,20 +492,24 @@ class Navigation extends Component {
); - } - - renderPrimeAd() { - const { classes } = this.props; + }; + const renderPrimeAd = () => { return ( -
- this.setState({ showPrimeAd: false }, this.flyToMarkers)} /> +
+ { + setShowPrimeAd(false); + flyToMarkers(); + }} + />
comma prime
-
@@ -693,12 +517,148 @@ class Navigation extends Component { Put your car on the internet with comma prime
); + }; + + // Set mounted on initial mount + useEffect(() => { + mounted.current = true; + return () => { + mounted.current = false; + }; + }, []); + + // Check WebGL support on mount + useEffect(() => { + checkWebGLSupport(); + }, [checkWebGLSupport]); + + // Update device on mount and when device changes + useEffect(() => { + updateDevice(); + }, [updateDevice]); + + // Fly to markers when location states change + useEffect(() => { + flyToMarkers(); + }, [flyToMarkers]); + + // Reset state when dongleId changes + useEffect(() => { + if (dongleId) { + setHasFocus(false); + setCarLastLocation(null); + setCarLastLocationTime(null); + setCarNetworkLocation(null); + setCarNetworkLocationAccuracy(null); + setGeoLocateCoords(null); + setSearchSelect(null); + setSearchLooking(false); + setNoFly(false); + setWindowWidth(window.innerWidth); + setShowPrimeAd(true); + } + }, [dongleId]); + + const carLocation = getCarLocation(); + + const cardStyle = + windowWidth < 600 + ? { zIndex: 4, width: 'auto', height: 'auto', top: 'auto', bottom: 'auto', left: 10, right: 10 } + : { zIndex: 4, width: 360, height: 'auto', top: 'auto', bottom: 'auto', left: 10 }; + + let carPinTooltipStyle = { transform: 'translate(calc(-50% + 10px), -4px)' }; + if (carLocation) { + const pixelsAvailable = viewport.height - new WebMercatorViewport(viewport).project(carLocation.location)[1]; + if (pixelsAvailable < 50) { + carPinTooltipStyle = { transform: 'translate(calc(-50% + 10px), -81px)' }; + } } -} -const stateToProps = (state) => ({ - device: state.device, - dongleId: state.dongleId, -}); + return ( +
+ + + {mapError && ( +
+ Could not initialize map. + {mapError} +
+ )} + setMapError(err.error.message)} + > + {}} + /> + {carLocation && ( + + toggleCarPinTooltip(true)} + onMouseLeave={() => toggleCarPinTooltip(false)} + alt="car-location" + onClick={() => onCarSelect(carLocation)} + /> +
+ {dayjs(carLocation.time).format('h:mm A')} + , +
+ {timeFromNow(carLocation.time)} +
+
+ )} + {carLocation && Boolean(carLocation.accuracy) && ( + + + + )} + {searchSelect && ( + + )} + {showPrimeAd && !device.prime && device.is_owner && ( + + )} +
+
+ ); +}; -export default connect(stateToProps)(withStyles(styles)(Navigation)); +export default withStyles(styles)(Navigation); diff --git a/src/components/Prime/PrimeCheckout.jsx b/src/components/Prime/PrimeCheckout.jsx index 5b7ae61a..707bedd1 100644 --- a/src/components/Prime/PrimeCheckout.jsx +++ b/src/components/Prime/PrimeCheckout.jsx @@ -331,104 +331,104 @@ const PrimeCheckout = ({ classes }) => { return (
-
- navigate(`/${dongleId}`)}> - - -
- {deviceNamePretty(device)} - {`(${device.dongle_id})`} -
+
+ navigate(`/${dongleId}`)}> + + +
+ {deviceNamePretty(device)} + {`(${device.dongle_id})`}
-

comma prime

-
-
-
- -

24/7 connectivity

-
-
- -

Take pictures remotely

-
-
- -

1 year storage of drive videos

-
-
- -

Simple SSH for developers

-
+
+

comma prime

+
+
+
+ +

24/7 connectivity

-
-
-
-
setSelectedPlan('nodata') : null} - > -

lite

-

$10/month

-

- bring your own -
- sim card -

-
-
setSelectedPlan('data') : null} - > -

standard

-

$24/month

-

- including data plan -
- only offered in the U.S. -

-
+
+ +

Take pictures remotely

- {!subscribeInfo && ( -
- - Fetching SIM data -
- )} -
- {disabledDataPlanText && ( -
- - {disabledDataPlanText} +
+ +

1 year storage of drive videos

+
+
+ +

Simple SSH for developers

- )} -
- - {'Learn more about comma prime from our '} - - FAQ - -
- {error && ( -
- - {error} +
+
+
+
setSelectedPlan('nodata') : null} + > +

lite

+

$10/month

+

+ bring your own +
+ sim card +

+
+
setSelectedPlan('data') : null} + > +

standard

+

$24/month

+

+ including data plan +
+ only offered in the U.S. +

- )} -
-
- {chargeText && ( -
- {chargeText} + {!subscribeInfo && ( +
+ + Fetching SIM data
)}
- ); + {disabledDataPlanText && ( +
+ + {disabledDataPlanText} +
+ )} +
+ + {'Learn more about comma prime from our '} + + FAQ + + +
+ {error && ( +
+ + {error} +
+ )} +
+ +
+ {chargeText && ( +
+ {chargeText} +
+ )} +
+ ); }; export default withStyles(styles)(PrimeCheckout); diff --git a/src/components/Prime/PrimeManage.jsx b/src/components/Prime/PrimeManage.jsx index 199ed254..f5a2a962 100644 --- a/src/components/Prime/PrimeManage.jsx +++ b/src/components/Prime/PrimeManage.jsx @@ -333,158 +333,153 @@ const PrimeManage = ({ classes }) => { return ( <> -
-
- navigate(`/${dongleId}`)}> - - +
+
+ navigate(`/${dongleId}`)}> + + +
+
+ comma prime + {stripeStatus && ( + <> + {stripeStatus.paid !== 'paid' && ( +
+ + Waiting for confirmed payment +
+ )} + {Boolean(stripeStatus.paid === 'paid' && !hasPrimeSub) && ( +
+ + Processing subscription +
+ )} + {Boolean(stripeStatus.paid === 'paid' && hasPrimeSub) && ( +
+ comma prime activated + {subscription.is_prime_sim && ( + Connectivity will be enabled as soon as activation propagates to your local cell tower. Rebooting your device may help. + )} +
+ )} + + )} +
+ Device +
+ {alias} + + {`(${device.dongle_id})`} + +
-
- comma prime - {stripeStatus && ( - <> - {stripeStatus.paid !== 'paid' && ( -
- - Waiting for confirmed payment -
- )} - {Boolean(stripeStatus.paid === 'paid' && !hasPrimeSub) && ( -
- - Processing subscription -
- )} - {Boolean(stripeStatus.paid === 'paid' && hasPrimeSub) && ( -
- comma prime activated - {subscription.is_prime_sim && ( - Connectivity will be enabled as soon as activation propagates to your local cell tower. Rebooting your device may help. - )} -
- )} - - )} -
- Device -
- {alias} - - {`(${device.dongle_id})`} + {hasPrimeSub && ( + <> +
+ Plan + + {planName} + {` ${planSubtext}`}
-
- {hasPrimeSub && ( - <> +
+ Joined + {joinDate} +
+ {!hasCancelAt && (
- Plan - - {planName} - {` ${planSubtext}`} - + Next payment + {nextPaymentDate}
+ )} + {hasCancelAt && (
- Joined - {joinDate} + Subscription end + {cancelAtDate}
- {!hasCancelAt && ( -
- Next payment - {nextPaymentDate} -
- )} - {hasCancelAt && ( -
- Subscription end - {cancelAtDate} -
- )} -
- Amount - {`$${(subscription.amount / 100).toFixed(2)}`} + )} +
+ Amount + {`$${(subscription.amount / 100).toFixed(2)}`} +
+ {error && ( +
+ + {error}
- {error && ( -
- - {error} -
- )} -
+ )} +
+ + {!hasCancelAt && ( - {!hasCancelAt && ( - - )} -
- {hasPrimeSub && subscription.requires_migration && ( -
- - - Your prime subscription will be canceled on May 15th unless you replace the SIM card in your device. A new SIM card can be ordered from the - - shop - - . Use discount code SIMSWAP at checkout to receive a free SIM card. - -
)} - {hasCancelAt && !device.eligible_features?.prime_data && subscription.plan === 'data' && ( -
- - - Standard comma prime discontinued for - {deviceTypePretty(device.device_type)} - -
- )} - - )} -
-
- setCancelModal(false)}> - - Cancel prime subscription - {cancelError && ( -
- {cancelError} -
- )} - {cancelSuccess && ( -
- {cancelSuccess}
- )} - {`Device: ${alias} (${dongleId})`} - We're sorry to see you go. - Your subscription will be cancelled immediately and can be resumed at any time. - - -
-
- - ); + {hasPrimeSub && subscription.requires_migration && ( +
+ + + Your prime subscription will be canceled on May 15th unless you replace the SIM card in your device. A new SIM card can be ordered from the + + shop + + . Use discount code SIMSWAP at checkout to receive a free SIM card. + +
+ )} + {hasCancelAt && !device.eligible_features?.prime_data && subscription.plan === 'data' && ( +
+ + + Standard comma prime discontinued for + {deviceTypePretty(device.device_type)} + +
+ )} + + )} +
+
+ setCancelModal(false)}> + + Cancel prime subscription + {cancelError && ( +
+ {cancelError} +
+ )} + {cancelSuccess && ( +
+ {cancelSuccess} +
+ )} + {`Device: ${alias} (${dongleId})`} + We're sorry to see you go. + Your subscription will be cancelled immediately and can be resumed at any time. + + +
+
+ + ); }; export default withStyles(styles)(PrimeManage); diff --git a/src/components/anonymous.jsx b/src/components/anonymous.jsx index 19199059..d7fe4459 100644 --- a/src/components/anonymous.jsx +++ b/src/components/anonymous.jsx @@ -3,8 +3,8 @@ import { config as AuthConfig, storage as AuthStorage } from '@commaai/my-comma-auth'; import { withStyles } from '@material-ui/core/styles'; import Typography from '@material-ui/core/Typography'; -import { Component } from 'react'; -import { withRouter } from 'react-router'; +import { useEffect } from 'react'; +import { useLocation } from 'react-router'; import Colors from '../colors'; import { AuthAppleIcon, AuthGithubIcon, AuthGoogleIcon, RightArrow } from '../icons'; @@ -87,12 +87,13 @@ const styles = () => ({ }, }); -class AnonymousLanding extends Component { - componentDidMount() { +const AnonymousLanding = ({ classes }) => { + const location = useLocation(); + + useEffect(() => { // Set default redirectURL from pathname if not already set if (typeof window !== 'undefined' && typeof window.sessionStorage !== 'undefined' && sessionStorage.getItem('redirectURL') === null) { - const { pathname } = this.props; - sessionStorage.setItem('redirectURL', pathname); + sessionStorage.setItem('redirectURL', location.pathname); } // Override with query param 'r' if present @@ -118,54 +119,50 @@ class AnonymousLanding extends Component { window.location = [AuthConfig.APPLE_REDIRECT_PATH, new URLSearchParams({ code, state }).toString()].join('?'); }); document.addEventListener('AppleIDSignInOnFailure', console.warn); - } - - render() { - const { classes } = this.props; + }, [location.pathname]); - const loginAsDemoUser = () => { - AuthStorage.setCommaAccessToken( - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEwMzg5NTgwNzM1LCJuYmYiOjE3NDk1ODA3MzUsImlhdCI6MTc0OTU4MDczNSwiaWRlbnRpdHkiOiIwZGVjZGRjZmRmMjQxYTYwIn0.KsDzqJxgkYhAs4tCgrMJIdORyxO0CQNb0gHXIf8aUT0', - ); - window.location = window.location.origin; - }; + const loginAsDemoUser = () => { + AuthStorage.setCommaAccessToken( + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEwMzg5NTgwNzM1LCJuYmYiOjE3NDk1ODA3MzUsImlhdCI6MTc0OTU4MDczNSwiaWRlbnRpdHkiOiIwZGVjZGRjZmRmMjQxYTYwIn0.KsDzqJxgkYhAs4tCgrMJIdORyxO0CQNb0gHXIf8aUT0', + ); + window.location = window.location.origin; + }; - return ( -
-
-
- comma -
-
 
- comma connect - Manage your comma device, view your drives, and use comma prime features - - - Sign in with Google - - AppleID.auth.signIn()} className={classes.logInButton}> - - Sign in with Apple - - - - Sign in with GitHub - + return ( +
+
+
+ comma +
+
 
+ comma connect + Manage your comma device, view your drives, and use comma prime features + + + Sign in with Google + + AppleID.auth.signIn()} className={classes.logInButton}> + + Sign in with Apple + + + + Sign in with GitHub + - Make sure to sign in with the same account if you have previously paired your comma device. + Make sure to sign in with the same account if you have previously paired your comma device. - - Try the demo - - -
- + + Try the demo + +
- ); - } -} + +
+ ); +}; -export default withRouter(withStyles(styles)(AnonymousLanding)); +export default withStyles(styles)(AnonymousLanding); diff --git a/src/components/explorer.jsx b/src/components/explorer.jsx index 279b5390..23bae5f6 100644 --- a/src/components/explorer.jsx +++ b/src/components/explorer.jsx @@ -1,8 +1,8 @@ import { Button, CircularProgress, Divider, Modal, Paper, Typography, withStyles } from '@material-ui/core'; import localforage from 'localforage'; -import { Component } from 'react'; -import { connect } from 'react-redux'; -import { withRouter } from 'react-router'; +import { useEffect, useRef, useState } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { useLocation } from 'react-router'; import { replace } from '../navigation'; import 'mapbox-gl/dist/mapbox-gl.css'; @@ -12,6 +12,7 @@ import init from '../actions/startup'; import Colors from '../colors'; import { pause, play } from '../timeline/playback'; import { pairErrorToMessage, verifyPairToken } from '../utils'; +import { getSegmentRange } from '../url'; import AppDrawer from './AppDrawer'; import AppHeader from './AppHeader'; import Dashboard from './Dashboard'; @@ -55,27 +56,35 @@ const styles = (theme) => ({ }, }); -class ExplorerApp extends Component { - constructor(props) { - super(props); +const ExplorerApp = ({ classes }) => { + const dispatch = useDispatch(); + const location = useLocation(); - this.state = { - drawerIsOpen: false, - headerRef: null, - pairLoading: false, - pairError: null, - pairDongleId: null, - windowWidth: window.innerWidth, - }; + const [drawerIsOpen, setDrawerIsOpen] = useState(false); + const [pairLoading, setPairLoading] = useState(false); + const [pairError, setPairError] = useState(null); + const [pairDongleId, setPairDongleId] = useState(null); + const [windowWidth, setWindowWidth] = useState(window.innerWidth); - this.handleDrawerStateChanged = this.handleDrawerStateChanged.bind(this); - this.updateHeaderRef = this.updateHeaderRef.bind(this); - this.closePair = this.closePair.bind(this); - } + const headerRef = useRef(null); - async componentDidMount() { - const { pairLoading, pairError, pairDongleId } = this.state; + // Get Redux state + const dongleId = useSelector((state) => state.dongleId); + const devices = useSelector((state) => state.devices); + const limit = useSelector((state) => state.limit); + const routes = useSelector((state) => state.routes); + // Calculate current route and zoom from location + const seg = getSegmentRange(location?.pathname || '/'); + const currentRoute = (seg && routes && routes.find((r) => r.log_id === seg.log_id)) || null; + let zoom = null; + if (currentRoute) { + const hasTimes = typeof seg.start === 'number' && typeof seg.end === 'number' && !Number.isNaN(seg.start) && !Number.isNaN(seg.end); + zoom = hasTimes ? { start: seg.start - currentRoute.start_time_utc_millis, end: seg.end - currentRoute.start_time_utc_millis } : { start: 0, end: currentRoute.duration }; + } + + // Initial mount effect + useEffect(() => { window.scrollTo({ top: 0 }); // for ios header const q = new URLSearchParams(window.location.search); @@ -83,175 +92,159 @@ class ExplorerApp extends Component { replace(q.get('r')); } - this.props.dispatch(init()); - - let pairToken; - try { - pairToken = await localforage.getItem('pairToken'); - } catch (err) { - console.error(err); - } - if (pairToken && !pairLoading && !pairError && !pairDongleId) { - this.setState({ pairLoading: true }); + dispatch(init()); + }, [dispatch]); + // Handle pairing on mount + useEffect(() => { + const handlePairing = async () => { + let pairToken; try { - verifyPairToken(pairToken, true, 'explorer_pair_verify_pairtoken'); + pairToken = await localforage.getItem('pairToken'); } catch (err) { - this.setState({ pairLoading: false, pairDongleId: null, pairError: `Error: ${err.message}` }); - await localforage.removeItem('pairToken'); - return; + console.error(err); } - - try { - const resp = await Devices.pilotPair(pairToken); - if (resp.dongle_id) { + if (pairToken && !pairLoading && !pairError && !pairDongleId) { + setPairLoading(true); + + try { + verifyPairToken(pairToken, true, 'explorer_pair_verify_pairtoken'); + } catch (err) { + setPairLoading(false); + setPairDongleId(null); + setPairError(`Error: ${err.message}`); await localforage.removeItem('pairToken'); - this.setState({ - pairLoading: false, - pairError: null, - pairDongleId: resp.dongle_id, - }); + return; + } - const device = await Devices.fetchDevice(resp.dongle_id); - this.props.dispatch(updateDevice(device)); - } else { + try { + const resp = await Devices.pilotPair(pairToken); + if (resp.dongle_id) { + await localforage.removeItem('pairToken'); + setPairLoading(false); + setPairError(null); + setPairDongleId(resp.dongle_id); + + const device = await Devices.fetchDevice(resp.dongle_id); + dispatch(updateDevice(device)); + } else { + await localforage.removeItem('pairToken'); + console.log(resp); + setPairDongleId(null); + setPairLoading(false); + setPairError('Error: could not pair, please try again'); + } + } catch (err) { await localforage.removeItem('pairToken'); - console.log(resp); - this.setState({ pairDongleId: null, pairLoading: false, pairError: 'Error: could not pair, please try again' }); + const msg = pairErrorToMessage(err, 'explorer_pair_pairtoken'); + setPairDongleId(null); + setPairLoading(false); + setPairError(`Error: ${msg}, please try again`); } - } catch (err) { - await localforage.removeItem('pairToken'); - const msg = pairErrorToMessage(err, 'explorer_pair_pairtoken'); - this.setState({ pairDongleId: null, pairLoading: false, pairError: `Error: ${msg}, please try again` }); } - } - - this.componentDidUpdate({}); - } + }; - componentDidUpdate(prevProps, prevState) { - const { location, zoom, dongleId, limit } = this.props; - const pathname = location?.pathname; + handlePairing(); + }, [dispatch, pairLoading, pairError, pairDongleId]); - if (prevProps.location?.pathname !== pathname) { - this.setState({ drawerIsOpen: false }); + // Close drawer on pathname change + useEffect(() => { + if (location.pathname) { + setDrawerIsOpen(false); } - - if (!prevProps.zoom && zoom) { - this.props.dispatch(play()); - } - if (prevProps.zoom && !zoom) { - this.props.dispatch(pause()); + }, [location.pathname]); + + // Handle zoom changes for playback + useEffect(() => { + if (zoom) { + dispatch(play()); + } else { + dispatch(pause()); } + }, [zoom, dispatch]); - // this is necessary when user goes to explorer for the first time, dongleId is not populated in state yet - // so init() will not successfully fetch routes data - // when checkLastRoutesData is called within init(), it would set limit so we don't need to check again - if (prevProps.dongleId !== dongleId && limit === 0) { - this.props.dispatch(checkLastRoutesData()); + // Check routes data when dongleId changes + useEffect(() => { + if (dongleId && limit === 0) { + dispatch(checkLastRoutesData()); } - } + }, [dongleId, limit, dispatch]); - async closePair() { - const { pairDongleId } = this.state; + const closePair = async () => { await localforage.removeItem('pairToken'); if (pairDongleId) { - this.props.dispatch(selectDevice(pairDongleId)); + dispatch(selectDevice(pairDongleId)); } - this.setState({ pairLoading: false, pairError: null, pairDongleId: null }); - } + setPairLoading(false); + setPairError(null); + setPairDongleId(null); + }; - handleDrawerStateChanged(drawerOpen) { - this.setState({ - drawerIsOpen: drawerOpen, - }); - } + const handleDrawerStateChanged = (drawerOpen) => { + setDrawerIsOpen(drawerOpen); + }; - updateHeaderRef(ref) { - if (!this.state.headerRef) { - this.setState({ headerRef: ref }); + const updateHeaderRef = (ref) => { + if (!headerRef.current) { + headerRef.current = ref; } - } - - render() { - const { classes, currentRoute, devices, dongleId } = this.props; - const { drawerIsOpen, pairLoading, pairError, pairDongleId, windowWidth } = this.state; + }; - const noDevicesUpsell = devices?.length === 0 && !dongleId; - const isLarge = noDevicesUpsell || windowWidth > 1080; + const noDevicesUpsell = devices?.length === 0 && !dongleId; + const isLarge = noDevicesUpsell || windowWidth > 1080; - const sidebarWidth = noDevicesUpsell ? 0 : Math.max(280, windowWidth * 0.2); - const headerHeight = this.state.headerRef ? this.state.headerRef.getBoundingClientRect().height : windowWidth < 640 ? 111 : 66; - let containerStyles = { - minHeight: `calc(100vh - ${headerHeight}px)`, - }; - if (isLarge) { - containerStyles = { - ...containerStyles, - width: `calc(100% - ${sidebarWidth}px)`, - marginLeft: sidebarWidth, - }; - } - - const drawerStyles = { - minHeight: `calc(100vh - ${headerHeight}px)`, + const sidebarWidth = noDevicesUpsell ? 0 : Math.max(280, windowWidth * 0.2); + const headerHeight = headerRef.current ? headerRef.current.getBoundingClientRect().height : windowWidth < 640 ? 111 : 66; + let containerStyles = { + minHeight: `calc(100vh - ${headerHeight}px)`, + }; + if (isLarge) { + containerStyles = { + ...containerStyles, + width: `calc(100% - ${sidebarWidth}px)`, + marginLeft: sidebarWidth, }; - - return ( -
- this.setState({ windowWidth: ww })} /> - - - -
- {noDevicesUpsell ? : currentRoute ? : } -
- - - - Pairing device - - {pairLoading && } - {pairDongleId && ( - - {'Successfully paired device '} - {pairDongleId} - - )} - {pairError && {pairError}} - - - -
- ); } -} - -import { getSegmentRange } from '../url'; -const stateToProps = (state, ownProps) => { - const seg = getSegmentRange(ownProps.location?.pathname || '/'); - const currentRoute = (seg && state.routes && state.routes.find((r) => r.log_id === seg.log_id)) || null; - let zoom = null; - if (currentRoute) { - const hasTimes = typeof seg.start === 'number' && typeof seg.end === 'number' && !Number.isNaN(seg.start) && !Number.isNaN(seg.end); - zoom = hasTimes ? { start: seg.start - currentRoute.start_time_utc_millis, end: seg.end - currentRoute.start_time_utc_millis } : { start: 0, end: currentRoute.duration }; - } - return { - zoom, - dongleId: state.dongleId, - devices: state.devices, - currentRoute, - limit: state.limit, + const drawerStyles = { + minHeight: `calc(100vh - ${headerHeight}px)`, }; + + return ( +
+ setWindowWidth(ww)} /> + + + +
+ {noDevicesUpsell ? : currentRoute ? : } +
+ + + + Pairing device + + {pairLoading && } + {pairDongleId && ( + + {'Successfully paired device '} + {pairDongleId} + + )} + {pairError && {pairError}} + + + +
+ ); }; -export default withRouter(connect(stateToProps)(withStyles(styles)(ExplorerApp))); +export default withStyles(styles)(ExplorerApp); From 0045487352171b4c11d8b827c61bc3380f399fdc Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 2 Nov 2025 20:03:59 -0800 Subject: [PATCH 19/26] mui 5 --- bun.lockb | Bin 460988 -> 458988 bytes package.json | 7 +- src/App.jsx | 2 +- src/components/AppDrawer/index.jsx | 2 +- src/components/AppHeader/AccountMenu.jsx | 2 +- src/components/AppHeader/index.jsx | 4 +- src/components/Dashboard/AddDevice.jsx | 5 +- src/components/Dashboard/DeviceList.jsx | 5 +- .../Dashboard/DeviceSettingsModal.jsx | 11 +- src/components/Dashboard/DriveList.jsx | 3 +- src/components/Dashboard/DriveListEmpty.jsx | 3 +- src/components/Dashboard/DriveListItem.jsx | 3 +- src/components/Dashboard/index.jsx | 2 +- src/components/DeviceInfo/index.jsx | 5 +- src/components/DriveVideo/index.jsx | 2 +- src/components/DriveView/Media.jsx | 9 +- src/components/DriveView/index.jsx | 2 +- src/components/Files/UploadQueue.jsx | 7 +- src/components/IosPwaPopup/index.jsx | 5 +- src/components/Navigation/index.jsx | 5 +- src/components/PWAIcon.jsx | 2 +- src/components/Prime/PrimeCheckout.jsx | 7 +- src/components/Prime/PrimeManage.jsx | 7 +- src/components/Prime/index.jsx | 2 +- src/components/TimeDisplay/index.jsx | 12 +- src/components/TimeSelect/index.jsx | 3 +- src/components/Timeline/index.jsx | 2 +- src/components/anonymous.jsx | 4 +- src/components/explorer.jsx | 3 +- src/components/utils/InfoTooltip.jsx | 3 +- src/components/utils/PullDownReload.jsx | 4 +- src/components/utils/SwitchLoading.jsx | 3 +- src/icons/index.jsx | 2 +- src/index.jsx | 6 +- src/theme.js | 154 ++++++++++-------- 35 files changed, 169 insertions(+), 129 deletions(-) diff --git a/bun.lockb b/bun.lockb index 1605bd836dffd3b8f440a1738d385a28e0d1665d..59a40711998e01e47fdea0cb455d4f8a58606225 100755 GIT binary patch delta 96036 zcmeFad3a6N-!{JYNeqzSn)P>9am--1{8Kj_GCYX;^hPMJWrOUt%hd6-|W|9>AFN^o*>OSmhD&IagfOVGs%}f^=1Y*{q;6Zp0$E zu_dKt!V@Uf3%n()Dh^x(Wc=6AJ%L{VY1kYfTQnZXhCBx;1dNMLN{UTONdHF_`Bo#b z5A+$p(!i00m29O10s|oslj4)(lhFERFpmXAKxf4*fJK3|fV8|ckS)y*#J`+ZsEr2P z2hxMrfv_cK@PPiA>2Zqk6F3`q0?2X?NZe6KPqUQOrlW2;>a{+{Qm#o6w4SYOjwTY_ zz|BnHH1ZKz!@?5dW6hB>8!lqHTlxb_$?S88rKv|si8l5{L#u*!0@9?0WrS`AXDNoa zs5=+P(g#cI24vHNCDxKy3P=}dK)N7rd12jv*#4P=6s3Zalx|w3yg)_t$pawGuL;i+ zQ}yL8Rn_MDNtbfj%PNY(bRa9MQCW2O3?Lm+RN_a7r}26f)}Z7J2eJc)Lx(GK;w9ci zB#mlUP1MyJI{RZIJizi_BcA=0kRF>JgTbe?M*F z$X5FTX~?2l!doaNIx%`ctPakKvVp~b>A(WO_CSu*O324P%8E`*#Q0J&lT#8i2W7`6 zx2z*tS|7-k#Ka9596umBZD4xr(AeaRbeo?r&|hM)x}t@?;Q5h0KHYav;*kEzHR$v% zCi#E?@o6d1^+biy$yrI!88LDF)1qTy(KChXi*((91+j4CEYnl1CAGK)qPRZ#bZg1% zJ`DvMFeD>3d8ne8HK13^H4?g`HJmOf(dp^Mq@EwhRwg$VjoAmJcOB`DU~JM$YyCxh zQWN3bQb4Br96I8&b7qP_&O{*H*c=Hwfn9)Jz-mCc`CAl7FU)N&3Q9;9gKuzvs3-?I z=0T2U3(@L$aE_}kK#qq%iG2e_c{Ra{VOZomY$h_?l;~JHV-nMcb9k3RLJl-d;!C7s z%Qnas2DMZaOpu()Kn~PGz!JbgA;Mr4oGpGFEO_NmF}|h{vk~FaN+fs)ffZc^a^z+M znGq{21`@nt6D`RHr2ZKUC<>ec@6K26j^!0E|!vSdKL~!aEKsIG$PtnQuflSvbQdoKooawY)Vz~bd z&h$?Zk3o^0a}xn(_(|dqKqlDRTNpBENDAvyl4QYS`-sks0jGgU@kz111Ntk`=~>A! zgX1#>4M8h#_3J0*=_MeCeI+1A<0&Bf;6xP5k5O_CNudppqit@q7#)pehM@kU!lK|D z{!hS*0dMpb`X4ghk?sOGTf7tT^kg%=XZ~{8#bbp!I5ul2&3g(?Gh9$A$Kqc|O*{`| zZtEbC+cC7(%hE<;GSOWrK#uW-af(t4m=8$n=f?}T=s>zL8whK&a~%6yA_V#&&tPFd zR&-J#4N3%OhA1G-_Jv9;52Qig02$u_@pMBuRLEr{5{3}3Ckcbj0hvAv6OZ-83`vXi zO=z61v`0b~*kFjjo-PUf10YR^mDoXI6N#08^i5%4G2qK|fj1?dmbhEuDv7fNX6KBRLMpH*3g|1b ztweu`Re%`OImIMeB;H2@sHY7{OvLO{Mx=^zqU#Btj{86~aJa+-#B(r20rM#?*fex6 z_j1{%?`gnsf9QC?nMY*jxZ9UJ;RcyV|o zr{AZd;CwOyXP&g!L9xSkpa53b0r6~63m^?@DAVsl0jzj8@^K`rn&;DWvoNXr~g6YIYa z1;!?%E4&h-2V;#@l!5Vyu{`KHPK4%00eu+;C(FrLB0Mq}$OcV?&X#9LjFcEe$U%wKA@fffu^qs&$z=6@}8NQim@gIV-&xcD)+$$0Euyk>xN zY}5g=oWe5QHE??7I53-me=j5dUOu)WAzhXci$x&~ty?1scI*vF;55t%WQ*^u78Rr? z;q;DcJa{qakJpNHf$Ic*`4Rljh#XWvOOqw`0kZGM?hvkw0s4Rk?^Kj3z`H=UXxDn- zS{vfM!K+Iw2Bg8U>6sbviRsG8Z^Xi7>{gVT(0l9=W9G>oxk8sf%T-W0jq=G*e({Z?|{s= zHT#gF)I(q%gj&E%AX^v?tOl$Bq(Lf>1)SI>($_jBT2%J9INKfrXa1)^=3j<%G+;ci z0~tgM!*+BM_?Ub86Y!0hCyt}R$vR@49Sy$w7e{k zefiHOaYQ`>tO33nNY70GvZ6>JTkI#}qb`YZ9|22q{{OR4QR*VWc_3Z3UgF0<8W1b7 z0g&lVZ%~u~;4B~w3j>A&3j><~&tp*f1H&%)WEUy@)(i$}4bW6!h&Waf_Aa-CnPWTyV z(KT<0_;SDkD6bfhJT66|pJtU2w-xVeB zsVFETE;gBEH;~-nxc<+?!q^E&1Is-Z>5EBR3gk$50dxnZL}$ct^AnE7SPer)w$SCJ zDB$r6k?u(X`hBJ4?OTKO%n&kn#U6r=p^o9yH7G{%;Dh zuF-!iStWa%MKyck8IYdOh)WxiIVeu)pE+v^OG;YC3Ew5V}iFt33J$&$2~+&a0Xm$Wb62 z`nCVbZJ{nutCQq@R=GGcwqJd%?rCJyaeTvU7St zU~k@m!0{au7tNnSWSxe1`9k>|`Z+c>EA}U3pwwv^Z_JI142ViHE8v*Gq_& zp9az+`z5XevU|2mOi3G(l#-FIbn_JY;KbNWj0Pn=C3+a2{vGomc6hwm4>7|aVrf)9 z^AasJ-!tIFM)gv{@=PFIcLd1sP`$J$xD1f4Uk{`~S{adkSX_JzJ%pEfxGTyoS&rf@ z@|A>VXt3iA&Qa(C>57kKf|# z(CJlx98|y77X|zPq<#R%wmYWZjs~LO?NaY=9*z}ddqZK^Fw9midJP&0A7mt@m`+WI z#anV*e?q5W;~KMEtnL`#+-{ZYh@kU+_E*hU!c&2?v_MlaNnn$20U>)d9fjp@c z0@eiHY^ItgnY}>jGk|`;XkcAn5D)_>r#!Gc@EOXj%9F@x1S$i!0qOcrCBNH5H9tZ) z2P^^o0FbVo3#4Jwf$Zf@p~7=p!0EBCB*qR;;irGfAvA>fxGhA3#}1E;iH0X?+EgW* zD_mIwSYQz#T{9#(HUsbD6ugv+kMSLt{51+-AMUY>6){(OW*LwbzHF_Uk3xR{SzZ#J z+33>q;LLXj$aylljqEybb~TPx*`~`^L!beZ+lm4rP%sT~9Eldm_!aHs;FIw|;i7`N zKpHYn8kQ;J<0T$zFAUfraV?PbEp4AITxdf=4zd~@g{!=QOmGZHOJliL#inI7lj)8` zh|&BtkS$&TWcq!bgdy93?3$P%9CBDu5zq1m$oI1|!8z7`@L4Ax>bi(&G#<#lt^=g& z=5^H*$~VfM(p{9B31m3~QD!mV&K|0H>^6WLb7O#9$>M;trz6s_xZRP$UjJSqzABK# zdjn}lx!wYEfV4XU$PS1F!m-&o#gLE@6WzoSs4)um0gCD3Q;xDu~TAruYytas+hF@Lj`ygm{_TDZD_aZjmU9z!H+fMES zzbZ03F6;2F=bQgJwLP}jk3NO&zh1O0Pm|%Fe|3B8qNuY074nXr+`0Rgv)9h~)+^4n z(T?FSs@*&q6Ljw0w1CsseNIf=>6cO`V6tnaXTN-#V(&ZppQSbx&)0h5Jol^nnqSxxQ)t@GfW`|q zPOCB8B`SD#`0ODmwFjN@IZ$iZvu2B@?ff!r*W>SY4N_X1yjAU|V%P6%FSWb;tCQE) z*=KLuGd6VU;tgG2jXKfw_RYC-JJ;FQZvKXkC)X`t_4qb>_RA~5k^LGxFR-)w%=LZO zT=?dWPkOCV`m#FZ{eRvvcy-CF(M$JTnLI1$llpm9tdA{tyk6Di5AIj~_VfCUj<-t* zzx#>bmmd~b@xu>IUFXLgShTZz&4;I&>7KRy-2VJ|>Tm15e!X>L>)Nf=!c%|xxX`mN zR#_~C{yfud@1=tq57jyEUbuYEBk9Ewdo^2m+b=Y}Xt5RgqJWNW&)h3)E*`Y#{>J+O zIqJsYfj6yctRCIUu705}$NifApq1U?h? zm-H)PcFixZcpz7GkFY>BSx;?aSGVZfaG#^AZSCq~Jq-8G`gGhs(|^MKy6)4?ZYh;d zPiSXTXY1?R+0~Q!Gu%V;;BdS43Dyxl;am0ftpe5K`pIy+C4T|ERC}A+N{?=DS8wXe zaqq4_zODQ8lO0vf!F`l|rITITh6SY!;#KC+T(IEVOy<)* z&>997YU~MgX{Ik~<)%*2)h>4RgdWz#t`)*c5Nalz-Yw9rGgwP7V{uc9znONX?$gz- zoq^r}x{JO(El|_2db9Bsli9(VnnKG{{`^)OLZ|V6aAJd35b!J-3J5dInl8y^lRaQ?al#Lu?WKWI`Yu z(6gsq&CwU*{)_$x?ltwgk#;Qs>tb!Q#Kq|E#rmE|#%sOoT1h-U`M)W>gFdI19X4OV z{f1t>w_P2lr{exd--dffUF~C6x9efJuhFOXv0GnZeGS*c`-G@%bf3O<)zH`DewBBt zFV{{pZnz%Y&#vtRXNOoh<}{D;!b^F~E)CbcqU>t69vx-ZRw739faur<&>G?lMxSDM zrO~Ik(RS+zXntalFY4x}{-b;Jx2qBQ;{GM|lox(Tv>1G|{s-=-^|~>3OOZcUm+Mz>|4XkPYgb$7sj+tJX6(`f^}GE;tfi|eN)J8h zNvJCVL3+}SP<{G9yVb24OxC^chw46q?AEWqnlm|u_C)6|UnL7xupg&En_Q7}k&;6GKHRIzWEmqicWUk9zw+zw0P99D+)@>kquA^=_ex_YbT(xzZJ8@iZGjV$lMdPM6e(*m3y+b z3XEN&nVVEPDrPpIxR#CMu=v(vMTE^uvYr3b|KmhgxGv@8`oZe(Q!C~^a|7h z!$n+PJ-TC{H65%qOVz$Xh-Kw54SfJ6n#6swZhMi(JjJ-hg28h+M#Lhus6IH%S6c~% zdChq33YgfJF;cDG9nepDc$W~ZH$tIEW#K`>vZ#Z;eTGfD3y~wk)rd|}gWND_#5lp} zL5l_x&D)b4s2N~vh6}ef%TFEk3ZL4vQW0YCt5O*6szBc(-0wU#HH^is2IT5xBPUDbnaf!bIwj&jB9URl4X+ z4Vz_H7k!Ljb32cSfrxu^l(Dwx%0;Blfe_2su6pEbo3<4~FEe{^hd^u5ZfK_22Vn@w zsf7Og2+ZH`_Etk(%@jM6L$tpU!rG6DVYf%s?qY&ChH4QmELwl4?0s=&S_{UW6zmz8 z=o_958e&1COU?144FeNR#5B=1gRv%8o*S&cGo|j{D@3c_Q}`I=p^K)1VR(r?)&2qF z$Ph=tj*+4~mHn+v1!G-UX3?4D(R?&TrW^{!eiL!)z*wdjO)tSjnJC4rB^Igw9D5U> zh`emk_h4e&k`?SDrlM+&fEHk)qz4@X-DZGsG>UGze@avP=tmaWJc{;Jl*X)GI<~nmAM$}i>ZN@&e8f@s4JjyUBu`L3$#82Yi~~X_Wd2F2e`sI1FVg{ zx_yY2KSt~}Vzui9CZ-vW%%4dnjJW1toNd9_W7s2k%>Ln*j_5hFQf)aH$BCFbH^8{0 znTwdULM)iMfObNNBTe-8crccyn)`y~P^?~RnN4#UC`N%fZM9%9HVualcxWOR`_9!o zfA0e`^PB$i806?lE~*h=OldXuyN_j@x%+t>1>;VDCnNJJXwHJ9xc}G@R)7veB6BEs z_{8Jf;FQH(uiLe;$5NeELy)~-So1B}DCOoGGL5lcd>VwiFR+6o=(9$ds! z9)m@r^OAXFg4Jc+vfzArYOBWDQmCTw?5E3ML1uogd`%Js6B9EFOgM&vdOsNRiJD%6 zg@B1^8l1%Q5cW39>x@9vUEc$(dx|LCoZ;#`Jz|yJ zaxO*x@k5*DnJPNkh0|SKre9fQKIp8rtJU;W+=uJiaNnw{YwU;(!~Kaq9e14U*V@(T z=KYd+uc@zxGE@&<$HzO~-Sm^VN0|4y=KY#^ucbd&Z&x$T`z}3qgI&cV&_=u3&b;fq zTYt{tCK%f?M3!(`p4hb&Fl?t8c@7ny!9r*A9&m@nX4j8!bkdxiMQpN9)_$*sRkaiuL~> zLR=%n9DEJNj?QDQnEu&f^)f5c_U9X3Mli;eALGm>fuUF# z=k}p98xMvK6>)eok^7BZiyG@NnDcc$SfnF`_85%Ty7HvrQG1+N?J#W2tFSqF_CO6q zn!IKkDvuWjF*N@`pq304#5ltzSPgOoYpEw)2z8x+&&2dmF(H=tiF(?%Hm&|7$4bDd zwFQjhP^>w5J{H5w+$%iVgSBFuw833hZH+Y@DyKD$XYB*sPJp!md$T=jUXz6)PD@{a zVY8FvzW@`p<;DbB+fD&9Ru@x4w0Q_(qen8IWr5l~FcxZ_0Np~TirN46fHVdQyHeFL zaMX&nJb{=(! zZx~M^%fK4wQ@Vv%FE~P$!gKWJM{I7kIU?Iz8^=JQ8!$X@^!*L29T=w9^q{c48uqWRrT9MD*bPgVBdxQC#6=MUjeEOMQ5nx;C&A!J&!%B{O1nFGSk4`cJ_9#zHiF( z{K9Gad8B{^BTkW*m+6(=U+AUI*gOh42&+r zab{eg$5pU;V2+H~9Pxx#Y>7C$72-pH#~iR0v`Q9UjC;1*IjH~Pdd*|0=tZ%>CH)6G zESY%Vsr;2b;=Ijc>Q};QH(9XxGQjOGs9a~>_F%{|u}FwjX*w94i|rKsc@B(?6GwnT z%Y~`peP6g_cu>VD{$nt+sphd{Cm08rFt+##F{%U`3|8BW;~RxJU>vF$NScp_L9NUI$Etw$G?pF*^rkm$)-4bdP0K1AM7d^Y z5ke^psfG32n|ABS?-V7&jJc0cf*FcDBwx&0Zy_|^)KU)P{}Y&@TL>kap&myRCCv;S zK`2h25*K2vchphdQiR6yMX~EKI*6~7n;w^MfUTb*G{V#he(xx5BtoWXmOJ0;Ki{=k zJDp%z%y82r+p&!2)>iVOiOfXHGjL<+c^bny*W@zLo zn#*p#j!+u2>QVPyRneG3rya3=XV`>Me}%dtFv+YT=q%n-=&R#HT@euODsax>=HUpL zZ?vsv5gKXM(CIuniCHZ_p4am|vRQloc4goL5WMMt|65fc8ng^(DH<1abtDfBDW95e4AgvRRbk3y`s5faYs zby=VE)Mh<;*^#`-6&cd@A+#9g=f!L^%c)-R^=L- zLX#IFw8IQVURRV)&Cs6+&7cpooEu^)o6jVcM>q7y7dE&4zx{hjpAV%0s!|O#2(P5T zY^E99)=K>D%zA@`B2Jvw7l8$VVR>p7=y4gW1xr!Hj*~Wq`Ftl-Ln=fHl>_ z=Z6+Xz)o3u5J$^z8(ZyvzS%JFk*oG0s9A~O5s%K2Ow|{|fWN@l;5_C_gZlS`0WNy9 z9j{}+nj=mu#izg;=zUh;|7*PN!9;s3Q+v*Ubp@X!JzB!;;-p(R^W+3pGMt zJvK!95urv%jZut;KDVdhKLuFyJ+A|;ZNOUSNqA-bDMC!;Vs5iXsEZns11+A{@i`dAz-BN`Uok-4UWj&x*0urjH%s7=XABs9 zt(hm?9g?B+s6b26m&VT?u%PQpk;cvZtlR6AVCJW5T3;}Z4t#WiF})kCn^`soe~H(^ zChC@F81Rh{qa) z>LR^k1{OD;>3@Yt{2fKpXQ?MW;c{{=U@g?tC9FEoj2sIGz3}z!(AIUt7x?Xs9d>gb4sA-C|p&P2v zxy*ckP%!l3=CZW|tR9$~SP;P27_0drp)9@|&Nx@|BZ`h-wZPyhjDwM2G+Xq9CWP;s7hzB(q;#q1LMjhSg^ZlF6!pcwaj)m+Ej!YSD~_Eu^N{z zs48uZQPuJMj1cppC!&K$xLb;XybFmeVlnIm)&y~Qn!=L$sf>eXu>|}G*3m44Q?Wu} zky4a07p$ilXKol^9l+oXob`Kqs7hCp@!@?vSTnG~hDR&-<{wb5K9~}Sv=?!71YQ3T z7=4r1^u|#zt}^0Xu1isoQaHRJ7z-7~q=1PvkZ+WiI>%YBfVDD4g~KPsM8}F9`_p1Z zz8di08K^9&fLQk6t8XJ+T#KM?;1p%a)eYAYC*I&;{l zZbp+PD7sIjH?75(SOC@zNyN1KLo)M|FSViJ(G(f7D+^ojIvX{d2MZAOVXG`&1vT)z zr1moEHbdgCAkYtDieCd`|Kcec3f4s58ooW$P$M`9X>-6uELTdb0OqVRS5fON zFnj_E7gR8!gORvPEysj}zdR;@HALMOIjAjq>XgRXPN;N@INRI<;{Y-DRjsP8h%;aH zs67pj5Y=uS4^iw>df}sfM&S@RfJ=-R67jV~x0}O7#dkeIVMkIO;cnAq9;?9`BZFhN zE@)f{Q~lLCM!r_6O|5D~v_h5`Khf1PU2&$;4^R2$4%1~JI| z4E82M+_c41>|0N4En>rTTLb#GZ~4`u`%ug!#T*M-?fPQ(6V1s4d$TiI9@ICUx5o2E zqXtN0tnQ4J9-+WDjXwm&^~lX!oeDH`3~zQ-J1|xwUKUOQ<8o*oEVTV#92I;a803ck z#vx`QKZpnbFa~!@-zMtiBt;c=j_*wYF+Z2jF`s+BAg3kYmN)gK?6(8qqtEpoe<1l7D&|Fm#j0Nr05KEl^V{Uu2erbD z8wn8@1SO625txw4Esf`()}LCcc+J7L2Tej$eA12=6xv4!g*zIrod$bz@IdzH&S+&+ zs8i=zmw?&$!K?K)LVkpSf=>cp+al19!RUef{nX< zVO5xFz8e;$CxS7L*vz+sv2<~Sc?iaVh}naug+^^Km&}nd2_dn+pk1?is&4q87Hv`s z8a|P5Sev$v#z3@w2G*X-iRErv<9Q^`8ouqsV3Z4pQrtX?$3dkF%y%H#CNQ!6&~^90 z-YyOi;bLZ*&*N_Mz_=%vAMY5w2B@{&puFittx|jEys`hmE`W*c91kmMCBvgH%pcUj z$#2@1U|cDMM=pWAov6(_IuD+SU~jAa8H~OYZ|=)R2)~N&D|G{VQ;PKxSX;xpH+rU% z>~KO4oLQiT$3N>q9VZcIKGy20af9lM$*^?ooCq3(_%tXek|ulIQoq6HwtgSl7? zhJuMbozs6gSUvL_EWaQ`k83=>d(`hP`aGW;3TOb{_s@sQrizo>RWL3?u6jgU93gvf z5bk^(qH2c6AQ<*RPgT4pcKZV%+RaVV)7U*ot!8NwY1|rw^Xte+(HZW1QEoXMX^e=& zI1I;s=Hb(eV;thef5*n!BB*pbb{QOXu7PnJT6u1?R__hQPpq|x2)#Xw?E?!!D)W62 zT$Y-Ean!kwBMCk=*QS7Rco$(av=d<5T&%`}L295!=e}6RNTn$S`RSLo8!9JbS@Yxl zr(m?Jtof|bx}WGsd}sD(pk-D+V?!d^c^)eFW|77>N(_>+Msz!T><-pQ_r|w~79zx+ zGE-TuM;WD(u~?QfqLX2D?`W}cmF3|`{lW-Nf_MpHTSpG9dVewO&HU<6;{o#>fXGo- z)_g2+jd5h)5vv0j-|q>tW`S`s<5{)?KH&lr6P@n>iVl$OHq>5t_UZu2CDT02S#k#$ z`O;vis}YfgWxZFdF&ET&DAqjNq+=s-GpeWKh!tgmb?YE(_l7Sc3L0t#220;KRq1Og z)*T3nNNbUJoVJ8I5W!9&xb=;y7BJRlqQV{t#`8>gd0K*8zszTeqhQf*8dqzu7zr-s z+pSD6Zo3xIoQy>I3@YexP@aNCEKXYwhQX1kNy2q9&koRtH;FX&WZ`=m8wtwiSV1kz zla0tMwPiLocW&^CiXUw4Cc=;AMRdatMz5*EJ`>Ri=JhV*{KSkj)1f2Hi^%dZo6U>p zf**{NY*Ro$$%7wQZ(hz=07@UJ6D|1ZClSsxFK1*$m>}jwWVvyIz5|Pj7$(s0lZqeJ z@Lr&ntIl#V@xzPAdWVtVa>f!y5|U>#dYT#eZe(%OW&HmOGW`sh{{I1mADNJjorxbB zWZ;Jd&BhO}{|=dN9)6g9zQhGUUPS5(C4L6v^%h0_PJ%FCF%r4qXE{^jBC?uSKwi$sggfv<+=U-r??RUItr;t@5W?R}{$F7>BUtbc5`UB# zh}2I@JS%l)nkBhXENkoVR}=3;qB)Ju*th6FtDE0x5kW zbs}3n6Ug+2)QOzUUjSL(N+1o$UMCa03z=ZEjDHu>Guvc=dw@*3SEeU2xDPj0d;-Yy zr+_rHGb zLEg#5p~P|X3}ZX)$l{6Q_a%2mN)Mz?WV*j4C%PC@#-Q~1V^BJ8O=#D1L@><@i7zF- zqKL~Gnf@Qf8^>AD9h6}XXbU575!s1(fvh|~ki`^`@kE{qN&qQ&O8s5Pd|omge*-yv zTvnzhGQOO}EY1wTs8JuPC8P60uZeipUq_}VGQFR~x>6@nuP2eeQk@r(dIQOcT$!7Z z8{T8paySX&Lpqr(Kq7y|J5vNn9!!FZ$l_WOjexOmUAwVx9iv;xH19%AoN&Zzz;4V7 z><(lT`^$X)9nxj7NXITokm;Q;+cY*&Mi5y+lH|@vJsCO+OqKCO2Gb>XMoO8uu@ACj z{Qr$|Ep(1xhEd4C7ES=N!jEME&R7EaVyXX+(e(fSMnV4{4524KM|w6id#TL$E@Ypr zL_BdFkV!Yl^h5?XN!$Wt!CwPe@Hdk00P=E1j->-4K3h2`6MiT0ki^3hk4QW!@tDNp zKwd-!Pe@MWZot2hKJn!Hxfd(55a30m#q)uj_g@0(ne{*xv>C{Pz6SF8?~vtg zMLHU`Q>G_U-vwkjyItUaCO9Ay5NW_sneZ5po;W4>X&}@81jIk(g2Z2eH1Hab>2Cp9 z!5tZYPx1#q=6@{pXD;wREBprnEi+4z2uX24sl+@$7U(8+Tg@GQYSK4Ut(ja|5up(Uqw)7 z-e$P51p%@kA}eemF;HTV#9$yB6e@WuApR-l0pec>JzEKv2_k^3s54Xl7sz|E=?7%KXrLXq49I-TO&$He5&^n+J&>0(vVcv{8MRg74w;U~_;01Y z56E&3%XlIyJ}S90(tu;sIsX};a9k!Nl7A0m1t%q*2C~4j63gpC)Bh^@6^Z=q zAk23|#^03u7SP;(?jV4F%6;58@1IKk63C3Nfi&nJASnJkFNjLU(nV5QWZk@{+>6B*oq8}&_6Cz5Y5 z5&geaMi5!SHpz+P+a)LR%=ZJ31^g&=XQXsa>dwgYKS8GlF3NbKinrv-B`G)~EB+Na zGhUJL&Y0KOxj`+-zw4yjW;wt+67S07L^|*<$%!oPZ^?09|3Vg^Nu5ZZPhx(l6PdrDL=UMuBl8uJ`dj4c`Ob*9I`eqq#xti6 zkS(bw3nG$NmYm2Qst#m@HDr7(8Be6{E4gnr0?bfX3PgIT5s)ov0%V4!GM-31Kyo6N znNZ2!g-mak@kEx_TJmfL_@<$Y6o_n5H_3_2&|T_1CH4Zc;J!c_90SBZC0^nXAoHb2 zOl2f4B0V`m@N6@{f=0;%&d35rOP$DyK9rou_^}elNgOZZiEPLOsZW%;GjjYX{0n8g zh|Dk@$S#=)q-*B`Y2ar-UhhI0_9fzJ&=Q%BNWK)v_?1$3M)OVDDj7j!hSfkCvR3NO zNJBPA-5HsFlhlbUXETuc*All${07L2n9Y`civTn1mJvkqJ(3g2_exHrAqS*>Q0hds z^eB+!o&eH-lQRAtm~9sPqf9_#MW-YulAo6RUC1u_1@UEoPh>hG^F5XLOyYAH{}$!^ zr@#y^fNa@ona~;85_3TO3)xavS|O3?@<>i(xp^hJNu5Yt%a(%XgfyUlOyDkcA}jKc z+!>j^nAC|Zn15c6*SnDMC1iYnBS56(p0WThAU`Ll24tW5N~{OuMYI@GW?>5u)L3y$kuk*g>Z22&7q^fGnr0)Vl$B0mTsNE+cx#2qG)$DKS#& zL>kf;$bzF}e6+;=KyT>m7*;q2$US>DurP2Lkoi_fT$LB?r?5r}>m+WFxJlv`iCZOZ zm$*aXE{VG(?v=P-;z1xA^c|25I11!-l$KIBA%%A#<4+-;EjlaH5xEloD!DVVqRY^U zS7bbq<=l{*$Z3*&8-Y>?SaI@a1#S}gryN;80X`8(q^Al>PGouy$%%|FDzP|_`Af)n zBI7+JC*nP9wo(BBCafqUh_tLakjDA}*@re6Ph`bm65C0gSR8sZkQK!MS?&NC?~Gp1 zM?p7V0OiUAM1H<7LvkV~k0CjcABe1woX9TN2xPjgKvuX7NCUnB($HN%x_+;W-v{I@ z`2ooBr<_B834aFiBC_RIBzH#YH=(nFTN3Zcbk0bF9zbW*Ga2uUH1s+2>>>yhKr>ii zL5YQdY?&8t5}Bct)GGqXD*>6W3Xlz`F7+BfUPN}KpTtH|C$b>{{B2V#s09QT6eJT6 zSzri|Qajw}!j2NVP{ieosYWJ~%>oydaYB>(S_&P>G*^QYm5^%&I_sKwrYTLPX~fFE8&dT61<&w#w%BKzz= z1mViX&^VTsGZGh(1-<{a#96un7m@4OMf`BNx-9V;kQb32yH0|O$c6b25?n+K+V|g< zc>isQ_urOy|7{6z#(Dp339O3mzb*0p+YH&@P4H8I_urOy|80o^_~49_P@zAe$sj6lHrnDl?`+Y(><>{1H^1$p{gBc2WQ+c$DT!uj?$ z!+!KQ`FW!)(>pKeoBGR*i+ilfMS}x1~sKfp4BzZ!Dg>rQ7|YF~ti; zsCC+Q%^qZU|D$>uODvYQ;f~)Mz`|W4K6!d(@X|32cdU(^>~^p6Y1gPbCx0JRyqm4W z(4z613LLDpHfrCK$O*l7Oc`JKPyt-B>(Y8_FD;L)mAC>$#BP4L@EVr)N0hz&GGe=oGvu|_`+iB^w zaP7TTPcPm2t?dU7(&BEV2R_VudgJSp&tE>sv$Wg#iGy3mwv{LHv}5KDt?DgtQDQI-?`x4 z$GZG*`h3cY1?z_7w+&dfKeR(Xm(pMLUFDO0!M8_#&oO~Xog;Hc)lDcl%S9dX*PVSe zziEAO*^OCkKfExoXVH5TG~*)5&7N!AtjWQho2G@FUpw(s-Q|^srhjcYd%t%}r)D2?w(jByU)!&H zlLn6dvURhTpRP-~&|V)sc63~?>aTOW=DD1<=P$77$AObmy{djcuG_ha2cP~q?n3Uw z{xjMQY!#pK)x=XPY&v)>&z06MCo~!OV&HGL zr{vucf6T|D;MBsa7JNTvWbbs}_Nji}DLJ8AYD77icf{Gei3j#aZ>&AKVsg(HbB}#J zVZ1+JPr>~y-D*0xap+P};nnG(11)~r_nkK&94 zt}yRG!x8r3LqFNF^UR6O?!&@9&e-t9+Vo@Nd!5*D`L|Qk>(AI{eqP~otM?Rp$uTzfVOuNza`@Emv&*_Rxjr~%SMwjg=+PE9HR_sdGMY(*h?Mlzc@X7$NGcIT;?zCJ#fnGW#f;gglt+- zW9Z3iTfWRVziWH!2$bG%pT z#u3+l=-2i|*{s?JDyAGL?lrA-|B~zd+a2qxckyi3O9TDL)^oaot4Y}5nnXubG6@R z+kAe>Gx|V*Mr8_Qd~^M39w+not7ROQYvHluS6sT&`pie3Q=gBm{or)AG#UCgVasy;a92-;;l$y$0UzHF4sLlNbE=-YHPSr+^j~@yE7jK~6=t}DN^ySKT^p9kjq-Mn(M@`RelA5K1d zY3Q8ZGYZT(*4nn|;WuNwcAhPqT>9ZRE30+B*4MZDutQ&+8WrH4)ptcH!`%(${Tdwf z$+!C#EgZO~^Y@X3>uK5J0{(JY-FbfIiP_;?*=lCv~ zJa=S#-rN3xTLPE5TnqL3=kX^|i#O?qE#5w7s%&q&WOrqMkCGu7b9Wd!Xx(}A1YWmPYL=+%xaXPJ zZefXS#h-LNwJxT}S|{^=+qIFENBlGRvEQyfnd@60 z-(>el|KsxO0X4lQbb7RV^RcYgPbUohwut?1V)N6F`c){t{`L1pk_Pie`E`5pPt9N4 zFZLN&;BrdtnUeAMf4rJ_r_r<2{N?6sd#aU~@a>W1{id$UY|F8mHnXntF?Yaos4B&*EjADQan}UNU@&S-KnN z^I6=Dam659HcnEQkRL+B;t;MHxy2#)7l3dBg5|nm)GJ}>X56GQvjmji6yqwD+3rwU zm4tFrF=mv6(z+m&zp30(jFz5Io>E!j3FVGrJfyO$5R|T7Q2tbm&%L1ZC=A6~3d()O z=u`@dn+KH5R30jZr8JbSRANg*d88N{sKgb4QoIb5$BNOv3>43zP!3Resu)GQp&X); z=?&$%V(g_dycm?qWud%OjI^>)suhQFhRSQjs89~dc`D<|!5NBivK+lr0z$*`5G+P+ zd3vWLgc}rGjk-P%Zc>=(10j!bg~Du42(2nWa5JV?fY90t!rv6~8Nn4HJf*OtB7_3Q z0}9JZLFifuLP2A3B?vuAL$FqcP}qp548g4ogv}I+7-|&=TPeg=fl$m?Pa)15Lh-5) zN*K{qA$XRBaDalR;ZY63Aqtt*Ae1upP#9hgLgnfZ${4BDAyg|5;S7bchEEL$=P8V< z0inEclEMTZ2n}mOs9@yQgy3HR!VL7eebw z5dNl6!w9Yo;VFeBwIS3p9#B|T8A8`O5NaEX>pgv}J{8ERb! zTPeiWh0wrQPa&=vgyQueG%}*=LGY{&;Q$4H!=pZgLliRWLuhL3p)kA#gvt#d;BRF$ zfKaU_gfkRc7(NXloTo6ZA%q~~B!vmJAT(?Qp{0@A2!g*agc}q>jk=8?+@vtGF$9}& zg~IIG5L)>|Xl+dQhtRqXguf}YF@l>wcuHYO6P&->VPSAwuFHb8ucv&tt!b%C`B#2A zy72Pj1G?!6f4S^PnHO@rebe?$(j)zDtna;W*IA3L+L@IZE6eV0-}YwlkUfL4R%hIg zKXSrY;D@EES$G4#b$i@@3M?`qta;ZOyG9IOk$S0rs}9$_>lRLOdAaL?{}->O|NiIs zhQB{J|KiI2a_iciUQuq<+AirOmVJEolTW^MTB_PRTX#tJ?RxUr<753_EeXprC!lz~ zT}{eWHm2(j$1V7MbM>sx$95Sw?^>sBUU5D_ce=D)wD-oM-&(yoaev+Ovd_LgIH$;> zf<|~>(-X#GGzq?!GY3i$UFYjbz`MvIX@!DFK@)tMmd~tNs!;fnnX`1WyV$sHV zEB9TQv7>$Lx0gL@Y`WO~fqmLdi!sB? zct!IXe0BDZujk(!bR<1={CC|q-ObbE(Sv};ch%9qK3d!0!{5U1G<$J>de`diEoaV~ zzWl41WiNj8HA{m;D{EI8-Vd|0WqwR)C09N+B= z+wt1n3pa|=yodDo?Wc)_PULPMVYPa>lyCgmyt{?R_Z|7HNzXOK`fOO!);Kb4=7Jn! zbv-<^Wj@28!LN{gbGha#c&b=J>$TxSnz*!gPoEl>__)!uPk+-!eiu2h_?GA6wxrrO z-%bf%yLnx$c6kopdzn(@OzleTn%6uy_@&yQR#x8)MxXjVpVGOmZ>K}|`rSXWG1=Rz zLfdsye_6iP5?1!$!-x&Lm)z(k);?Yt3dm#F<0c(l}NOMoc!k-!Q8G*u_;BVMp{v9N)sAG$t(h;ziR9)0>$6oQovZ%)Y48J zU_5JzOgH_Jq)#(6dZ4kq8HCwQAh4`yzbUr6I??D!m}IOcd~9f~0h5hrfU(TRR<=f?rWzh$Y^9y8 z41+Mu*h9gsHH69>Q8SFxHW0Q_@NEm>QzMH*EG`T}Ksbb1#>8+4o^2r9r7+uQ(jLMg z3Jcmpm}~q&VR%~z;T<5%H|BJJP^}$=R}>Z+VI3iyr?9#sghj?P3KPO1^ofA*xv@L~ zf`5Am?wuffY4q#_;U#>5*}!V?KwOwFbU$0RIkim=T*kPzPpp?Nce zZ_VOn2$78u{F)=|FpZldq)6B-;d|rT0%2Mcgl;Vmc9~=eHJT#iYKgGNM7Kn^FJZrg zeI~FKLSi$7L9GyeG`l4^O5Uxo$W}@05?2<6M9l{B7Swc)}ggWgJPMYcM5sJ1!cp~Anso4SHn1p2= z5YCtf65`t;H1CLT&MfYT5ZMmFuM@%r)3_5tiiFJ)emB0+2-Dglbc;qvG075YbU?_} z8R3eF?u>9>!hQ)?O<)&<#EuAqx*%LPyCpR0gixw0!cEh!D}qln!YK*2O|fnWNfO3& zL%3s(OX$=Yp;C7Su)CgSOm_ybfG#N4q}=y3ulGRNC1rLGl!u!Wp zq)6B-A&v3vi!iMxLbtvMJ|8glPj1y2TUvrc?e@n^gM+7681|NYXZMSNSuQ(=u3q0X19b!Um%p4kC0&c z%}4N=i*QQ9BvWhwLXw1W3lKgx$0c-{hfrxD!c;SQAws~H2-hS`Gf`h5?2<71D})*5 zvV@rV2z3@A%res#ArxJJ@I=BKQ!^3an1p4C2y@K?3GoXNnlDE9(kxz#5cw5?-x7oc zrtuPl6bYLpd}VyUMwqq;q1)F8i6&V>jYNc8OA(fs=%onvCG3~5)C4X=NL-9CXc@wC zvs*%=C5-(c%N?~e30aQd^EDQymSeHn6kCCiBw^eNgf-^4gicElDy>9VXGX6?2v~-2 zO+u21T7|Gn!t7ND8_Z=1G0PF^tVY;mrmsdQx&q;ege|7#HwechEc*swn|UB1ekDTl zH3;9D#cL2ES0VVVMc82)uSH0auvxz$ApkH3)-}5PmefB{W)#P%0VWfa#Zv;Ij_ll!Qa3*an0o3F9^(95%-#bXt#4 zX(PfBGkPOJKoY_=3CB#-CWKuQW^Y0`VJ=IENk*u%8R4Xvz8RtD281UPPMexr5ROS$ zwgusgc_1NvBSQ172d&}bV%sT~M6O}`xoKHCvaNw{r_?L_U0$ zFf(?c6y1sPM9Nc#skIyBn3QF^Ny@`K*iBOL-y<~NgWxcW_aH?6fZ(?m!D$-rMM#mb zSwb4)yANU7E`)CT5PVFsgc`dMa_vV*XQKBb+?TLlLIxA~BSPXHgh4+dWHh@aG}?<$ z>L-NErr%EpKKl?(Nyuu79Y9EuFzx_?zd0_U(|&|X2NANH(FYL%enhw?A;3f(Lf9o? z_929v=CXvCpAhQ&j1X+5|BO)d0KyXqxlPT(2*)HWJB*OmJdhB75TW@m2>H$8Ul1Y> zA^06ZC}I6a=)9(a=&ryU^62eTeUlEcdjQbU#oH;I`(=mifClMmd=#vNm z#}Tech%`~B5OztJeG1`qb6G;n34}VQ5h|MLrxA+&itt22WmEGvgkutx{f1D*JdhB7 z5~2ASgg4FNGYFBV5d6*}ylonvMM#mbSwc1Adk$gRX@qX)5NeoY2{nF0$aNl}mWe)( za9_fH3AIh&1%$*i2!k#l)HS;$G&+k=>LNY&eJ}ISi=OLq4yCyhlMhV4i~5d5SfDD{RcujQ|}Li6bWl3bTFP*5vE;6 zXnz%jr|) zHH2Rz^fvi!A|y!|aTB4hIVhpib%gL+2%nfCw-5quAY7CXV?u8u?2<6$HbQ@MRzl28 zgm?Z#7-%N`iBR+w!e0^wo2qvZj!9T}2O-Yfk`R9zp}}7WL(ROu5F-CX@V<*M+|;{^ zkRoBNgptPc9>TOc2<`77#G6$TYW#(e?LNX7)A~NbeF-}yj5S#vASB*J*#7`wya{}W z(C8k*poa(vX14^N`v|2TAxtv;9w8)2I3?k8Q|vK9rw0h*9wSUO$0Y?^ zIbUj`odihqMA$E3xe4?}XyiZ`?3Uo;g-|LD!fMkm4MLKHQxevgVrdaNIT6OC zMObH!O9=2rsN{o?WJdcS?2>Rz!UhxNix86rVYV;ACUaRr(X^%m|JA5C&yNIAC^5@X3f!Dht9P(=Q7`l7v$d z4x3_G5jtf;7?%~{h&e7HATvUx*AR}G(XS!wl5kDJ2@~ay5R(OAwm-s2b6G;stO#|o zA)GeTvmqRl@I=BHQ!_h4{A&oyvLl=`4F96|p(>MTOS~i5u z5>kwBAVQ7o2;Bk^u9##A_a)@YiE!0K=R`=%fv{h~brTqb&?o?5P!PgRvs;2sAVR5N zgxjWHFhY`qQxfi&V!04Hji9G@FuSv~}Zc_1M&4?^?&2u`y& zKSGKGzXAwpOydFw)AAy0mf&N23nJ9WhtRDcLOPQy;l6}ig%C2B=t2mI`4RR@$Y=r! zBQz?2FsLv>X0uy@PeFuIMG&%@enk+HB%G4qZ;BN~=u`+{Tv3GV=D37_!U&a$Aq1Gw z#SnH$xF#W|i7Ji|Qv_jlafD!VSwhjG2z5#zd1j1$sMU8K1uZEt*OlvvCO|qO4CQBKdk|tVC zDYIQphzShEDQ$YmDPwla2{rk`aKcPKIc3d3Ips{TvN+*ph@1#>TuyltS`H`DjK(p$ zLdn3ja%A9j6BUkL!Az7>(Oi~O$yANNscfdpdBfa_@Y?IyXZ_~#US+-f&hi^@89hAW zT<-c_b+IrvYk7IEZ(Px9zNg=p{8S~sTNk$!H>2Bo^4xcvzUA|~^{S@Z8(tN%|4_j7 zQ)6-Z5P0W4J-UbE`V?Hh-@dJPLKRl@a?S#fQ-q0o!MUAtEnRQtIKHsi53a*@JO#jCwodaE8p_+@%&@`!2w?BJ=d41?RCfcf9j`R z0qJ`7=-RJqbocg+Ypj1-%PYI5w<}Kyo!;S!wRihIJ-U9<-lJ=MV%3}1%RBlvSYNlD zSBtc+B7G9wx4oYE%r^PzdsWERncvt_#i&T_`?UEux@$X+W$Sy@r|!70C$^^E$--P$ z#%ebtV?)>18|?My9~o07_qp<(yS>WFUz!E(igVRe>n^So(=1ruy{=bAS2lfn_vqU7 z3Fa1UXHF^*4G{DwfpVKd21GZzLWg_$Nyiifm)uvdc6UEH(Qx|Eu62LaxI8Bn?l@fo~EkiC2k0X|*_iiXc{pMn8OS@@lj3gd8 zEKTp_P<;By+H98gr=?{^QGd*wWay55<>fnrm_49p&LL4Tf>rXLv9 z*BVq92b$v1udM33Ao_D!c0nB9v6{r&vg5|$(Z_0%w3b~iv`;N9R&OCugt?)cC8o2q zJZJ+fErS&}FIrDa^Ru*kXx%MMZ!u9p@(?DAM)OQY#6M*7QV+3EK-YhtGk>Uw93 z0*As4%dmhII1KHUrRi5ns4l%t*yE9<6}2KPhjz-+idmYb2*=RWX^UH01jnZ>t%Rk; zmPb5p1ukicdXYdgODkn*dO_H?$|-;Li(>S{poJ|vy(~uFdXef^puaMfR*~a*pw1nN zrXZDopKf)3k6dqRduVBuoTRVZybYbLOXm&C@EtV$&abYFDwbA_X!H}$0Mv9*08kNXrEhJO-rkTrr!ZB zj9bgn>T;|fur7l8uBE-laY-v|Z8Y_x_d!4C?W+Ix5LJ?Tu*b@^{i84+pxJK#(Cc(m ztslZIYjmt{X-xY(Zd#iCI-Le+dWDWUx9&YkL*LSRlVf%6M*7KQi48%y)n5}_CDI6t z6=73LYmBxKO})FBr8VJLFCJ0vZjPq-n!;{H!e2{EYsRs@6r#V@R@mk$|9(qsV~H&= z_|ekZT3SoA?=7vJ6=5s1NTtSK2g|NC$4fz1K}Sn#!*NMEusU}qG*y3FC?!qx-^CK! zaU5b9cDDkzM=Nb6X}!_(LkjAQdQX9By$|ShBKjMGrfTgA2d!orZiW3A?IN0* zaD=6O!tw7eJL-R=72&6d8=y7BTUrdq?@|3~!!efDkK?z|)P`fN2>Wwf)6&LSb_3A# z+tclECs^7*j`ai9YSxJgtM(rRdTXVsa*{;c!JukYRZg}v+3JNUD*5M@7RT{ZOPgY8 zL(nu?klj>E8_KcnEBZ5*HjLxg_Nq7jrdi@}jyqV|bW0n7rq_w8dS_VLNRE|3Rqsqo z8^!TuG*#~`G&NH^sBkLK9LsJr$9e??e-%8wu*5N($xso`wY1MTo^NGlo~7m0#miq} zA2WWiGruX>(&=M1b#bnYErl8arJ)y<+!Ol1$Iu)4LJ!baLpwri=m4D{8rniT=nUXV!Z&P1!yYV23lzT}$6Kp#og$8$e~f{+jLLjjme|M>!R&(%<; zp-n@XMyc5_8scFrsE4ZO4kuYx*B!;l2++l)kwX1mSG_LYp`Z~(BSRc$#2Eq_05pQk zf@z>}R)aw_XaLaI*#_D{d*}eVx9VQ1`|g|2*q0QV(DAe?XaFC9-gT?*3g4w;-Gkep z6@q??e;a|e!?*Aq?0}u{J^TQ>U^ncAeXt+&l7RKF7S_RCwEOS?9;$>|YG`TEA9_Fs zXaikgAZUg0320T(544gP1X?|4wV>6376Y36YqH-CqCu1Vmhe4^?u5b|7l9zi4Fw^# zJ3V|T41qY%+i}O>eg-Gu6li5|8nhZX55L0|xBz$H2K)tQ;4J(GDewnehFfqOuEBM< z1bXMppL&7NY7V{utso4{fa&lpd#4yy=tY;VS$E58xWyhD(qF*Woh!21h`zot+O$VFkn{^50^J0llsF6ZjN*L2qaXO+ZVV z7SIw}!zxuR=oQ>r;&`EXLmF^^6AD5xC=NxS5NPRB6!Jp>2koDigM2WXNcuueswM$f zA9wErEuj>IKuIV8#UT;9ui#6V4~u|3MGpsPCOHSj!vvTDQ(+?LKCAn$rcBi}!myz7 zC=Xgg`O<;(#;a#Uat;Hnmj-ZtiQ^Qw1AoD7I0lE|5j^2idIp}@J3zZSUho)AYpHv1 zAGC(jds*}{nZwX8mJ_X^v_9$sS`)=U9XxA5ZFp0LWI}7BeE8*shR_^ZfYwKEKoy99 zsn{og0WFEN1eyp1@oR;v7i2AmgPh0y!hc8LXVCjl4ujS`#XxHv{g%!fP#LN~4+0K@ z5%3H$q4_~Zc*J=&To3RBFK~bl=v`8JOVb+M*)R|IF{@aQxg6-XoPL1aptaOaC<;X& z1j;}uC=K}_KXj(gY=o;c)eWeRrZraQBP;dD=M4q(vx(+u$Z|1uVH@!2_ zt{hweExbd`&X1j=Vl}%R1)9;02F+qW1I=7DQymYQohE>0q?&+g!l?LoK91?xu7Z9moOg|z(TF>wELi439VYSO4T|~?@N9L0QyzJMKBul#>#k@4Rc^FR3O|Y;@S*bU@L5c?eMLGi{d*DR>CUy5%yA} zS{&{KEeQ9(e$blld)NiJu}cd+;0q_w^5BL+2$X2xr4NHI>e-F0!Jq*Ws(~aJ4Qv%Y_?0S{XBhVV}DLe!1qk4h^oZt;ZUxr{E;$y-%lM1-gM5un@Es{0O}fwB=ZP0eVx?G|s2P z444VCVGeu&b73BQ3G-nAEYvHxzT)6VI7$R*C|z18&ADC&=#BdTcO5K%uV4`*!eUqg zdh^>M*b6^G2`CPgspe4JvJegh;3hSi74$w%y>j!B-pQ&(qTWNPcUukyy+5@ZG=UG{ z16WH5^Fjlt1Np#{g@*&Yz#Gzn5BNfQSW39hVIHg|GwmT7&XIvrpoQom%|(BQY*uSAR}5P$P8H^4u-%`7!KdS8t4O`z+EzN56)1ddRJ6K zT)prtc0JXS1SO$7yheh0JLwa62A*hn(Y8_I_MG3sy$#FZBghY0IO@&gAy66Kgty>r zs0p>84%CHu@DVhGMtUcAa}HWSThL-ti_4DC2|7a;=nCDSJM@5_&J({u-Xq)~|s$Xx*YD;Ez=%yIRK_M87 z@o1O|+E5OJnotAMlK2WDIts@q-8nc3r(pp!hgMLHM6@L{4=RvYMbPf(K;q~R7fI(D zT!r?e9ovrodf}m0q}7H{(1zns42HpQD8RYikfzN#|qvc_u3xQc9?d* zwA)n#ih>sqiAQ}hl8Mae7tr(@VA7`H&V->b4D_~8y~a&`d$HHs@fPa(*DggVPP8MX z9jMo#0_-Eeew6_35GXfx)yTcJVQp7Cqk1cGBIvEgQ{X&y7vL=X271@XMYseND4h0? z>X7le@Lnwcy$#hs8${X=(gsi%l!b7}0ZKq`$&;&h#mN=g5m5okl3|_eMVgyPU^8eh zNP9mXXxg5Uowi^80NbXsU6txA&mXJfNPC2_63Ij)Ss()xqSSgkrpIe1EdM`oZ-MML zVIy}L{>QWf$=}N9uI(7z?>x#Q6@?<8xctBYdK&f+rV#c4?i|p-rtw0fYZ~Z^-+5~B zYv{u9m(Urap)It4I#3%I3X9d~`6SmzXHtct%20^xhu3CxdNi&+x!*aN#^ z2Yd_LAw6sZ4a*zh8Gou>*(*LO%N3toRljtx738mDOOO3qusy!BjO>ia*iJwh{Q;Cw zWm0|tVEfCJW@o}awhL&7wc|d-Rp*N2Ac1~@A3@7^MP&a~=Uk=B0g6zQ2Ab8C0qOEr z?a9wh==qwI{xhfs?KtHsY@m99T@rh3VH?RndkRP42>b#{Naw#==O=KFgA%bLRU>Qh zq%k81ZgH+LL__x(j!(mHa28@Uz0#dd3mi>_p1@Jm-1J1#9_ybblJY0ec z@HP|@+7+>mv-QJZ-64L1QkH>MnOgExC-uDP!-;^+}L+Gs0B4ao#;K> z=AcDxU0iiKjUwudw!hs`ZGUw_jR~?5aUff}^D3_T#PK0$Yq1`@4|LpEmtg}=)RxVl z5vbi8!bi{q8bec1&u@kME^bTQHqaWBSUcQK&=ER7dl(C!!6@hgBcTU$g^7fD_RJKI zcjol%&Uru1yP5X!&bMMe=Cm*Lf!@#ydV+$C!5t0ppbM@u+Ek9`!WW<^u%zk^VgH0CV9h&gX-Q zx)2tCwq>*#rA@6#pv|eQppB}LFang{;kd&<;Z&VNIaXXla5F+23v$FJO2}^^e1k#j=)v^4i z0Bb>!Dxe}>4|b#)45TTLY!!(H6_wymxDA`Zu7O(|--H{W_++n|(7<#Zj)US;Mq;n= z-&L?9KgqGGN(rdC{(wzz1unyP@DrrK4mbgapa7^QRFF&XJE*EJ!Ugyi&ciu43uoXr zPul-92dCgy*bQ4@13X`%jhx%nmWyL$XbY%Wc7Zay4Ss;{VJ9ea+d($+R|f26R3UU+ zMD4E#Rayx;e$iC|s#;}2wWJa&@jYO->x&&uncWMDOVzD-kHQi71%3u)!nI;O$boXd z4^;94pep_m_Jbl(d&w1tK?x{QyHwJ3ehhT{yuaNq)B)8&Ran)a(u&>8f6tdr?XME5 zbcJ8xrv%igWM|iaI@t3GJ%6r_Y+shr?M_VpighJo_fWa24Lc&0T5Tsy$Ld@c!1h<9 zicmK4Q^tgB?abNdvQ_ihnU~Ebwf_+g?2e)gsHfXTFCOc1Q{r}MWUq*Hl_-qdzu+D` zg!`bI!UNo8xW2e~ai8EmhEcKnr(3{6T%qkRZG&k$OvA2r#l67^ULYF{r5ZIgN@lP$ zJG|}Q!A?6L8m4v2nGW`@h%{}v<$~B8{HF{A<9>lr5N-hE1TFk~qxA&s$K?e@8ppZ9 zXv|k+&u7Zc&@lXlfVT06;ts&=5B)%o4D_ggM+WBE1gD>OZ%%rdTnWxRd?PC=!CAty zxoMr?4D$O3j|Na5J~V?8oH=4^b66d!!8`CayajJU6?g-*TU7}vf)G;RG0_j90Q~*1IQXK0;04lNk<(9UNqj1ZB zZL8f(?P5lNmgr#+3fkQ)3xfzR8#_Kbo?_Z!O+86X$WHJ@w2BBL7F+FJ{nfN643z$d2Us64=`FnS4?E z)XJ=MWp;pdUXx6!1ynP37+3AurF&Ub+lFxj>Oo*T(wEWupw+ z$1l3EcBIdH)Fr^b)r#E=vDgiUL0}IfwrfohU1QxduE0^)jDgV*51&DTuE+@-jE8ZS ztMh4KU@CkLQ=lr5e1SU$X2RE$YzFQuSkCcmT-m${Uvazurl8Nq{Ssz!tbuef#|vQ* ze5ETgk%J|04$i_En2KRnBGTBgiSq=`=i#n|ji3m1Ye>dTg7q+o^KWohgC3x)fTge; zmVv@*;C=pYsjARUXf4OuzSa3UTxDW|b*_>8H;%spC;nS;x4>rj7Bb_%4R^bBzJ&9A z9Pfohj(6hjfFIy{=!CWhH+C2Q?FQZ8e#G4m$Ke2+grDIU{A3;ff-67ihu|O_h9htk z6y`K24jumrC*TxxB#lXAz76g(&Rgipy}-c}xCb{tMwfBh;9kVV$W?8ZIQ|_{;BB;4 z@CK3n!TA*k<@g%zRk#jSIKPW~3vR++puTel-oo#;>zwxglLNI+UQi-3lILT11S3gE zC4LAG;6B*3A^j=np@#~g0_Y)#3ZRD~Z3wGEXho%hsIY2(JuH#tjOD*}96#SF8lY*9 z?>xrkadW~ukRS9^B`@R#e^9Bl^{*!_FY111=|E3lGJxXA1?s#CI{`N~D+hXdqTLle zNzoG&wWpq@yao!SL;`TLLpI1^xq-Oq4?(!WAlp2k%goN460wh!LHk%4rf{*YK;<|I zg(6TG3VKrxQBb}o%u2K2RAvL860k2ZA2m^oJPu1oS{Fh#KgP+Y@>~H|PQ#pe;0kHqZ*x z0b9xiJ!)zUu{?Nkbv_w3g=Qen*3gmwtw7JB+CgW~xUJ_=9ib(OM_ZbnOX-=Eo<*sN zl!$CU#w~^07dH@Bg;HjfseWqzK^)kGs(`vtsq?5qO~RcBA0`Oee5zGCEHHb({$> z-g0N+&cNQzpfaYbWSaa5Hw9N2{2V6h7+d)Z`O7uvQ`OG8bf&`$m<6-pE_?}JfNEzR z?p#prRT}kZyQco)_#)Vu(a>yXNQwQ9-&yz>j>1X!6@Gx&1^jmcRHeH>O`x3b1V7je z^Ff(Vq_UU465j;c4o<>V;?FmcCMN6AGJ)dOoI!DKgbgr|bK=kFv5u3qum%>IRkN6r z_9fFRI9(3QU@3eJOJFf1!Xo$zl%|^c|DyZPIqAPetU{_HQ~`Ejb#5OgbF50!xhhj- z-3nVk`gfqYPAKu{&a7@`)F;2?U^{FB-KKZoDu9~od&mY#NEeD~UViFRN<>{l{r7o) zT|l;t-9L|Fr}%z>gP>OW35KXo?uUJ#ZlDDBfG!MOS-U~qp%uAS#L~rH2m*D9A8{4t z0O$%;hSmQLf%?1b4#N>pf3-8K30JILBIWc12FlrSI0i~s#=iJX!C0lTt6RDqR<)r7 zRXP>It`SwgYAr9w_6#TvrKKAAO=FTexe~Q6hSMCMf_&f$_Qj!^X-Yz>1x26>LXpW% znb`st;rUEGU;Vlg)dc6kPA{L@-%j8h9sxw`gZmNKCB4A0T_Tkx59FoVmCy~)py?oE z&tH+((9eQOsdz4fYFAgNuILoF1U_niC8nxYZk0>rPMNw2Dw#^E()|I?mrk~-JwuTpKm6+Kz6(;Ozd_3dsPBi@q00mmnEQx>~T4tRURgSh^ANEwuJ*^Y-=@7!?I0fnA9QWrY1jB0SPa`> zA8Y`7zfJpV+Tzr?;?t&|;dOLw3;Epjybru{wA>=K&lm4hE`N*F;xFIS^zR2s+mn zBJBtinW|0a8S$5$BGaX(45;3rrZ#wN9anW*ooPLKhIIVfCwv?} zS@GF1Vb({_GG+S;pE4n#;UQ&RPsd)vXM5XB37adGpMy`hd_u#u$Lxnsr+&M)JY4(d zEJ%i)zCuQGjG_gLPib)Hl&ZE`Enkr~H!-#dHb3_j&UBFcr7@i=O-EOK@X*Zyxh z3@+zx)ih(Kyp=F08xk54=6>v?NM{euy?)@8!5Q(PSY-(M%q&~v40QN7%&tYwFh^F0 zdA!IO5EMkCW*|VPjP3R}t$as?qC_EKp&ms{=|pE>cv%b-3(qf@f z*$Uch@<(x3S~fps1ue(Izzj-smgOg?R>}Fr3|Z{-=NAmwM~ybyzjx;F3iIe=>Md~w z@{1XD7URU4TVLb2ECczC=$VTN=Q8mRbfu-v&Sx&-QWD2xI&vgUPlsm)r+K{C`TBpv z_>ZU@1-#ANCC&hMl!5&G$InZg9j%zndtW=f=@JdTwlkT{TXpD8H*J{8m@Tc@@^xx> zEAm1n{Zcy&H?dH&Y`Zfs_)c2aCn@5-c{_KJ#6z(sTy?Li=R-Ya{8C~mW)>}VmZ((S zhpU^yWTgUCr~v^L9!8I<-@)Ir2|kPwalLTWDmk+i$}*(Dhx<}}2ANFDoPn>6#vn5W z@f*K76!7W6k{Fl@c=*~egqr4@@{1s!E+ePo&DYDECDQez(-b9C*7WAgGV6sb8Sd00re z%Ic2OTXDJ@KCi0^rV~IHT+JIk4Q5=;xys?0fTGebGEWradQJm4&9|@c=4(6B2fH%B zCB*&1gsyOw4SJJHA{z$R+o!ACZbH@a7?dT+aF!1yc7@%0a(I>Tm~OryfagPVX@zrU z&|JbPodU_bG7eqz_@OIYm?GX}X0IgWom}oJ%O~X*d*@DDzhA1sPv#&7`ni4CUBHe^ z#`zuf>so%#sruNJcV7uNO`cWGz=$UpsEqS(M|D}+rqm6WSxmf@2RpGK92woAy`Kw}Yo zTtS~Po~Vkpb=@*xczn&zGJB59;vNMnn4h|OXE)teJ9F`SX`ij8S_hh~tI3Z$Tjus^ zXStw>mgjjA3@b=Fe8cCy9r;O^a!_wVt_tuT%^A69j zkg`##(GSeoHKf(TJdzV`vaNO23Az>RZsUZz3+HagA3zPL&|wH!$-H0 zOm9{DHB+T)k+x4b*XgR_-WrKxcrT83AV1olFNp*un+kFgO@k!oJNz)(%p_-ppw|ky z+jnNR^;dF^*wlqs=+?UQikn+9pJdXLt)OsfS$*$8miAqqmfJraJMO3Sli6YKwY?UVOPn&r0GuTRn-$3M)kDbNaMNea(I<{q0)2Y zD(g|JI5Rn_ti|!0A$8~G9Q{I7=+enD+|@iP3BPJswWxQXX}8Il(^0U5iQB}`VgKAy zk7++;8XRBS5JkC=FijVtOw}M)8^3Gvz2;3nDd`?#N0qr$JYf8sPq7RO;cgz~(FY%m zZDl95?Z18Y+(8b{4k+q5u_kCURXEu?T_3RX( zOjpXR-0Z9$RJOExNLkeW+QheyKWt14%ri7PzG?Do;qoqJ=53*fk!GWuYUYY2Ms1sOPMs`!wV- z8Pm*yw|X#V@chn{kTcqxl{3W*`3~nxQ*Q@Vz9Q0HVL6BUH!a+MS&+k%0)>^~s&-8{ zO89QUKz-+Bp&dD+Oqp+;0pUfXSRP>1;ar7mHG5nNOO2%>KDy(67ngDVp2S~=rTWx2 zgT5sL-7v_F!3SPXvaMTpx?ifnzoi)T>Uduk%r5jl%Kp*{`Jaom^*IBz=s%{xbad93 zefqf80_Wb}GPp`9uaDdQ;SU2KMce(b9Fs&mTAJ)vzMjfHOO zZ$H`)y!k=#bE#qD@KOKn6J0uZQ@(;9r~1smM}6jQy=K)4HA>ej)#pFwv`N_JGH)z% zX7hC&63m)1vYL5WQ(4*ba81Lr^DBNdO|X0MkUcl^m@bvv6?`sDg*lFzgBK}rnvj-r z$D76#ulx9Q*Kt5)cZ+tvbF+TNQkAz5LUST6tpDsNcIs9hBNgvUQ*_O#{%0lm-&oam z<+#Ng?xsF4vr*n6XM&5k%IKP8zB)cXhnp?OV6)TPnKGglx@QCvTWhKqdNbmGj@4E03z}ZdLaXm$J8Qm7_Nj zv(9EXT#LhwZ@KGf?1v2(Oj|L1tE)5& zbM`vly$j&#k2x4ovg~rcmcMeP(1;MG0RNc{+s7mm{p1VNZ z?ONz<_cG=1g?vAa-du+L5WDqXeJl9SHu^tlqO@u~+Q?N?K6VVMk8EjNJ^nu~?XIp% zJC+=)8*Ez{_h#<;@3^Ky49=_~##v=4U1_Yd;DcY)LP~+r_2pfM1%<~eyN)Ycv39mz zamVEXKS!dhhvPn)`%N}qEOVxheRUG)s<|VoF?y!ox$i2Tv?3z$ zS0@ob7}vTp^3?U5YqF(tWlNKM50dU0-G}}9xQCAl^l4Dd;YprCw1N6R9@F#L753tO zWoGp&mE9aX=nRkO%Qm~_&=aOt?{qt8Nog`cS5PJf;iCmaK<+o2<{wgQt*c0`#r^2& zrs5%H%~P>pgCs5_cd-deA0Nw=T7ZSsO;0QwYpa_vhnyW8Cu^9zWxf5=XfV52!({lG z&^KzhFXILc_tk5Eb#M(rmnUT|zlmCSS!C|spszB9!Q&9fI37cBfpLy@M8eTi~Z26h(%UvD`S%(*LF*%D52YD+ww|k~u2EvM1;uKB{^*imu6v zxVn0G=InX&ugZaMr-u0xA6*L_U$0#EaG%E-6Lej9Q>R`n&AyZ5{I!OCKI{x4+Nf<5)0ZRLA_er8$6w!<|U*X$&=^8uq?#{+KzRe(m^sreYZe z|J2G|WxhQset)IjjE%09C6kace@8W=waI;&D66zFk*B$)Dwr;(dFb%!8a>&@%q2j? zm63;yWnoP|eAWFwc_t)L2CU91!w5vvr?~|KZFy8eXF>H z%?o;Ox%-1wch<1}lKX6KZB3@{vS4?^6qyLw(T;9s^ ztLFxxJR8>%{=K!HLk3ogNTddsS(#S5o!NctvY1xOojGz-sF&_V(h1AE=MmYusfGSe zrc|#kZr5n{ms~bES^iu<@bfMGs zlkxGz=fcYB)4th0T!VvF{P@hmNBe;nu5QS=E$@?q_>^JQ!M)%W^Cj1GY5QpJz`!(J z+}HKi*lCZ?R&COfpc*uo1bIez=XhPS#P=}CLhL8jby=39-{7xObJPkS4SuKBeVwW8 z2Mg!oqis$u0Q;`kwTnr(#D&?fb+@isu9SP2VROSNt6E@5-jz;XbPa}I=WF!k!x7I4 zx_n&aE!EYWCahy)SM&H&Z>9sUoW>sQW-^@N5`O7cSb5E^FLX0iurPBDGIsatZVnu9 zX6NadwRmEqv5ZH#9`3@VPdYR-yhnnbxmmNWI5X}HTZCgU(BM4yldsFxtn*-DYEGw_ z?HG72HowZQRWEmImfnbzn2-feaS^)@TdQI$7)yKk=1$rTgJrRny&)062{WJp*U z4+j(DtYq-g)V{apy>WMAs*isk^OUebg)NJS+WXeco3y5Xszsy;Jx|u&HSgjCwZQH* zVv2Vz?bI^M>oKWzy-X|y;lnXdFWr^)eN!!^+qbC((=4BWhYv$P*b~t{)n_R$i6ZW8 zmcg&XI#dgtdSZL3!C~Whfjp#`Ae`XGmfhqER||9=HzPjPE^}Y={sqS0f_>cs=$xQ3 z8-Bjrwn?f*6h0b2Kd5}5L~t%XNAPzYy=P_9n_j>3 zK;fzR^LJ+*N2@O8%}d;>{(1d{1rLs87C_b-4~xnD#-nAW9G;AU>XIH`#+s5TTsyn5 z2*Kjfmf_tS_@87^V_V#dHLb9SC=}<8jmV?m*T z!?NgcFgE}VM}zUvK=u2gRqF@kTN8*+g!@iCW`wDGg+a!QFrBVAi>F(NWiXcBBTYg^ z?*K=Zk!IZ$=a0evImF)N^Isaco{The|KNF=yXo@rFshtK+EMONbywvyeJ8H!+J^Ml zhf;kH9$~Iy?Xco!TP5FB9&%@I2`>W+^F ziW;YL=84Q!c6n;pxKSo9l-MU(7S#rO%{qCY1^Z%l>XG~L(Z$y^XWh@%Exn-Kx-dN%>?%nx5<#*h3r4pvw@%y9A8CmWa zZEoJi-9OsIJ;6OX+LZC4d!&puJ=1t+cSiiZva!|?_6o;*eZ!f{UcLnXIojQ4N_>#~ z#ruW(*CZk97Va^|JiS42vX5~$+RF4Ny2XrGr>!Gvq$z@rGU=E7ev_MH&kRZpYcH1i zj4^X=k+~sbOx#W4nnZ}qgeZK!cYMt>jos5o*IN8beEjjb?ANwH@8hi=yW(<j{ms_HF0 z_|viOy!U?k^}{3Q#ujpgbUj=BY^>>yWyHNE?(QA%#enJK66Q@}oiCQ8nIAdBf?wTIb3$Ky6uNzF&pc(V2q|0yD z+I!9A!yv)uj}uIYuXpy`;T}I@lMb8XIZQ~_xDFRmZS4IJ_r;UlSa+jYVf!27iN|zaH_bKw=$$T(e%V3B5?)(FK%YY(Ye#1hjmhOc6Oo}Pgut*y0E$RkP+Ov>K)c@ z)!z-9cCwlCl)(0l;k(IZsT$ngu=;VbIm3BG_~-5_yV82Occs2x{gRq|Wqh)bvGnIE zTzPl$L_e30YZ3L{=O*MaVPD-PT3WHrot`ctPx9CsR;;1igspMh&WF`>%BMZPS4r!g z(>x^sTQp^!usZt3ewE2p}yc9?bVx>wXWLWAmeWPU2kvwY5j!CbyF+SE;J*+re~Db zE=@mUZgL(mhLDvLNy;&YKAvp#+G+UYz$au{zG7FZ<_}5rSz)GB_6~FWoG_&~ zj=Pz&X*+I*nX-*5-`%USPr2zG5fMDieZ9`z(=qe44Nfhxt($sb%jaqH2@U@^R84a< z`Dhkp%{1&AFtuY#?&4(2!!>(&y1UGs{%AL0=sOoRrYbzyu*WjHtj~1-*9^w46U#q1 z`%HHoOz~XiRp?yf6jw=IG15_bFSX77w)$I*jBeLd~<@U+@6eTyWP4U z{L3i+Tm}4Nu4^Z54=MJY#cp@IM?KeL?JNJqD4#R2s?99-C7*Uwc6pz(`};?lI6+fPZ?Wj@2*f?ukz79OlIqwe6qFmHR&Ln&#Mfw{QKc z=9||ucz3WqET|9EZDK~i3!wF3ICDJ%#pSc&ktxrXoOqspCgJP_0naV93n-1Ub z`OU#L4}&Lji4mrBX6kFjQg?wzE;H>id$&k8W10KTb7Ps=mznFwd->EX-T@IAm%B&N zshQ)dmTkWL9iB*N|CBAYZusc2$M9!s=R69?);+a8W<{GSJ@^pyzkObK2)TFMU14UC zNYEQA-BIQHwRDRjE%IF=Dm^WrdECVefBBZQJ_C7xpqkZ;tXcWp`FG-<@Zk|w@|rWb zKQU_}vU+FzyRa{`lw;B;Gcv0R>)z7vbbV4b8&90WJ*>}GJGQJcXY$j{+@GCw99v~7 zzNYp0YQ_uFtsE8K>fOt{D_-e_>63mnSDT(##7@PcG8X5O2W(etl(ceZ@I$;zs4Oa^~4dkm8z1g;wT>Fm!B&B*4Cv8ud|H$p5f<9YgPAX@)*YbTX!oG8^d)U}h8Fbm%)wtGV&PMFrvC#HhY<&8& z!&#NZ2FGGi3X7?pgZzIVyYsmkS-Q@gQS5uLD1^n7#GG@J^X4y+ zn*I%Zl;@iJ>(y)aXO<6AeO_B{Lb4OK?0R?l_v$qd82qb`K2z!H0^uGV@d+dBz4x2X zzEXeK_o-p0uQvk;8@ve%)pxz)t+$om7yew%F03~z6?=vxcc)qLv~Tv0vP5S{jiWR^ zDtEi!!CezqH+(DAr)`pXs<0!lC@YJ1ayH$0BDiC!MG`*6@ENx^W70R?r=IHxXOm3r z9ONv0vb)@mJxVQkaJBla)Uc(KO`I&6W1%?Sdk}Sf{_*@VZVO#+Be5vRO)D|k{D@`5 zPgtrRjwD{%yncT||J1lVH@M^Y`TJOpm@U~ZrTP@#V1ffkr4AOVp_N}Gf9SD#^x{;D zk2je2v51(7MM*4fY~FXiTcg!yO=jOC|ap8Eq^-Mcr|XzwuFrsihQci%%C zuWvW4g6W%$wwwOJ-eHy;ykNU~?efXvuA$GC^_W66Sx;h@Z#U;K4Bm@{?vX$K5LWqz zU*CMLL5^%UWpdGE_ps2=T)pz{osQkB^t}ndgaF$hxb@xgwkJ{J1r@dUYI)QEUzdCg!?J`~SxGK)|%)%Q{13yp8z{Ro)T87+bD)H`KVLiyWd`6Xt<`$L`}Vo7`6G2(Yz^GsT@P!m zG57vHGd>@+lzYErQ!Mlj{BQ84m-rYeWrzG2iDhf{`n;;cj@gS zI9`%9dvamr)NU<1{eQ|Yw1k~oOQw=T3#L|>{oOE!J+9Vt-B0yo_k~!kJinm+Z%$v) zWTj1>!hB`P9h3DPHM=t0->q_g!|UZ4_($l!gS}k+-(=R#kJXTNmAi+n>|THO8r$Q4 z)D|x`%_}SWpE-R+#l6bNbxFCtu=nD1VKu(>^*Fn>>>l#>_+^dFFXqQe1o1rR-`5>nm@3BT?T_{O4B{ zb9j|?e`hg=Gc~vWjM}aTD{H}Kn|nl!-(0EZ$>{0TTmt}~4~S4{Z+2wV(6KeCh&Za7h<4cU0=&|$7`0C@y;2s>!N!} zoH^l(gA3MNYELn&XE+D((PE+ZiZx!IQ~8-XEn;08RWB}lUN{f_ua7;$U%jY(^<%~o zW`C%6*`VVo?gv^wuE<|udi_<~$yPbO&B5}nmkA2#F$zkaEAB^mkB`=J zyi@ z6(uh1kfOT3)#s>m-Bd2;UE9&^h8bIq0E2G0pFM6ZIrBt?1_9cb)YB;@-KEUda^7Vf z<8GKTlk~CAaPB+quR59v;of;1)oz+*;bdygO?M@YN?UABo%yS^0#K4s{5;wXlYoVz z*sb+T!o3}yj*mx}lV6vX%KycjRA|JyQ3Jg%7ma({&NXD)F|d8|fYAn19TM z-!ZwPsHMkuOk@;|J^Zej8$}GS*svf5@8#w?7LJY|nEbD+E$^A0uT!n%?z>C8@c-%T z$^)vdvOn+X_mK&L3JCH*1jDqRZ2Cmp&`^<(a0?Vvwg)_Y@Q?>CM2fqXDCTlZP0iGq z97{8kTr(Y)NprMCOC84=ZCV^NTQ!&8=X~$|@&Li#H2TN)eZTjdbI*3qJ$L1oDLKPi z92F}RYKvQJ5H2=s!Pz$hQxhHqH@sO5iCy2{=s=9p`O*2nbp!idf1{f*sD1D)VWNX= zA2aM7mvI>wY$DW-39{Ip?D}wJ*6$q8benCqZjCA-Z;W&q23${+__b_WXm@S8?M1>)ha4+Da~2szj+c(-H_3i|>j>@_)~4j)?Uu^w)H5?{RG z?iJtT2QLYZ{PbaOc-}1Z$1T% z&%4qZxTUcHm*$4*bUvQHhozGMOkLuXeDfh(D#se1(bM&_J?3>udL73NjO}qxY-6_g zuo<0BluE<0yz}ZBBs$l~v|8ZaTHO-*Zn5+&2Hpn@|Y%73h%KqlBm8xBvY6 z6t_jsaKqwrI#58k8(kj=6|DpWxBA~U?f14sJ~DIyJ7m_UZA*f86mApN8Tc ze6Z4dcZ!V%7w6n*bUfSy9coc#E$&3#gGCP9c*zF*$HtLvn{qmFT<10eT}*00o`Yc~ zadd`L^N6TfEhuiV68Vtu(m;fe$6K(4n%)?!L}-dJr+JF@LEVO2J|69^b}8cILmo;v zEbpZqmf(H1BEGcRIU1{WZsV$@q;Tl(bs814<&>(fSwQu*K z;v}@NXMJfiKQ%tlUH`=I>-;GF8BpldR#>pTefjeI7RUdNI^cZV*J==@fMEAJ=Y8>H zV$uEK5(4Hs(3Yw|!~6jtxQ8vjVx3ym{#Bm1X=OH zQG!0b<8I+r!l((efQo{l~XTuh@gZtq|!0)#mp)YYOG6+non;4%dz z9G%O@G~G7E@m#f}3TK}eOs7)8*$P0gBSf~@8d?@nJ`WHw^VM!w+6;)6fS4FFd{s=~ z*8Q@6@II05rXaVd4yHvTLF#V+^akMEfd`+P7iHrNN+uJRg6YsmB{HCKcJ77fsO7Ut z8{^OpLfTvI!S8s-uD_wz4Uk`CHTq+Z(b#9AhepO^`Ay-bJ0{!ck>!C>f%qXSn%W;VAZoGN*;w2 zNb3W&-bO6PdSh}Fa~phhmMh%A8Bk>))rC@o1yQjp6^zC`I!|>GCUSr5y?FF21^n9^1ZFb*J{1Z+eA0#aV`g^<3jnPoiu`X1V4qJW>irk+x`KJ4j zjV|9zm8x-0%j<7+q0}^FfMaM=8gzt1F6%Rp2fxn ztE1_f14j)St&hIioJ(V=3v{`65QQ10o6+% zlg{soMT-YpuUzI*L&mBeD{Mg1a!1*))tN*u8fQ@yy_8e`ryf*cLH53@htP<(=UaQr z78kAr`#ctcS=F27yhNQ+4dx?&W;JZM^~vtF7k1`4g*}H7o{{N&^pVGhKXU9Hl0 zVD*KA!zW%8q?pr}dQwmxX1NXlf_E2u`}nZ;*H8U%krU!;l<<<>Y0FRRU;6gPJ5B~Y zs31@AGspB2sQ>Kt(~Vm#JACg1$UsRLPg#A^|(^0#EyShMfK`cx7!G= z3rppl73hmo#aNNwJupKeOG^^2X(a}2+CqwWyA8cm>%}U z)B~=$^fNayRmR=EoJ2b?%z9XV@8c@ik3%L(WEl2uHBf}FNhy&5mE}nv0751|fi$!L z9{9vSvK2TP&}*^k{XulS0DQ~A6$KP3-L;mlaa+?FNNH$ap^{$%B)45X0Ic;Gvg^@n zaa5~$eLO8JMa^%-lV_1LO74jliAIZ?>lUV&@;Hr?Q)@DMn2!U(6P|hDz|*f?S(Kly zYD1k<{tP9Y;N8h`x!wPMn`J0L$HIEjLaHY2H}Q0tE7j4qiAX0JOcK;|KhaG<`27Nhwa}iTOoK3#ps^`z+ z5??wYl*0Pjl1N7MPkPx`Qj$YSsxhnP$eJ1Jc4qpBArw>s&SHlMm4EW-hOG;GKHeA9 zc~t>j1?)Yd1bLxG$k|}j_M>GmTCq$l9?}tO4kK+z2TGOv|6)|MIf>FI)oPiVK++$L z+mb}q;gjh0{mui=eaMy(xscXFik?jCy|f%^AMn@>TYnndW#e0`4><8oCQ-&@)F@|v zjE&F!Xl|*63C%s_0c+`7Y8n?l1wltsmZU5??d?<0X*Z(IntZ2zE0o!c76<$Tl7$v# zdZeth4pHqWwNO`jO{n@wim@{YaDS1uZSU?=dq3l$nJ5AMqC!T|B5AkxnGU? z&Q=s$%#O>My(KcY_t|IS2i2dlbZ46Xzqd5CC639#z%QtGm^2d;hy!kIm!sV zTy4;cJGOjqGvXgzwD8qvXp70EDHJ#l*?z-Y4SBcTgLe^Eq=<-6nL;+;^78H6dFpmN zo)l=09n|42`KbbC^AgYZXS$S^!(TAAM-Pmh;&h#BoCye?Q>wUkpiTIuxjuSbsl*{X zIpsg`cDsbW;|KGoUv9nJpGv*vW6Aa^Ab4Z1bMJ8_9b(_M-}fzJ~_7$8Tdktfc77~7?bSY7hbo?}M0(6)f!Sc54#d0tgLi>00q@@|K( z7Ql0CYI$QtWmc^2J(VLhkJFBGAd4tTr&9}|bnRFNKE0rxH^Dkt6?wggNvsOc;RI)f z&b;uk{t03fsm_CI=V5TtviwDG*vLss$k6cx+RhNCmWs`;-ixNRzxVlv9C>*L2DPe( z$kanDI5l+-u=1!+ofAvi(HHHA7f#t!fO~U;XRB3F2aFc0!LDnToD7-u)dpE1QdS{( zqJCc$87pDP;3bq?iNG_Ftd&Y0W~RzVJ2rNTwf;iMMAe?8aES^B|@k9b2t6haI9x92$8w+PY>ze{HU z*=^1^;Ro$r(O>S`YUjTJiIE5o+TAlm25>g|Df{e%1r=BiK=kJ_D7^|`nmkCYtMG1YWW5P<2ijCunkQYVf&t_Ll2(ziD`pnif8$o~*ct+t4IEcrLiyu1NkL%vN4k%|M|_P z)4ILPZlZdLOCyWbaK|MU3S0(7zhV(1pq;~Bdh=_0F|RuC)kJWQ*DW+`8Kjnw`g;~y z4-E4oxgw)_y~pyRVSYE)HPvC^TAdy;qQn=f|6y>_m@RI7XE{r{=F)Y>eOf}SedCht zcE-p}PKa!j@SNF5w{PZHMwJb6mXzmGujSzMWk7Hj-SL|fAI@q$_mV{R+yrSw7zJ#um!3fnrDr)Z;lC&n%B$ML@eS^0|#Ee+lwyi+5i1nbBrs zi~C+(FNNaW6YocQj2qr}Qp~yH&Z5_t`r)=aGpGE!TRGl26g*dOHtup>Wb^uqRh6CT zJn9+r1>l&@@fUX7Ih;In^AD2Fze;9WJ#z+M_#N-9QNC$H+Kah^`WZ8p2x&&RxT>0W!a~MiHFINGaTRS-%?;L%&P@7 zJv+0&Vl!oDIxMxm78Toz943doxTMy{97}Fysjb9RT4=5Pd6K0t$6jnIDz@ZWr&x+> zArzO|ET&1Bwo;2Jx3n;uwK$fupDy7+<>f(RRUzrU4N6A}zoImam2xzI1=T#9tcmYI zr}wui!R-Jj!R6iPtVgTE1Px^s+b7e(MTS7~_+06)RvIlUttUj?3hNb$%7%QVJW2CD zSA3fwTG5PMhW0AKNJ+4^vg%T+UE<_hMeZVzo$9ZP>ik|0F-#&ljae7b`CUZ}ryJ*$ zxt$vD44~EX74}Ao$TWm_Gq~!308*bdMQyl9byF0nPZM(0F1WdRvx3#-SCrN`%y{N| z!(+`IQvku&Qkx>_#!)3i6+2XNFB}#CwTvyk)e~1k5H4RAL3|SkU+hsrytNj~%>|(R zFon~ZPnD2fby_CMv_@LL1v;jpB^AUL*^7$U!Naoc#psMaRebza3jAuyu}?0v*)ww- zrjp{!>)kX8+CCQBir3iUf^FeVDD zTAwY9T>HH?4Nc+Mnc4Z4nrP)vW1+Q7rTFXvpH+$y#9~4cjQ<<}HDU$$VJ&l#;~-?S zIGoXtJ(AA6ss#9HD0O`mOGuRIWe9FpQ!FV!6pfgPqX;{VzXl|$1&sU!*YP}I2#Kp< zOqCMl>eIygUwMkXHtUXji>0InezGNVf=LilRne05Xw{-W0##Q!^DiZ&LqiCxq+0kE z+*PAI=2HWyRs<0BNi8oKLOXK9tlJx*yzU3h$wI1&zEai%P1i&h_GNOy&_c9`I-+G| zW})*C&9{aP$iRV$BfmAL=4+|Lf*1@h;BLTV$<4)<7Sm*FNxmsJ(`L&;lX391s^P9( z!cE252&ob7h5(=1eJ@xMf4LxH`6buT;ToU+1z}+R7f_}MRr7f@EZ3F}Bx=8^hUP!@ z21D2RUXYnxZ0B@1v&dp{loX@4H5FU(EK`bdksg_f?e-Ffy|g&nVj_D7Lpw^2H}D?> z)4gqI-?|0@mC4`a(aF$>cD-)sOu@c}4)phZ%H!m50>A932KNY2TYcWdR}=5MR6Q}< z?kHfJ=UVgV%qxmNZS*m;ZHu)&>8K)d7iAX1MB^RyLOSMS2>0NtKtY)wXpa%p?=)ih zuRh@U315RhRh>4tR_|R9u7)so zq1EEj!V+tNg?hRghEd`#;2m-sDDo@tvgU%4MlW7f`czlC8ZPU|eZRq#w*6CysV-<{ zxZ1pWjJILDj(pk}Ff(vnX+}lgEAG`__!>^RR__inoXTm2s$n5ZW7v}cRK zzk28EhA}NXm@8W*at5*Ys=DR7h97j){Jb)af_594RvY#hBAYa0rA{*0tR-qoroUXq c^k%_+gBM-AtmIX%*>8B-y*lcIVL|Wz1Inmb9{>OV delta 97316 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 + - , + , ); // Install router -> store sync diff --git a/src/theme.js b/src/theme.js index d88b60be..3024942e 100644 --- a/src/theme.js +++ b/src/theme.js @@ -1,117 +1,137 @@ -import { createMuiTheme } from '@material-ui/core/styles'; +import { createTheme } from '@mui/material/styles'; import Colors from './colors'; import { ChevronIcon } from './icons'; -const theme = createMuiTheme({ +const theme = createTheme({ typography: { fontFamily: "'Inter', sans-serif", }, - overrides: { + components: { MuiButton: { - root: { - textTransform: 'none', + styleOverrides: { + root: { + textTransform: 'none', + }, }, }, MuiPaper: { - root: { - backgroundColor: '#30373B', + styleOverrides: { + root: { + backgroundColor: '#30373B', + }, }, }, MuiDrawer: { - paper: { - overflowY: null, - }, - paperAnchorDockedLeft: { - borderRight: 'none', + styleOverrides: { + paper: { + overflowY: null, + }, + paperAnchorDockedLeft: { + borderRight: 'none', + }, }, }, MuiSelect: { - select: { - padding: '12px', - paddingRight: '48px', - margin: '0px', - '&>div': { - margin: '0', + defaultProps: { + disableUnderline: true, + IconComponent: ChevronIcon, + }, + styleOverrides: { + select: { + padding: '12px', + paddingRight: '48px', + margin: '0px', + '&>div': { + margin: '0', + }, + '&:focus': { + background: 'inherit', + }, }, - '&:focus': { - background: 'inherit', + selectMenu: { + paddingRight: 54, + }, + icon: { + marginRight: 20, + color: Colors.white30, }, - }, - selectMenu: { - paddingRight: 54, - }, - icon: { - marginRight: 20, - color: Colors.white30, }, }, MuiInput: { - root: { - position: 'relative', - border: `1px solid ${Colors.grey800}`, - borderRadius: 20, - overflow: 'hidden', + defaultProps: { + disableUnderline: true, }, - input: { - padding: '12px 16px', - '&::placeholder': { - opacity: 1, - color: Colors.white30, + styleOverrides: { + root: { + position: 'relative', + border: `1px solid ${Colors.grey800}`, + borderRadius: 20, + overflow: 'hidden', }, - '&:focus': { - outline: 'none', - boxShadow: 'none', + input: { + padding: '12px 16px', + '&::placeholder': { + opacity: 1, + color: Colors.white30, + }, + '&:focus': { + outline: 'none', + boxShadow: 'none', + }, }, }, }, MuiInputLabel: { - shrink: { - transform: 'translate(0, -2px) scale(0.75)', + styleOverrides: { + shrink: { + transform: 'translate(0, -2px) scale(0.75)', + }, }, }, MuiFormLabel: { - root: { - marginLeft: 16, - marginTop: 4, + styleOverrides: { + root: { + marginLeft: 16, + marginTop: 4, + }, }, }, MuiFormHelperText: { - root: { - marginLeft: 8, - marginTop: 4, + styleOverrides: { + root: { + marginLeft: 8, + marginTop: 4, + }, }, }, MuiTab: { - root: { - minHeight: 40, + styleOverrides: { + root: { + minHeight: 40, + }, }, }, MuiListItem: { - root: { - '&:focus': { - outline: 'none', - boxShadow: 'none', + styleOverrides: { + root: { + '&:focus': { + outline: 'none', + boxShadow: 'none', + }, }, }, }, MuiSnackbarContent: { - root: { - backgroundColor: Colors.grey700, - color: Colors.white, + styleOverrides: { + root: { + backgroundColor: Colors.grey700, + color: Colors.white, + }, }, }, }, - props: { - MuiSelect: { - disableUnderline: true, - IconComponent: ChevronIcon, - }, - MuiInput: { - disableUnderline: true, - }, - }, palette: { - type: 'dark', + mode: 'dark', placeholder: Colors.white30, background: { default: Colors.grey999, From 17104a72c6c55cf1c2812570bfe86426f953087f Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 2 Nov 2025 20:11:24 -0800 Subject: [PATCH 20/26] looking good --- src/components/Dashboard/AddDevice.jsx | 4 ++-- src/components/Dashboard/DeviceList.jsx | 6 +++--- src/components/Dashboard/DeviceSettingsModal.jsx | 13 +++++++------ src/components/DeviceInfo/index.jsx | 6 +++--- src/components/Files/UploadQueue.jsx | 11 ++++++----- src/components/Prime/PrimeManage.jsx | 4 ++-- src/components/TimeDisplay/index.jsx | 14 +++++++------- src/components/TimeSelect/index.jsx | 4 ++-- src/components/explorer.jsx | 4 ++-- src/components/utils/InfoTooltip.jsx | 2 +- 10 files changed, 35 insertions(+), 33 deletions(-) diff --git a/src/components/Dashboard/AddDevice.jsx b/src/components/Dashboard/AddDevice.jsx index 55050b90..31873ebc 100644 --- a/src/components/Dashboard/AddDevice.jsx +++ b/src/components/Dashboard/AddDevice.jsx @@ -41,8 +41,8 @@ const styles = (theme) => ({ }, modal: { position: 'absolute', - padding: theme.spacing.unit * 2, - width: theme.spacing.unit * 50, + padding: theme.spacing(2), + width: theme.spacing(50), maxWidth: '90%', left: '50%', top: '50%', diff --git a/src/components/Dashboard/DeviceList.jsx b/src/components/Dashboard/DeviceList.jsx index a4cf7c61..0f892cc4 100644 --- a/src/components/Dashboard/DeviceList.jsx +++ b/src/components/Dashboard/DeviceList.jsx @@ -70,13 +70,13 @@ const styles = (theme) => ({ }, }, nameField: { - marginRight: theme.spacing.unit, + marginRight: theme.spacing(1), }, saveButton: { - marginRight: theme.spacing.unit, + marginRight: theme.spacing(1), }, textField: { - marginBottom: theme.spacing.unit, + marginBottom: theme.spacing(1), }, addDeviceContainer: { '&:hover': { backgroundColor: 'rgba(0, 0, 0, 0.25)' }, diff --git a/src/components/Dashboard/DeviceSettingsModal.jsx b/src/components/Dashboard/DeviceSettingsModal.jsx index ba2ac97a..20ea5cf6 100644 --- a/src/components/Dashboard/DeviceSettingsModal.jsx +++ b/src/components/Dashboard/DeviceSettingsModal.jsx @@ -17,8 +17,8 @@ import UploadQueue from '../Files/UploadQueue'; const styles = (theme) => ({ modal: { position: 'absolute', - padding: theme.spacing.unit * 2, - width: theme.spacing.unit * 50, + padding: theme.spacing(2), + width: theme.spacing(50), maxWidth: '90%', left: '50%', top: '40%', @@ -26,7 +26,7 @@ const styles = (theme) => ({ outline: 'none', }, modalUnpair: { - width: theme.spacing.unit * 45, + width: theme.spacing(45), maxWidth: '80%', }, titleContainer: { @@ -37,10 +37,11 @@ const styles = (theme) => ({ }, buttonGroup: { textAlign: 'right', + marginTop: theme.spacing(2), }, form: { - paddingTop: theme.spacing.unit, - paddingBottom: theme.spacing.unit, + paddingTop: theme.spacing(1), + paddingBottom: theme.spacing(1), }, formRow: { minHeight: 75, @@ -60,7 +61,7 @@ const styles = (theme) => ({ zIndex: 1, }, wrapper: { - margin: theme.spacing.unit, + margin: theme.spacing(1), position: 'relative', display: 'inline-block', }, diff --git a/src/components/DeviceInfo/index.jsx b/src/components/DeviceInfo/index.jsx index 48863314..434469f9 100644 --- a/src/components/DeviceInfo/index.jsx +++ b/src/components/DeviceInfo/index.jsx @@ -32,7 +32,7 @@ const styles = (theme) => ({ }, }, columnGap: { - columnGap: theme.spacing.unit * 4, + columnGap: theme.spacing(4), }, bold: { fontWeight: 600, @@ -85,7 +85,7 @@ const styles = (theme) => ({ flexDirection: 'column', alignItems: 'center', maxWidth: 80, - padding: `0 ${theme.spacing.unit * 4}px`, + padding: `0 ${theme.spacing(2)}`, }, carBattery: { padding: '5px 16px', @@ -175,7 +175,7 @@ const styles = (theme) => ({ }, buttonIcon: { fontSize: 20, - marginLeft: theme.spacing.unit, + marginLeft: theme.spacing(1), }, popover: { borderRadius: 22, diff --git a/src/components/Files/UploadQueue.jsx b/src/components/Files/UploadQueue.jsx index 28a115fe..c26b1b20 100644 --- a/src/components/Files/UploadQueue.jsx +++ b/src/components/Files/UploadQueue.jsx @@ -13,7 +13,7 @@ import ResizeHandler from '../ResizeHandler'; const styles = (theme) => ({ modal: { position: 'absolute', - padding: theme.spacing.unit * 2, + padding: theme.spacing(2), width: 'max-content', maxWidth: '90%', left: '50%', @@ -29,10 +29,11 @@ const styles = (theme) => ({ }, buttonGroup: { textAlign: 'right', + marginTop: theme.spacing(2), }, uploadContainer: { - margin: `${theme.spacing.unit}px 0`, - color: Colors.white90, + margin: `${theme.spacing(1)} 0`, + color: Colors.white, textAlign: 'left', overflowY: 'auto', }, @@ -96,11 +97,11 @@ const styles = (theme) => ({ }, cellularWarning: { backgroundColor: Colors.grey500, - padding: `${theme.spacing.unit * 1.5}px ${theme.spacing.unit * 2}px`, + padding: `${theme.spacing(1.5)} ${theme.spacing(2)}`, borderRadius: 4, display: 'flex', flexDirection: 'column', - marginBottom: theme.spacing.unit, + marginBottom: theme.spacing(1), '& div': { display: 'flex', alignItems: 'center', diff --git a/src/components/Prime/PrimeManage.jsx b/src/components/Prime/PrimeManage.jsx index 34ba6b57..84d80552 100644 --- a/src/components/Prime/PrimeManage.jsx +++ b/src/components/Prime/PrimeManage.jsx @@ -130,8 +130,8 @@ const styles = (theme) => ({ }, modal: { position: 'absolute', - padding: theme.spacing.unit * 2, - width: theme.spacing.unit * 50, + padding: theme.spacing(2), + width: theme.spacing(50), maxWidth: '90%', left: '50%', top: '40%', diff --git a/src/components/TimeDisplay/index.jsx b/src/components/TimeDisplay/index.jsx index 5f0d7dc1..b757a390 100644 --- a/src/components/TimeDisplay/index.jsx +++ b/src/components/TimeDisplay/index.jsx @@ -24,7 +24,7 @@ const styles = (theme) => ({ backgroundColor: theme.palette.grey[999], height: '64px', borderRadius: '32px', - padding: theme.spacing.unit, + padding: theme.spacing(1), width: 400, maxWidth: '100%', margin: '0 auto', @@ -42,7 +42,7 @@ const styles = (theme) => ({ }, }, desiredPlaySpeedContainer: { - marginRight: theme.spacing.unit * 1, + marginRight: theme.spacing(1), display: 'flex', flexDirection: 'column', alignItems: 'center', @@ -82,7 +82,7 @@ const styles = (theme) => ({ borderLeft: `1px solid ${theme.palette.grey[900]}`, }, currentTime: { - margin: `0 ${theme.spacing.unit * 1}px`, + margin: `0 ${theme.spacing(1)}`, fontSize: 15, fontWeight: 500, display: 'block', @@ -204,12 +204,12 @@ const TimeDisplay = ({ classes, isThin, onMuteToggle, isMuted, hasAudio }) => {
jumpBack(10000)} aria-label="Jump back 10 seconds"> - +
jumpForward(10000)} aria-label="Jump forward 10 seconds"> - +
{!isThin && ( @@ -243,8 +243,8 @@ const TimeDisplay = ({ classes, isThin, onMuteToggle, isMuted, hasAudio }) => {
- - {isPaused ? : } + + {isPaused ? : }
diff --git a/src/components/TimeSelect/index.jsx b/src/components/TimeSelect/index.jsx index 0b593bee..d168db78 100644 --- a/src/components/TimeSelect/index.jsx +++ b/src/components/TimeSelect/index.jsx @@ -9,8 +9,8 @@ import Colors from '../../colors'; const styles = (theme) => ({ modal: { position: 'absolute', - padding: theme.spacing.unit * 2, - width: theme.spacing.unit * 50, + padding: theme.spacing(2), + width: theme.spacing(50), maxWidth: '90%', margin: '0 auto', left: '50%', diff --git a/src/components/explorer.jsx b/src/components/explorer.jsx index c08b3b2e..3a2bf586 100644 --- a/src/components/explorer.jsx +++ b/src/components/explorer.jsx @@ -31,8 +31,8 @@ const styles = (theme) => ({ }, modal: { position: 'absolute', - padding: theme.spacing.unit * 2, - width: theme.spacing.unit * 50, + padding: theme.spacing(2), + width: theme.spacing(50), maxWidth: '90%', left: '50%', top: '40%', diff --git a/src/components/utils/InfoTooltip.jsx b/src/components/utils/InfoTooltip.jsx index 2b056528..ecbadc52 100644 --- a/src/components/utils/InfoTooltip.jsx +++ b/src/components/utils/InfoTooltip.jsx @@ -38,7 +38,7 @@ const styles = (theme) => ({ marginBottom: 8, }, icon: { - marginLeft: theme.spacing.unit, + marginLeft: theme.spacing(1), fontSize: 18, }, }); From 864c158843c57aad4102b646bd6a97ff6fec3407 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 2 Nov 2025 20:17:31 -0800 Subject: [PATCH 21/26] fix build --- src/components/Dashboard/AddDevice.jsx | 2 +- src/components/Dashboard/DeviceSettingsModal.jsx | 4 ++-- src/components/DeviceInfo/index.jsx | 16 ++++++++-------- src/components/Files/UploadQueue.jsx | 2 +- src/components/Prime/PrimeManage.jsx | 16 ++++++++-------- src/components/explorer.jsx | 2 +- vite.config.js | 3 +-- 7 files changed, 22 insertions(+), 23 deletions(-) diff --git a/src/components/Dashboard/AddDevice.jsx b/src/components/Dashboard/AddDevice.jsx index 31873ebc..22dfe45f 100644 --- a/src/components/Dashboard/AddDevice.jsx +++ b/src/components/Dashboard/AddDevice.jsx @@ -335,7 +335,7 @@ const AddDevice = ({ classes, buttonText, buttonStyle, buttonIcon }) => {
- Pair device + Pair device scan QR code
diff --git a/src/components/Dashboard/DeviceSettingsModal.jsx b/src/components/Dashboard/DeviceSettingsModal.jsx index 20ea5cf6..fe81c51a 100644 --- a/src/components/Dashboard/DeviceSettingsModal.jsx +++ b/src/components/Dashboard/DeviceSettingsModal.jsx @@ -270,7 +270,7 @@ const DeviceSettingsModal = ({ classes, dongleId, isOpen, onClose }) => {
- Device settings + Device settings {device.dongle_id}
@@ -342,7 +342,7 @@ const DeviceSettingsModal = ({ classes, dongleId, isOpen, onClose }) => {
- Unpair device + Unpair device {device.dongle_id}
diff --git a/src/components/DeviceInfo/index.jsx b/src/components/DeviceInfo/index.jsx index 434469f9..d7b773a1 100644 --- a/src/components/DeviceInfo/index.jsx +++ b/src/components/DeviceInfo/index.jsx @@ -336,22 +336,22 @@ const DeviceInfo = ({ classes }) => { return ( <>
- + {distance} - {metric ? 'kilometers' : 'miles'} + {metric ? 'kilometers' : 'miles'}
- + {deviceStats.result.all.routes} - drives + drives
- + {Math.round(deviceStats.result.all.minutes / 60.0)} - hours + hours
); @@ -436,14 +436,14 @@ const DeviceInfo = ({ classes }) => {
{windowWidth >= 768 ? (
- {deviceNamePretty(device)} + {deviceNamePretty(device)}
{renderStats()}
{renderButtons()}
) : ( <>
- {deviceNamePretty(device)} + {deviceNamePretty(device)}
{renderButtons()}
{deviceStats.result &&
{renderStats()}
} diff --git a/src/components/Files/UploadQueue.jsx b/src/components/Files/UploadQueue.jsx index c26b1b20..9d621909 100644 --- a/src/components/Files/UploadQueue.jsx +++ b/src/components/Files/UploadQueue.jsx @@ -204,7 +204,7 @@ const UploadQueue = ({ classes, device, open, onClose, update }) => {
- Upload queue + Upload queue {device.dongle_id} diff --git a/src/components/Prime/PrimeManage.jsx b/src/components/Prime/PrimeManage.jsx index 84d80552..bb5693b0 100644 --- a/src/components/Prime/PrimeManage.jsx +++ b/src/components/Prime/PrimeManage.jsx @@ -341,7 +341,7 @@ const PrimeManage = ({ classes }) => {
- comma prime + comma prime {stripeStatus && ( <> {stripeStatus.paid !== 'paid' && ( @@ -367,7 +367,7 @@ const PrimeManage = ({ classes }) => { )}
- Device + Device
{alias} @@ -378,30 +378,30 @@ const PrimeManage = ({ classes }) => { {hasPrimeSub && ( <>
- Plan + Plan {planName} {` ${planSubtext}`}
- Joined + Joined {joinDate}
{!hasCancelAt && (
- Next payment + Next payment {nextPaymentDate}
)} {hasCancelAt && (
- Subscription end + Subscription end {cancelAtDate}
)}
- Amount + Amount {`$${(subscription.amount / 100).toFixed(2)}`}
{error && ( @@ -457,7 +457,7 @@ const PrimeManage = ({ classes }) => {
setCancelModal(false)}> - Cancel prime subscription + Cancel prime subscription {cancelError && (
{cancelError} diff --git a/src/components/explorer.jsx b/src/components/explorer.jsx index 3a2bf586..34e0ca17 100644 --- a/src/components/explorer.jsx +++ b/src/components/explorer.jsx @@ -229,7 +229,7 @@ const ExplorerApp = ({ classes }) => { - Pairing device + Pairing device {pairLoading && } {pairDongleId && ( diff --git a/vite.config.js b/vite.config.js index 39fd834f..1158ff81 100644 --- a/vite.config.js +++ b/vite.config.js @@ -27,7 +27,7 @@ export default defineConfig(({ mode }) => { output: { manualChunks: { 'react-vendor': ['react', 'react-dom'], - 'mui': ['@material-ui/core', '@material-ui/icons'], + 'mui': ['@mui/material', '@mui/icons-material', '@mui/styles'], 'mapbox': ['mapbox-gl', 'react-map-gl'], 'sentry': ['@sentry/react'], }, @@ -51,7 +51,6 @@ export default defineConfig(({ mode }) => { optimizeDeps: { esbuildOptions: { // Node.js global to browser globalThis - // Required for Material UI v1 define: { global: 'globalThis', }, From ed7fd351670979f539cc40bcdd3a70d94a7ade3c Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 2 Nov 2025 20:19:28 -0800 Subject: [PATCH 22/26] rm mapbox sdk --- .gitignore | 2 ++ bun.lockb | Bin 458988 -> 461213 bytes package.json | 2 +- src/utils/geocode.js | 5 +---- vite.config.js | 2 ++ 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 07c676cc..a013ff31 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ # See https://help.github.com/ignore-files/ for more about ignoring files. +stats.html + .idea *.iml .vscode diff --git a/bun.lockb b/bun.lockb index 59a40711998e01e47fdea0cb455d4f8a58606225..bc133cf914d91786b3a64dbd29cb4f2eeb2e68fd 100755 GIT binary patch delta 76224 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 z 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 KZ<>`Z@&5tYm}3|K delta 74426 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 diff --git a/package.json b/package.json index 5d839c76..b5cd6754 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,6 @@ "@commaai/my-comma-auth": "^1.4.1", "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.5", - "@mapbox/mapbox-sdk": "^0.15.3", "@mui/icons-material": "^5.15.15", "@mui/material": "^5.15.15", "@mui/styles": "^5.15.15", @@ -69,6 +68,7 @@ "jest-puppeteer": "^6.2.0", "postcss": "^8.4.28", "puppeteer": "^19.11.1", + "rollup-plugin-visualizer": "^6.0.5", "tailwindcss": "^3.3.3", "vite": "^4.5.3", "vite-plugin-pwa": "^0.16.4", diff --git a/src/utils/geocode.js b/src/utils/geocode.js index 6dd75cb0..a4eb65b7 100644 --- a/src/utils/geocode.js +++ b/src/utils/geocode.js @@ -1,4 +1,3 @@ -import mbxGeocoding from '@mapbox/mapbox-sdk/services/geocoding'; import * as Sentry from '@sentry/react'; export const DEFAULT_LOCATION = { @@ -10,8 +9,6 @@ export const MAPBOX_STYLE = 'mapbox://styles/commaai/cjj4yzqk201c52ss60ebmow0w'; export const MAPBOX_TOKEN = 'pk.eyJ1IjoiY29tbWFhaSIsImEiOiJjangyYXV0c20wMGU2NDluMWR4amUydGl5In0.6Vb11S6tdX6Arpj6trRE_g'; const HERE_API_KEY = 'O0atgmTwzKnwYJL2hk5N5qqG2R9y78f5GdHlvr_mtiw'; -const geocodingClient = mbxGeocoding({ accessToken: MAPBOX_TOKEN }); - export function getFilteredContexts(context) { const includeCtxs = ['region', 'district', 'place', 'locality', 'neighborhood']; return context.filter((ctx) => includeCtxs.some((c) => ctx.id.indexOf(c) !== -1)); @@ -119,7 +116,7 @@ export function priorityGetContext(contexts) { } export async function reverseLookup(coords, navFormat = false) { - if (geocodingClient === null || (coords[0] === 0 && coords[1] === 0)) { + if (!coords || coords.length < 2 || (coords[0] === 0 && coords[1] === 0)) { return null; } diff --git a/vite.config.js b/vite.config.js index 1158ff81..75c95ec4 100644 --- a/vite.config.js +++ b/vite.config.js @@ -3,6 +3,7 @@ import react from '@vitejs/plugin-react'; import { VitePWA } from 'vite-plugin-pwa'; import svgrPlugin from 'vite-plugin-svgr'; import { sentryVitePlugin } from '@sentry/vite-plugin'; +import { visualizer } from 'rollup-plugin-visualizer'; // https://vitejs.dev/config/ export default defineConfig(({ mode }) => { @@ -47,6 +48,7 @@ export default defineConfig(({ mode }) => { }), svgrPlugin(), sentryPlugin, + visualizer({ filename: 'stats.html', template: 'treemap' }) ].filter(Boolean), optimizeDeps: { esbuildOptions: { From ec9f4ccfd8e92e79e9ec3202ff064f7fc9e2ff11 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 2 Nov 2025 21:57:14 -0800 Subject: [PATCH 23/26] one more down --- .gitignore | 1 + bun.lockb | Bin 461213 -> 436666 bytes config/jest/setupTests.js | 9 --------- package.json | 1 - src/components/explorer.jsx | 1 - vite.config.js | 2 +- 6 files changed, 2 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index a013ff31..4bfba79e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # See https://help.github.com/ignore-files/ for more about ignoring files. +new-connect/ stats.html .idea diff --git a/bun.lockb b/bun.lockb index bc133cf914d91786b3a64dbd29cb4f2eeb2e68fd..3c8f87e4cf1a6d64b91ffdba884570f37594c386 100755 GIT binary patch delta 84503 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 delta 101874 zcmeFacUToyyEZaPk z9*>q+iYr#BTBC#Ye%2!C9LPWI2%M!qEnKS zW1=&ZG?Sv_P?YSnnBJLLhL^_DN0W8nkYa6E(B*fo0NAzdd4>~ zD@q|?S`6~}#-}#`XS(?G$h0(T;IsXQZSJR2o4|D&h-d#Z9GR zL2imt9K5u|aX?nI7+QD&qtnwf2ByX+IU#qfIKZwD3eAgj{y-}$sDT@?B5rI+4VmyZ zO7#Zs0<8)FHvt*{8{}TV9Y89!7RVNT3uHs`=1~;<%Z`goN{UHKNH2u)m~S5v`v8{# zivXv2C|0E)0>dC6CdDVmC!zIip&kp0hny960OkXR0;zcoAX{1*h=17yaH9flKw9t} zYKJb_eS1e`rpGDDQ*bu$Hjw3BmUt?Uo@OepEk)flR6%{Fsf4wn)V3X(NUckP8=1hV zWKM7vmKYync+MJ_i0Mo+UGJEvl+5JlnBI{C6Vj35u_~0mQCPIPKbl?+=@WodvUyP< z?+K1_t=X%K33X-yS>Z^D$v|48v&2w|)q%8%50F+VQBo)jMKb$9fh1~yD<9%%B@M_1 zg`h8p;(Tt@iAG9c|$N#b{iXG@lsRg_Y| zDM0q`6v$!e?BNp4Kq}a~yr?(>oZWQ@=3w~+!P%V&=`rciu!Ir|0X4P&O8}!PDhjNX zT^5{<6kSP-gw{Z|APh)FHdPjuLotzwk-cM$VFh6htFefk;NJnmneC)!3k%@_L zKP59cH8Hb~H9omZRngL>K(-`0E~RgL@5r>+^qBrJ$rQXq^zI#>mO8Mys4y~lU{Yj8bX-(gWONL=seBEQE*Y2`^Gfzky`Q;| zmR(a6m#I%R7qVv760CPhMoe;lMKNkX|JFh8u~K_$IGR!;)6*+Ud1)Y9`DGo^n2SJK z*PiYM9F zN=O%;II@wbXa?jM6xn|MqSeE}=~szB`a?&F{R2dKA>jGp7TN9y(42}y`_vkpn4U#X zuMRmK%|~K>AX|1&wy;yMqF@kYHv-a8%K-}ltsz2TZ*aCaH;@fz6e|4dd!iMBB4Hwd zJCGHA>)@vU7`*#^#Xl44Q@ zupyaEgktZ2MIj#*0sGT5ZxCR@`#?Ho7LZ->5DCfcK4ACgtB_NHxXARB0m+Ku)?8R5 zJtnDtOq!y^AfDy*jZg0Fn-Z&h14URKmZWmYWorYV}QtN>JW67F}SG5%pvR zl_b7vDV+_i&`=OE8u^MNo?Vd_$O>G6H1Ttk$8;PazNvlt*!joSqMj*jM3-6HbQC6! zNlQyf^Nq=x+Ex@`Hs$z^SeP>}e ztG#M$05HZCWh-hlRP7{6SOv}|tb&aU+hZ8^Ml3q5hcYg-X^m)MH6xM770T%pJX1oJrf(zY*B7IU)S)Vc*8JTWQchR|n!P&&5_@o%$ z-cd?q`oQGqzVR7-QqT%q1A2;a`T|%4=^6s*jrW06>~=4fkMVU)3Zj7Ywsn!hJ6g&N zouWjAmB8u#d7{MtecwaKRd9NnJ>7GpXNylGo|d$)@2QzdsZ=Zl%O!C@T4ZXfb)cg7 zf-*zjn1THn;Snn|EP@K@ra2@&L4izHtdA(z?sW%bMbk0PXrZw{D%2dCfy%&AKsM~B zcww>SKw8)awB|>^zVwZPfF>&5S12$rGAWS?jRI$eEFfDH1}U*FkP4jyGQJPuX`wo( zkTXmg6d}G#5(+&AGW}GHN!Amcl2$dw7yE`-BxHfjQUvY-Qn58a7PtV&7R^Y}7r2$R z*1#BMImwa9De-WQnDnU3_{84IQuKTw$aNs=9V)Sp#MTlU0%?%)!2H1c5*3LL(uMq- z#Jv*N2()I;k%Do+d?=v5#Au1FB>Ds4(>051TmWDl4o3N9rhun9_w=@XN63I(vjK8RvU034V&PXfXwGVLs+1uM3kQ%lc6ZUB)wtIoYwoO$Q=pyBLkiK!Aw!W8t_8k z3xG7`R3H_oGF$M*$jA80K*sNaBIH(ZD!xqe8B)Pvz`~Hn0=9>4`a`p8%y^JN0rpq@act0(1O0NKDi50FB(1)NWB+B&IV4Dm?p84 z#K?sH$gLhIBMgMhu2NrpU6ZSS|*Mec~St0W~WIWQ$#a ztROuJyLMdPt`sfHy+)+#DDh_$oFD0C0O_k=O3VbZhv)n(EIAnH1KxQXDhHakqd^=b zXVwbS_CNw|LxLn$22$gg^vsO-#B}BERxv-V-l-^+AWz*TTqDnJF%LZgX9Yof6s0t< zAdu;9Le7R^+fI0?uW#sJF$gMn1Y8_4{(H;eS4hhhJU5Y#>*_O!PSivm2rS-?&t zqypapO93;1EWiS!f~A3+d0%f5mWf<18gLAp>E;4!00#q^-vX=&`~paY-fe{aso|-O z0@nf=VFj{9O@Yi%30M;73S@;hHi(M$0%-vo&=(j7tO~3NWWL-$Hslx-^9L>il79(g zIkl|_u#XA>O8_7KBwDf$NX6y>*(GT}wz#p3&$=QC%6U}`*Fun2L;RB;g~bj?TnJ=^ zLnSr?GTno9iqZ&ZU4;NOiv%_YmIu}YK7mu#1;)UOJ%D$A7nZpO)W9*ra__HnKs<+K zU5OQexxuH87S34$oX%GONMEy$HhJQZuC*-r{*f?umJ@4v_O+<$HSlyk)Hq z?hA2)2V$_ccm$C3WB_T$SOYOl<^M~x+#N_mrWy}piqaJc zXkhy}Lu+ux&v_v%W|2HSGdc~AmdfatqMX$Dw8#t`G$ajzwzxXJ66IvX#U!)nW|A8g z#V}C@y%zIf0+1Tkc_T7Zmbe{APssOHRGb=_5yz#?-UX4!#}*cOC-Ub8<^p$pFXTUf z(~`Tu3jsF(*{}Zq-s$dUnV!+JOTM-`K>+KIw^( zJlR!-p+MRvI^GwEV?F)TkN*``Q5}QEI`~xE6GkjC5$x38a zd2e2#cBPk{;-sp(v0T6P?4Jjg8Y8*`9B*dkt(7X+hruzZN9(BPJ1}l6GPSbw{ zPKEve(t-ox;-hIHoC4ymD6?fbmy3&h&tVznw;%Z|DWNLiG({W&j0h|#3Z4UGfs-ZY z13^4SMQw1$0_?n8Nqw1DaZ}F{`a!Sa)~#Qt#wxlPSOBH82hve5mJzwDloh2IlUK zU{G=z^QakobWbk9I*vc+M(0Ci`tHx1rUm!KT+dz0p zqQ7eFks1N3LS6{St;~Z)s2xywIyehH0i*(1QlU07K3rl_D^YQGiLHPv&jO_7O4qjv=Q`9{m}onY36k0f z4P&?##iR}NLVn+b~YlG9r?yM0r zNh9wLV)&E;vX76o7cFbpQLk9MxZbL`m$gb~QFcKf%Zf$0`GGyUsK%DOE|C6K8pv5p z15&3}NXH^0y9u4o0~!A-kjC2%q%J$V3-swBbT0s8C%6D%Tx<4vBxIxJyUC3f3ibv+ z)l)cfhh9Q4`$BsOoC=hU6cyS1@ZZ-%`+{p!SGR|1>v*U>zp{)>Li|Yev z(qh13KxZj`&_@h_(?AxyP4cBccGY)4DpDOt(?$R}vi&7Ty+%V`C5dt`1344y1D5qd zU^N1)csh`ZSb?ml50LS#lYU%Q@{x;m@8mfhKISQ~*yHr=ehIg#RT#Uphc&jqTc1wp zf!gMFXX@LUJ*yNy*Za}iwmrPhUm1U8_LF?e_gtEptN!X{-ETJ!$|!s2i_JT(-5KH< zkT`xz$?d%d1y;II!?#_IF6DOB9zLbri6?u9rp`Hg_~bL&nlpum_&i&f&_8qFhpxpM z2Tah$MO?EUn?3Vj;eJV*aujItdxu8oW);d&qVScSUd4mEmKt7R zeZ2vBcNH4DblUpkx8MKL>rU-^@fAidC!@vtA0*yeY3SSRNM4sjQQ*G7aLr>XwMgY$aRxbu8Jw|8}&KXd&roCFWPrJ z+&bpLu*SRcHu$S&v#$^B4t{uV|IJM^?OZQkzPyLs4EE;f*UEW$*j0ZvWM$xv)}}A@ zWA)3seadz%pk&=D#Vbr+@$Ou)n&&28d2uql%n#!p#*~dLZ<##P68EggvZ}cQr{60w zxNWDl(Yeo5n$u&W>zt{FOOO0xf&QwZpYB)5OMg|bymex?{!dPM?TCK0;?k%Qwd#%? z*-9&w_3eP=mv3CE+UzgCT2rfbnN)Utqk39O!(Z;Tp0%~=sqrrcxt%(n$NOQGS~EJ< z^>dn(F*PyLmaE@aA%$;Fe6{u6a?gO8i~4+?+{>?@pl_Ah_$ z(4rmAe*68|N(E#(YoABX%8LDuIJr!TPp>>qFZ5(%__|%@5wq4u{<#c)!HlLA_s()K9SobLJ^<%5@ zOH6v>N~u5YtTa#kG0u0ad0mZ7CjHl1CD+w{;-r_Xzh+&78S0Po8lF>s%=Yi4t_$>2 z)uDQ|Ad9+HABg)~eHZTabS>DTuGL%PeoLQ;dn5fi?gR7+AxzmX#A1Hyj2T(a6&#}W z($!Flxbn=3b&|7^>Mhb)sKf;Ou03^uq9mWt4CTa>PCGj?(g)cxL4QfHMXd0^x?SQ)eqp_ zRrhRS(SE>O&VvrKK0GKu{av5m#G;ng@8aHFuNGl3DY^7P5#efzzAM6_?$WiUY-wxU z+v+oM|3<%#`x(7LGmGk@_rpC>-;DcAU2SgB{=oEy9bUFcS6c?CjrFOJt;D3?3^GL@ zo*m%niiy%-oO^JY^`M|Ss5-s{%U+B7as4&!Mf9MS7IP#PyHMNkTuu%2)F3zYd;NGz zi+Wr4Ze>x+>5;80T3<|a!6;nS)u#dKO8qHh44XE8s7tg`MK5~6zR*W1yK71~?W8G1k5|I|0*9-^xqEZPXnpj8aL`h_v?)DDb4 zk9$?!r=vyfqsQYuTVIR&d;K-;bM>H37E{im`uI-aYMg$&lSMtDdv~^|zvz*;7to*L z9%bBD>%+TP)Hl4F!!XA;)r)lwQK#shT`k&a@Ca0FHhidpKEJC)jnVJoZquuEvzYgk zgq3L=%@rHPhHSE}bx}1yYc8qTu;gsLb$5&THe`N=!|JJR{M17F_3jomUhmhVknYja z59;^pVNs9hn{j`jt354hMZF2`-SnwFE#{eDp!fCnPeR~$KE3FY@wo5O*Y>iQa+KBI z^a@uy=s}Sd^AYSUV)bo3Lev`iaqtP);RYJ~njRTtQA_GeaZlEtMp?`|a6s75h(_B#tXJq`QD5o(aF5V81)$0=7seXrM;e%7J?oLO1G%B_2amw@orv)g6bP_cl5{% zi@90@4hW_lqCd^x@Tr$+Q6K8Vac`?1z#Rjnzr}o_5k28ZW{6r}pAX(2jqYUdqk6Rg z7IUcpMQLa7@%pX-7WIOzWm(j+dTZQ!=reJju3yixXukzwjG!$h!}K5ZegiG$ra^Rl zmTlA3K^F5daDTlKI6kugKaOdvi@_`DK7%dV_z=f=`d5AJV2jBqRIi^IuC~;JhFHuS z;Xfh9v{OMpKE$H+4ii(Mq94x;fU`ypwP2Jj#XU@aI@F>K3|EvUP)gC~2M4IT_2I)T z=J$|Auu@Np1z&$MR$h7Z`5o$Lw;^pO^27#c4H}ECHfC~d6d2lxsTWhBwik>|)(jV! zfQp#UNsnw3pm|~P>18lKenQMwx0t*UVN4RHaFgm0&H8D>H3)7D@4$)2_1V0vQlUAU)ec_-hb_8Rb zt6r^HfHnaP%|Qt){UjL6b75P|S_|sHxv~jD%ww#~+E6fRsv2W-4;b^P`qLYMZXldg zRegSJfVoynMG4T0wF=QP5aJwQGOF1mnTu_0K}@~oR-#SLoU^q6$;|rGCIQ+&Fww%P z2?5$_FfM^kOzHU)44##pU)s^6KV4NvtKM2T69yhiO9i976n)pU0Bso<2c?55Hp?8Yw&Rg%T{lR(8l`$R z4bUoeup5P)76~SHIhVh=omCV4h$0x z3g)b_8mumumn|qaGX4ol$9B~tZv<#HBXL{|=A^HkAE5OGV@7A&E)7X{gL3?0)^RhJWoQjjSN99bb9-VvE+c> zqBC5K0X!Tm5Gh5iyTBTPiIMXj%n!_%56$&s!1TGnA?5^xYO(`8zeOmR^(f+k6Sc16 zd5tL{b(T`Iemtm-Rs;itu4RmPtuq)~iw!+&I3J9i>deiCb`i`d)v#!VKK3r=po|A& zO0zLzEtGM_lBL}Q!&=8qtEdK;M#t&PhK6gqc#8#tl_5Z@p|>_aMPQ3 zeNc9|Rx`nFMh@Rm3A#JR^f3t81BT7D3Vnt4uC$uxB(Q2MQ?}4u_Z(E$4MNcfj^0;b zfkt*tJFOE16QgV@m}nq7+^q1f7N0Y3&_S8qNs#I!R*kC+&4&Xb83))bh#eF`o86ngO~6w;sV zXS%NtYGQ=WehQUDzY1CWr_j1jp|_txp;=6KWJ;*B5nyp=5V9D>6&q*|_5KuE{weef zp)ey|ok8}{kWZmq_K>N-V13Zn;abFCG3S_R6zu>Qd)C=-WTzpb*Nw+aEexyy;#8fp zQ?`u5J`(G|8?f4l6RiGFF({4M*3^HfzGYgtwgf`XGlo#R2F45qQ%mZ{ms(8ShUw$O zk#Lyf3UdXF+3=_os0O-Og?=uEwynUzKh=6ETTx(W=s<67GaT=;KE)jc!|0H4bw@a| z1z@N|#+4lD$i4-G8_Brbqa5>Pfi*-N_7#{AegforZ?{yVj4b9cb^k(ZaN-`xzd=A zBGk%QnTk&k&TXtKrq~I3#kt|yatNs+_Kr~THdutg)Te=N69qB)*1Q$0lTl8-Nn&8B zdh4D6rszrfviaejKSIcjg?;uA^P}rm_VPH-bpzvUDRySF!01SZvzTv#wXm%$sD_wp zP3Ay@?w$h>;^b#9)JqSVUB~49wSI45xT*cu`k+PO+N7^#p|;`PYJm9=Xgl3^M2NYb zt|;9M6MTb^Sa#nc)aH{0+0*PAU=cQN0TZc|Z$#IK{d8S0p(mH>G%(KbMjOmqz#byqBkVK)1o07fxC0Bda6webu`ZyEK8an9Tc zR#WfZCdB;Q9x|1msV`d=uJxE{??LJ}3rw_-yXg;L%}}#g2_t5SV-%tLJTP(Aa0?;! zx>#`<&K5psY${CIv-Nu`!cAvp>(y6=YenYROQ5&(0~40ves%e$IPMwLx%NhqH3#cv zSPc_{Y3W@3#;S0W`mJ7Zb-20Rx7<2$Q?v{rQ67iqEievULl3RucXm(W+@1ke*NDSn zV_NZ@eql|x_6S151?kG>;CZwwEjAvZK*PcZ5n_?pt1Ju9Jm%XC$Mns>+8JuhLr7H2 zLHGxlG-xRHc?-Z;mU%ovqTfy+)WcAQ<@ha>hEaL;oP7{w{#a@MP*)iIS{ zq<2{#?%8pXSajWGq-Ja@#zHEZM>FpPqgl+h{xp{Jq$)<>4cMY3=vA z`^IqXF@%3xu)<(Av?`=-x@T5^ zmSc&1#Is|%g0(=LnDdu{v3XcB(J_y~sJU48%PkdS(>U(ZVk8s0(S=~uKczek)(K2Z ze7?(sn+Y}&tcnpw2VVdH_X%nOHT@wPdufY67j<^7AJ6J0)JX5y} z(7e}((!`@`lw`&cvNjK_F;a?W(>Gv$8!CLQ12caO7RrM;ZQ0M*0U!@LteH4@!tt)@ z@z45&-QngL+wco|`sLjrTK?_AP|jT0&0WAc@SM)HX1o4oPq=5k9rzVhlwx-xXZ`8; zI;L?u^znO(oBHq2m+dWUcG}5@Jr2lv2=!-n^96*m3_XVI604gF&qTD^yTw9{R$_`= z0hVAq1N7dbD9NbD*ePl!z=jzNvw*qFUOvvh-xFe*xmWM9KU_Nw0hMw$Hh`v@`}BMJ z!#z{?iP7pRbuGdUFdv09(NL-WFDTRqZ9*v32$kP&kDZ24h9PtNl}fP@X$TpomS)od zMfuW@jYVjX5i%Ww%0?&^p)@0O1EDy*d+!i)#36fm+Yu6ZlMmB8=p1vKBRq+kdmz*q zfkB3->`{Ah(-1P$^K|}AJgNWPq@e6N<^)JHj67EmVv|Chk5T7`y^TPBLxG0J*)&$R z1R>G1q9+t(tfA;4gkp`5`$Za7gnl;kNxP*e(~OYI@A%~t+C!Ux5XZXlq@v~g1H~JRbHpI9 zzgK~uz-l5+94FiX3pc9g;#TFhBg+5_MV#0zYyt}e!+W8|0j5{C^@z*iTJ1YxYBT0k zQ`#N<0)*>72|0^?0OP!4JnU%^cg39QY`n)XPXzVTk8BHdLx2l~IKg@@nPxmHw7O@X zhq>H*4Msf-txPBG=~36hHP8DZJEn`+0M901wOOSiE>GCDj%J0FD~vcfSu2^s=9piD z1shL;Egu;B<0m1e?;hw~ZiJgJKv371ZSp=8b`D5AT^a9opOw7CY z!D{M_#)OzlJmF-Qg!g6r5DG&IlWnat_P@K0h?UDiH1(+{Ry4mA82jDWw0lkmt3f6W zmX8N)<^zz{<`&5G@u_~|PPlgBnOKKi_?Ez2`%f+!*!yUs5TZ+olekS_Ex?cpPyQ~? z?fP>+5C|58IC1zg9E=WT^qRI0jGE^$I=%c~Vwp3JeY7kvw%geJnSTQFGtLQbA>O7sn2>CZkqX0zwt0!yZ6%mD9LB6lCQ+) z{^G5hISLeS25@A(0-@SQy*&B2LAjwF29c-V>wn$D83#t%6iC|{X=s&OV00HJ?A8L^ z-iYktR6AQTSHl}jN8adfo`h>9-wO3bL!-dz8rh9KJ{Vm@Gq$m(Bty|%arpX9rv3@^=Kizu*8 zM&5p}15GAXzxXOl^TP+%5fB;=MAP%B&T6>MA+-~7dUFB2bzGpEvuaE)Zid^}0ORan z<_5_r+F8{nyb063lTsY4?+-BF0mCB$&NBV*;WO=E>~FLLu$l&A%fAIcd9EX<_2yyV>O-9!Mr%f)Ze&}78_6Snug$-W?I8}00^{(&3v=~=m5tD7WhZ<;t z^gg6_A?2ty@x7E&H8)ky@iELP4LCSEOk3e5S|H|&OJG7Lc${Z>P4k94!aDuao40sFyf8cy;SAq0(dcPQ4|{5eI4Y@~Ou0gLnn_6<7nr zd5FV^OQ4*X3K++EU*xx&p2qGCMpL*NBXS8C=OA(1drhVk^HbgeqEKOq=3rv7^c)_b zjr^Cm?O=Z!&8eX1PQ$!T{R*O=azX!f5L3sTTp64mLfjy?8fGqouion$lem_EAgd5l z(L69ZwqjFz;u8+OKj%}-%|f;=dDL*t7hk<|Y+~iU9AN71WxEHd`2?gvh86R9tHv>t zIK^)xnX|E=YEwa3lV(h8`z6Bz7bdXxl3^3GAIEitg?FjOv^)@uUM#G>9E`(B_|a7` z_A}OaEIP%C2=x@h!<&OuMV#^SSQ`(-mz(@9g(q)W^+s#~2xTqeu($7BFw3-n9-E|pYY?1M0ig_oPzu_YJE2(l(H0nI@31ARVjrJy4O2`NTjBE1YZjzTBepn)!RS8X@WC0s zHX-ukJjhhLs;zzn42Eb(#fqfwT;`|k2IYo9%!}cE!Z8e2GT$LH4jdz@3DX(IGL5fh zyH^pF?}D@*^2$?VXZ(7FaBL3KKrs4(m>0%^bpR8`K!1X@0do>tr?49Kj^*xWv}D3P z_JMJuV~kjHgPK%+rL!8MO+fHdhigZ`#N5Jnyg6!#l}YAEu`xaj1tm9A*zxpDj5@Eds7$L zpF`A9l-M-XHohK28$wl_bl?!fR4~j|xITKKcbIDY8m+MXTCk8$ZF>$z%Za!~;eYpJ zpfgCg@n-y2gaUNmX80!2q8f*uB6&lw=ASZ;0}~4zch%d##K2(}7ip|2EsQRXM~H4E zM)qP3(h>3vFkxPfn(-1>*xJzXS+$1K~Uan!4|5V?%w5p#PmWAQXkMJUL&t+5*Fh7bp(@u;pfY-wLV zI1WaD{oQ~2!2X_ITv|D@p9SAK2gd+*&)@EDVfOs<4C=?C-I98SGOhn=7_K zDYot|&=Db8LadQHz-UY3Gp6ZXRcG_xC0N@!YRj`S~S>)~*9)IZAa;JZ&uk zV*|nP>C#iMPy2JNZAXkR#0l402F9wen% zILBi73=c3LBr{$qSL`8nZoPYmvcv=8A~3P9;j;1^j6Q@N5MEhS=_!0XFPr3<3Pyi6 zOC1b7P0xGU652wC$X>#CiW~3bXM(X!#f?XfyI}0j;@nZ2>O|Vcw?mGBkzyJWX^w)? zR}5y>qA-c*51WK&0SK{!47q7^l=Y%aUxz&4>e| zD~MVSg3(O`E7aSePAwLU{$AX8Ciosq&#ivW7Qixu;vz1vN?&-Oa_hDb=U>2+V*vmP*gwM1bw@wk!*7Kt>%phv*yraT@C&q?q8MVMdG?x3yzj$H-HZj`ZaK^^i&q&noSgPpCj6?+Hn9~2co=n@0*q-k74jw^Vd zAx94y2>&v!e?oV}z#ois80N-BWcf`5HP8uRn9yp75Kvt3gH4@rIbu#o&|}6$G~uV0 z#3&#yM`T6OhEyQSjhFntqNv|UpdnEjepo;{eppc^et0<|Y>?S9U_@;o{{K3BkNg!A3D)8nV!h}%OxkWk2gyGA5e7GKP6yAoAJYfw@BOyz`XW=VW{GWFxlSsQ485}#;IL`><1 zK3PCU4dm_Lko6CNoaGFY@kCGX$v}#xNI8-1oDO9A8Tbu)fDteT>LNtY04so0U@ef> zKOy5c$oPLk8gPp&Z#R%h_sH}_2KVAO=#7exfic4=AT>K9@f=g(azw^ofSgemC0>&0 zhzwqqcty$`(HMtPe!ZbR;DD^)rsV$#oou-h;9f-&RJXrxK`j2R%uQso9!gFme=4~n zQuK^B+a#1~WihX1vj2os_ASye={t$hMWrd z$#^0Qs3x(xloKiEA7CfelyV|@Ey;o$WRwYSB z5LrR8&r3gj%1f8C!Kk--ef9g(8`xUtIy$@qUp^uJ>SGYmrpws0Jf6;6}|I3hP@ z3#9!221#3JVgZR>Rs^U?2_Q5209ipPATJ_$X&@^oD|tDI<$=72hRaA^#Q~YW zDmc+k%83kG`QMi?P?xv=B{FM6+}HqrSq_mE21pE)7$h+mhz41eFewNJ;-3=1+rJ@2 zEo6KfAS-Go)BO`NzJrV>Qjv}lJ4rdw%o(gZ0yJ$eATve*Ex@HfW?UxaD}XfdIv_7c zWd8M#GitNMZ89B^@jIn_FOcONWPF?qu;RlM{2Nk%BT`NzKPowq{5K#gI3e*gkma3~ zc%Eo`pQaY-Oz{mVz9sPwAhX|<{JzA8K>Sml;>J<_TJrZmmh%zF>N!xHY~9oGY{g=7 zfwFn|CaFC223S@!9W&B8qqhxP+KvO6|D=>VqA{7AlM#-{3>P4$1+K_=A}hEmxg%13 z4RYqYA>$p9&UshL9nlG=%*q2quz-gWAIXG7n)JEkL{{)Zaw2`;HIVt=P;Lv$!l*_- zc@N6$PPj3di$sk=T#m@>?ov)9&ml3VloMG_9*KFS+!2{Cp9`mG5%_N-%ksvJhAJrw z{wJgYrDeP$QeIZd%esjA4FNSOhX}^`;>PW0Z6FOBA)tw<5sKXbPleEr86>QYIi$-bQjF6T5=)_8Y{UYGXFR!C$gTeBqt)?s!SFEWs1b9 zG69h-(WQKvlsh6tv!tBJ^mBkT@jM`Xg#Ysz6z+uf$(uaw63~2xRStq?|~8SaKry z5y^?H_L!6(mvSPtKLcdB7dYlv@gbZqz!?!lvrO<$$aojTvt{ys_WKuPLvqOcj>wkgk#Zu_c}nhSMSun8m6%UP5Gl_u zxg%16LNeY<#uHglQOO;V=}SmCk>!?@+-eUvA`|$?1dd3}OUnYj0P$cJsYjBrG1%)imb7B!OvG?(fA3HeOeMW*WtWX0WqET@;0M*?{f zsZf-G=>KRLL1aX4i7`@6q$2S^7Tj0HCrV5L7K3~|kQGh>atU7u^Z@<{WWMzhH%i=0 z^g_f|DcB})2hmo{Do5vjDLx?aki;Vrf0K9|Nc~R$sqYyeFCzH`$^Qu%e+BW>|GG>E zv>MavJt=TRR&*b7;sY5^WI<0PCvsrE02T&%U~|t3@<}WRWd1_j^h>0nye0SM@BcGH zQ3x1OTw+NeGy2GcM8@+!s^mrF`KvFG>8eOMkqXrWQpW~B_Ec*bPh@@VBzCmQh>pMl zh)4voqGTWoPLc7B=neT;$Z3g*GM>mc5OXCba?mW0oX9sM>m?_0VY6;WfC={iS>awF z75D{6O%DKB(GeMc6v)AF5y%$a05aY0Kwd=3A4u+ql>Z4i%l}JYapk2<=!jJ49prAd zNyD*gIKw^-T6RB@w z4L-_(nn1vUn#u%37T5wvQAgZpsIC%wQi#hDSxzr0|0iVmQHUq@mKdwSM_F(J1ho7B zS-}5Iq+(gJTq5~E$p=~yU?&Zig8wa|2;=jJ|LG?Z)_?jof`w7eQE0&rHExU_UPSUH zB)Ev|s%9j(i0tz=B)A-r+sl9ZM8c}{g3#z2Ag?F^2C|}P$%!mDUh@Bh8q%cUhxya- z!}1+JjQ};c@kvmBGF(I^bo@4ga&pcy|M43MTX*|+2VXM}uKx~FKix?EKSLUPI)13` z=kFt=0eAcZ(!e{VocQ_s2pZ$__Yp9{=kFshIJoqD{yySAeHX#;!uZeMNASA{Uc}Ge zM{s5N{C&jd?<4*<-&N3eK7Swa`TGcLdAe^8Mb&LpA4#qg#YbC}ry0qQ>jO$5YI0 z_hmgunK5TVLp&eT;y=s zU3pgTOk3*xVa@0~*~^=KG_9%WbmrGPeXh9Q>~Yq!Nkbpo+$T`)hnV&2+!st9a=6A9 z!6#Sk8QEjDwU*^=?&}BclwCC8{53s#+3~O1nW|Qa+qHklgE1=@%hF(_Fnl|%rs)d^nUXT3?Kbn=Mxbt52`u2tIjZszPSciwsUQYpKt@{3|y^Vym|g?jzAjM*~Sqf1)zd<*8c zFI~CX_17hyz0W&maY}tXWblNY$0qb?SNG2@1rx^HE3x_L-R=#3Y5yd8;q{Yu~P0CLL-x zv-Gq_udasO{=H1#=nLsb_v~L+`&|3iedcrwY~eC{&epkuuPxh}9DnEPybIj|8g?zr zcbInHyX~mnl&js#Y`uNJ=Tzl!$vKB?JRfsp zyX&Z4*{|l7YhjvM{?XAPS`**9t$$xU;OX?Sodfb5EGEv-~jctgT-4 zve!gk&72U~Wz5)2=MdBW@%pIP2V-sB|5Ux2U3Co~cP4GQzU$=CLX|@|x6r>1&Glqb zY8jtspDjs?!VZ1B+3tt)cc&b`G$$yzN=(|7$)?pK=U3jgF{a&)(Y-9b4;<9HZ}a?9 z?P&9QuI933{;4)qAKG?N@GAxHPn()Hf9%+Rkn!(E6dH1}e2b5b|7wuh-=$&ko&##EJaX2WpzA39aY)uw!r(ZkHM)n>bfy(rx%sCaGnNvCW{f5E(& zd)II2xotzAkuRrx*q;(GDDSla=SS6Ad1&2}lN;-8+)*;L!A~t0U)-7Je%AGvj`598 znhRB0)N%B*ss-J*PP2S9XpDpYPaU;8_}cT3_vrE=Q*P)T-J`;9sUEf4A87jZg}SHj z+8;GQjV>3?;g*$JY{tZ2UUdK1Zp-+RD-QnN z;B3BSsRLJh6<%!GrB)8={pqM)m(owO8!z|i9*{M1Vp_i-C+n|erg$$|`ozh+Zu`rq z8(k}%?ltLR{B`flk1sQ~?U`@OKdDy#h#&qe?UeSziVeRUxjoBvgz7!GdhbfNnXlFd z|M26VTMHjpJz`>_XYJ9+yIO9@HE!k0W7qrnd?;gzX1E*&l7 zJ)mYnLPX^{;_rNjnddJ@^?vKUz3b_>S3L5!X}rD8g}1`yKw%}JKb*PtWfZmf;HRC_t6j6h+aD|)i(4c)cbP6yQHQIs#G4` zFmZIl<}thCVvl@zW5w^sYF?;&^1;TV6C1|0Z#%fc%l1*v+qLeQakjhD-c9Y_=Sy#~ zVRgevtAD(JKL_<`XxsmE3bk}@_hrzVvU|o9Kbq`O{K4-@^THnmjI~z3sTcij+_Mr_ z%!7Q(jLR6}<>~!6F(iMfd8LYNs5`xJy|(?F_pKV`{?~~et{FDpS5PnN=fX}+_f}Z( zn@f}Dd>=T1;EDU;cbM($;duLmZ_J2HWz>t7ErxRj-ycL+$`BmcOGM<;e zi``XZN5J4Z_|smW)O+n{J=H6Caq@F(oo+v$D&aqI)AKK9%~_i7n*yWH={1%W(vtI! z4x9aU&hy9Ky=~p1w>>{K@{esPJAMf5WO+C!r!_PK2mw(`2-I~`= zciXk*M(s+OWxj3Hsk?2`Yt^fHdfSt0ay^V%SGjV$rdQkdHc!~OW^0G`TXMbGxb*R1 zRUeP8Uhm$qv^Muoy{xg(`oXk3|BC82Q@Sp=d1dV{HwW(X$DaZF)a>_)?dyA{4z|W` z)LhoXEAzRozkFv_aFzI`vu@uz7&Pkb^WW>;+;eZih-s&{j!HdPu*8AKAFgSUQy^jVy~Vt9j9-Ojq4)(;lQ z(RlZ~liRbqen0h(vhjI>qv|`Try^{>oR{BJpY``VHSf?W_g6*cd^_`PykC`%fm^uFFg4DuBmle{q*wnjK!yVx-TE2ep?~em#rpFx6OTv-uC@V zZEA8-ZG-+&JJ>qC!<2iO60>Tn_yQ8Q_mE6_p*C&q>R9>5DHH2tJhzNKIXU~1_YZ3q z-n$c1u1$fI=gLhz^xn<=eqWw-Khv$LOH$r%x7TZ2^^cHz6TGL*dhOxw)wS8OS;5=0 zY%AZxBWCAyQg<|6mppRbjlp}Zn_myBerkQdwXDs@b_D;iyYkMJ2aW`vxc>7Or@G$E z@TwYFyvPxM-_4<=a`Xtx*XMPyb&sPROrxnb_h-;I?gR8qdWII{P;FZvu^NAaNLtM~ zwdn1+c_Jpxns$H9!1MV`_oqxuShwMR^MVEY-|DwyO_!BV4}FM?YZJ51tK8!HRjaib zR_x`gzplFE9a`kiHJcaJtaZYn#$1l}xVmY3z3=rg7rw1D;zZH6)kCWsN$~z-$LI4?83j2WWSv2W_$H$>F-n4e`$?1QwB#Y_p7q+*SP8> z-?zRrtbosy+;^s0ZXPH<_0qW$fjv50pOTnwU!RqB$@4dq-&iqwo)UjpNpS4)>G*5(Y>GX@e9xkwc7{1=A z$Cyih-6?f7^~;levi(mT_B_?T+F!RD{9t)|{O3dAwYruckrZ**p*!BAJsk?hpMUyvId6E|%IC)E;(oWvjQi8tr&qhfJvaM|%lZw{^$%;l z%6nHIaxv^}lPifmUmb}aJEh_kb!+owo}-ep2bmL|EIG60x{8mk?fbqWu*@b?2eqhe zToqGCwHW@gC7`&?ry!t&%`-osq%EG{W7`F=EpajBvXv=dYO0pD^(z2DCszngQ&7e> z5ZP>QZV+592thepg+dT)qM+DjQ&Up~)t0asvtFDA$q`B_skXvfAn|gCWat*m+rEx% zy?6Hf%MM3ZZ#dc`ZEGWs-ClVwoEnz@XU14Qo~>Nj-8j%rp}TV-Oj8ZH)p6iv()O} zUGgQg_Sp1k0b#luRvx3#Y_6^UynB&*6+0|uD zJGR(UdEUiw1GHb~jN6(0@R#jH4;?Vu%p-dAefoH+<%jRrZqISZLA`3Kt<89tvwTjN zbNzUjvxcL>=G-g?{%VAsBMd!G^Lyg|lcvLCdk(@B+HIEY33SRY{w*N6?SLcb&ms2v< zc;zTNI!{>4oT`V*94y_iWQkIX=DcjRduWA>VyE*?>GAc_rwvwqcf>XJ^op&0x88Tq zx0a)JH!eP0f3IVa_FZ}<93Qv2UOrRzGgqqgzk8xy+hV>YbKHw6cBXRH)q{DwcfM$* zY^Zyx)q=0?=03H}cjsA`wU=ZD=m27oYU{fL`CcrTzEylw($jvEr=)>Iy`sk@z)2om3!Q3^uVe4N|o3V5k2ATLd`+FI*#i7 z)@*v|N9NpHo(!z&J?o0|W@6+40`eICA zh2<|V1-`k}eBFt}_Em4X>BrO_8;dN@m;SV^_r$HUukUcPo%*?H_?3Du ze2>@8{$u&RN)Kx8v`xwb^(Id(x?!N}!=>MKe6zW@wj`l@uk-4@GKDYHKfm_atj5cl zMY`k-m^SVEGwBsVzKU$W>`Begqw^z6%^J}8y6LCTA<6q3)NACZUhXy@dOEGUbSW_8 zaB_}_FZ@lL?p6Axrs=2CBL|1yp5d}=bXH$=QqPXwGfLJ_&-uPxwKcKAz$veW=3Ov8 zk9MJ9QsW1dB6lu9Bto!(OLCPySJV?9jUJ=O4EI z)t2?s@;CDOa@f$e6AulZU3}g6)$uEmG>v}Y&;D~=+%(YV&wjI49IZWTSK~Q#%l`1P z-JC`7<4$bx8aU!W@Y>$9mKA?hIkkUa)mFXs4DIm!u4Nf6pX)NDM~7MM{_M6qSLf_C z&5H~ixu2f+ZT#xuvO}HU4o%&@#HA)J&K=pmY}A+6a`Y{kF>mYUF*gRS|8e_wW9~I+ zKI}y9&4sW1*5PUJ@YxBD9gB0+N!}wxT$18dPg=aqb-UL%cc|~PaNj{bJ&RY${&@Q5 z-M-IP;gdMVT&Rleh0t_i@+XA6@DiyyN3yk;?{*i@E7- z)@G!5jc;$>5K-`lm=#C1OzTl{%=+HjyvE1O|MOM1c5z3ncXZ$xwidQpf@s6#nda1>u7gL&+T9sm+-@aXy`aR{X z<6T~@Z$0wLwaRU(+$+~D`a;J7fm31@L`*#K+u)$Nw?52M&*$RJN{x%GyY2VgQ`0;X z#rxp5xWWOa%Y?1n{5&FW-g%`bXKr&Rr2XNLMrK;F z*W7ErsqyaPVIN$*;ZAY?l6Mg?@#|+dk0h3VV=qicnj0~E~cKttiFp0&5ZH8hpEqC@gC-k%ubnx zj0yh4#0Ox8{)uVqFyF~U1!Ar;mUlLFnD9rK>oN(CFwGq1lFZC3n5vI4%^hayV@!=8 z%mbO04pZp~=CRDOCzxo5xi7Oa7}M}6&u-dGyHKHqeqdOWpH!wvRw8_!5fNkRJ>#K{ zZ#KjxiT1|v9I-_r<~gFH*(lK=JHr13qO*y9fe6Tf*eB7|q<@LnFVXiUqPy9HaP%;N zuLydYo(g)I0}6U4gi!N72?P1JZ^AMD?Pu~k2>P4h3I>?73I>`mC&3^yM!{fnQNa*X z%9~)QnWA8rxuGD|RCE!kn|lgAGBte&MwmqkMw%xIMwxoaG?dFvIX5L^C^y5~ETf63j7)_#%kN)CgmSr$$5-MO>Ab#XF`D*Ci7C5Od5$iJ8R^ zRns8mnJH-yHNp@NBo>&8X%UYlmZe23GWR4_h9erLLo6|i(jl5eAbipzmYI6#5x&I{ zndG0b zVxzez5gLW48i@GJObJAsk$51n$yCgOh%bd$mIbld+>?lU8__TbvDGXJLR^>d2}W!; zs~FRpnWYhaSrI!;)2xUZWe__hzBDPaAs$O~&4$=xwo0rli^!TC@s;VA9nqv5;;_U% z6PN?xTOKhq2jW|EKw^tT;Sj_DGmzeEI#fWMlQ?Md=R^clL`=wuIBd>J?3XB;3vtAZ z$%PnD32|HEm?@PT5n35BFE`?Zxgl{zqD~&fDKje%BEAaZg~Si0W?n>8Rm9r7h_mL2 z#C3`0`4B&uRrwGzt0DYC5$8pC05ozWG#TWY&sS| zG^vR=EOFHY7DV{gLJTd4xMmJWY>_Bj2yw#%% zMA;&UJLV#jGBcnKqH0mZJu{^!BJ^Fv1BpLO#bSsv63dDq9+-O)@pTam!w`?mqA*0% zdkCL!#1m659C2M@lf*OQh(OG&hlq(lyf7OjYP^r|FOGO+qKhLQOYB299Zr)WQUj6t zn7)x1Z>QNS)1(0=PYH~V)ATBV@ok7XC6nA~a+btwkr`DIlfr3^%XDajiHyRea+;5# zFaeD*S7rR1CcG48zf3|YOj@V8Br~81rs~_6^iDJNZA@rW%mbN>PE)Bg=8Vj;(infI zxi1s{0j6OYOlGH9Tm}=>4C7N46X-PWm&II{*(4L>G|qCEnIB?e%3-oP&8IRonq&OS zW3oF<>++b#GW%pgXrBt0l`SxRD`0ZbJ~B;OV)9hPeJWwL$c(Cl z$xr*pbcn`8R>l;heJW!DT4S!t6sCQuVD`%-RKXObePjl-!Bnk^38Q_gVnW+u9>_${ zKGiU1WR_LKMAAMo@iCZ&)iEV$pX!*Xb{L-;m{PP)4a{|!O){lvpPHDN?J+SmF=c5V znHn81{e4*TeN0qOj8A<|l%}R$eVtnpn{$@TN3*uqD}fnh?RX1eH$U#m^~6r`Xcf)M#Pw&jS;^6 z5T_*Cn~)}mEfS-eAUc|35*_*@BAX&Qo8e6n0Rs?MCAylh4-oq$5Mw^f}h%FMM+91Z5V-g)cLPWMjj5EXAA_7Jru1ZWWVKIpP5(zPgN#>%& zfRTu*?GRJUly->FQHTc;(@e$oh%*w)+9MLoJ&E{_5e+*aj9JtH5j7g&(-ASt)a!`2 zF0n~sj&XEC%#26GbVAHC8zpLtLHKt@EHKfX5sxMMc0nvMd%7T2jz#3@idbTLc11K9 zhd3p%%!G79_>M=6>V{Zhj!A5hi0qD7WrlZ0beMp+DzV0d^*{tnL?rY;tTh)U_DfXl ziCAx@^h6Apgm@sa(Nye(2%U^r)(i2OxhHW(qG4~uCbOtFB7O?Orw?MYsn-V)H5IW* zVykiVMO>GN>5JHIHcHH#hVbu)*lD8sA!$nQ(!Wt$tRczlQBNt=0_RdwV1L~Fv-2m*eRGTGPh+?c$>GU zVmhqD%$tfylzeO}(gQ#y-twEfT@cRVO&@}x75x*a?Q=+j+u@(_^0MT_V zqN&*`aa|(oIz%(maUEjjcZkCh%}wBXM2&-pq3aPX%>jwW5`{M)qRqe!h?R#B=Oo&g z{2LKX4kIRPM8uf0629Lf%6^JyZ^nFz*dlRTqN6GG8KT1x#JtZCoy`r2fTM^ypCh`O zS)U{JOT3WiZfb5q3^;~Zy9v?LJdp@Jj%fY`qPJP~1>%f^-)2N#({wW;{sdyDM1PZF z3nJoN#+fG) z0Y4#{??Fs3tM(xFOZe?YOfnt6Mhy5FarkS*6ce})5qb_WbRS}xIUsRHqVP9}1T*j( zMErTgISFI(e~XCv1u@}U#4K}G;<`lH{fIec%znho3y9ki^GvA&h#D6W^9~>um>Uw0 zCF*>KSY&2>hgf+D@j_yWsd*65#C9|01Y+hb#BGV4rqoG9jo%RS zP9nZEHzXcQ)H#LNV`iN~th|kAcpCAQS#%oF-K)gC_bcBH$ikpTuF4{zt@qiM~G~j+i|X1MVa8{De4Wdj5n6{R44I z;)DtL8F5Bp)X#`h=9onMpNPnFh#$=GbBL%1h^rE3P1t$Fb%})Yh@Z?wiJ1=(RewR8 zGgE#+)Odt=An}W-cmeTPV%Y`6MRQML@yUbICE|+=#HldHptX7!J zWt_hgCU=<+6#BZ%rwUWJOv*ciDP5+u!c;D^O<`)6$#9p@&t*C(Oye?p6{dBWEcXc0 zxlAvG>0RbKg&ABX=Y7JAE;C4BCYL#`(BEYW{6YAZ%Y39Tv&;ObFu-NP|0E1_nXwA9 zxXdMmK`!(51HxdJnW`|W%iL6$&1EV*B+TwIvlZr`{t82=|0BYj)L&sP>aQ?2^?yv5 zhx#kbOZ}e^=A-@!L#e;Q{M7FmVFBu=upsq&PFRTgDJ)F=6c%xroG%EAQa^>osGq_x z>i3c`ocbw@pneLAQ@>Y)kAIYLKy^Tg@h*ipgM^CqZhRw<}t94>;&rm2D|yzJfkpkv(Tp+4Rb-hNN` zWyv&NUUBYlbH#F`nAW4BYjZ$K@1+jEZT#*nzqJ$hHDQ{>*c5ehdVEt;*w4GP|1Y`R zKVKN9U+C%7yL-1t!W^52`gx~yI98hpX}l|IR-DFrL}1l|?q7M1YtyA;kxu+Hp0?Oh zh#$B!!+pG)Y0oL!vC0pd#+5I!xm-E#8Sdhk9_hV(eY|<=YKqP2t9dtb@{vi@{}Ny2 z?$@Jxmw{b6c8lrB4+&=6JlxMaxn~Eh{Jeb~zid8M%R8-83C;7j*yBjvWtoa+{@x{h zrZ%L?|Ia)BPYYYjz3<6^?0ZvBYu`o9A=cmeh+h=cky4Yz^lsg^W0$sG`+BL3c6qAs zNf28l8_fTWYpB;B?wmFRd;2bp=u`cVIFVaz-&uB{lncM zqC3Y>WG}Z<1E%sc@ZXDD-(B3h`KZGFwN^`4cPI3_yoZLM;_rR^e{lr<~~PwH(&~#1QG6rNL`App7}VuGU`~m8^@N9Qpc#x)@xx&dnMe@ljFa!Jc%)U$LBt<&1n~B<%rR;I3Zu#bDEYM}BeZ^}XJTMh7alg+#8de?IJZQ_3^QT1=OaQvHdH@Ca>T6gT; zRsGbjtNTFsd7qeew@T=14gEit?SFq=`fr~9ZL|OOf&cb_|I0oQ@!xCP|9brRe|dcV zyRZLV5B}Q+{@Vxs+Xw#J2mad!{@VxsulhjBlmX533xCX++nJSFT&1$UeC7F*yT(tw z>FeBjQ;Gg~L>}bI7<=8)1YQ~35xn@%a>|V7dG5cPmeU(x3R~`$<@7tW9hj=??>Eco zSE8Qi$2a)Xn{V}KL96YopO3oZN#}XZklwSTKl|0V`h{@)nv(wXnq2;Kzwr8!_Qc-< z&&KXo&Rw+JL!5S^`gO6~V=Em`-nIU2UwFHtkgv`Fn09c<)uR4T*K#hsn^((vM@U0UCd27SWrh*f zH}Lh+UoG%3jsEk)O7+|>!*2dX!A6qVywQUaEV9V(Z#42BiI5)&uF4)>Q4{oUCvRW=Lu7~BaSuP(=@9xr{-hQmYgu+o;L5-8c z#s1X{`Qee(LG0Hd7r@=NoL-Hrjd=j>^}uquEvGZ&j^*-LPG`t+%jtE>+D8#6j8kXS ztCW>rQPn@pN|@i0#c+C2x&8`RE{x>{q*JdgXt{8fd8+9CD`dF{*6jazxv=GU@a}cj z%C87ci+ad^p9OdO>qX6K>JsqWN*G~n%$o_l&Rb6Jan}B#;4DtPJJNEcSpLOwB`o(g z?ni6el9nrtYi>E-2km)m)`6-dW_UX@h;Vo04XRjiFGv+S}G>V?tTNfmfRN79*5-Evh~ zPGg-;H7r*R_sZ&UH7!>i=VPVQi>H-e4d^SU_J7BcHCfirWa(6^ZMj-354JY0gHwaN z1NQ65>RPTgZn)Kt>RH>?!F9B@ecy8L;;LG%J}y?JsSC9%saIXg={>J{Nm@?AhL)?x z@?@)a_A9U7$1Sj&{rce9 zYP7dpbCz`|^w)_{8MXlXZN;4}*Alm!o#@QyV!2i<>#fK-GrHnbk!bi%nef+LPRGAB z9JXXnYvVS!?=9EMa&2)(EZ5s|F}QCn*9WJaw1ZMw;IE&Ru06|ZL1$2Z%XMHmwj@2h zA`1hMYK4vvWx2tY>x3(1xnb7EopEnlPB$@a+Xa&2^!JgKt}DxGnJR=MEZ2?YOrHK0 z>owAn-K~T*2}fD32g@rx3B5kH93QN?GgJp1ZMj~SQ^$+9TyK`2&@$?HV=UK)iWpXIYwhnrxz0XV(WR-JJoPOUx=o>61{O~$EZ z27!K0L4VV%ZTYOv>sOtBI)>9NIfUhFR>A};!=bqCpkrt(H;m;EXlfn9S(Z~@s*CGL zILFE_j^zfHn`@;Tj?+u>bXa5OTk<1T^r}4_*M-)`BUpY$Vbqk1EH{#6HLIF(vE@dw ztd}>d=1VO1G0U$kx72c@aSmEb>6Uq1tXDiMxmnTQax38&mfNY__*-GQu`IW@+)B%h z!~IBM)V!-KH=bn`P|dsAauZm-iBs#Y!Ratfgl7(V$4C~|S_vnytXJXcZ=K~Pv#eH7 z#_KINh2^DIVK!K9Lpv7u>od^2oyT=4wkXTRU7K8#&7(ziWSJ}f`;ntL8Ehx#;?#YS3#rj%WwfMf?mC=_cv?Q-4!~+7+u-M(asun zheAQnYpwG`0pLfaz21UM;1A!^SM&ySjlTE64$!Fk0PKRD@HJ@EeGtBbL$Du?fJWZC zVGj&vzp=6WGYpQxanLaQBn*K;Fc|tmcjyTklD`M_;C-kM4M3yv8t^4uU=QquU9bbT z!A{r?@h}pG!$%OS-`W`i!?Xe#%E!TI(EnIl7xaHm>-VebLmhY*>On(j0C^xM5rag|01epi^C^rOuGy zpbOhapzDmzq7`_L+nshJhhCT2I_XM88GtfLn^OjLC2zr8E z(c2$JgXS;8L35Uopm|C>Xl}w>#69)URD-ESta~oeos~YIIYcKo#!kZs!yzveg@JV5 z2{0bUf!@ZQKzI$VgQgWXKvRj|;T~uTp((>FcnW%<=`F(F;3oW`dFewI{)Ff70v^K? zxDR@(^-IuOy?24;8jE2WEQQ1HJsbf|FN#70Xj-uqw!wDT!oHi}8$mP31GynrEdOMI zAjk&UAsF<^`>ddO2VZ*d(obM$zOjzeZar*-G_3zbcmW=={0JVyCDt#)6}Sq&!gZKV zLFPdM%!SDiJD-1Mz<4k)1s1>}mmi2MEDzM0`v?t>A44* z=bV8{p!v-$_!Tr?`N_%g|C5CW@C2^FZFmSz;dl50uEPzu12^FU`~Z4C(^6Oq8(96CZPC<6M;8vUwHAziQv!YUH3fF-aLR)Q1n4P{tf0J>@F zCOHEPOa%>=G>Fp3tOjT{RtYo%OG*Ek2D%MjCeUQ-W7e;;d;=ap>_h(f1J1%J@a5D? z38}#kQh{b)$w4zNC!sfJrj-NqO6y->B+HsWMzHS1&L*oR8MYF9ta2I}u zKR~ms8*mH47!!qq#zvY{b%2hb$&@Bfnk;E@)D1Kt>H(Sq#cI-{NscBpeL)i$OXS5h7VG4ke+4o=eT4`83a50ZU;SEP<6U7UE$H=tVCJU=iq{$WAic1z*B$*aLgv zEBG2V!l!Tq^pj+okA4H1f*yqL;fT(E%_|Q;b`ttR3P=g(a5)GgpePiAQcxNqAqt8^ z6{rdusNhEU0zQXNVH11?YrvoU_^O-xWyE?5xZeC7TY`U5(eZo;lY!=yDIg`Jg4Ey# zX(1h?hYXMrGJ!w51;^OIE6{vXZ<}wynWLA+XN4;)Ux#bJEAPE-z&8A1o&U>N*Z`V; zMibEny0QE|O{}-YFJXNtEQ95+5>~-#SOcHHT383`VFPT0v+y zh0k>V|D1(Qa30RVX*dfNpuC`Is}a_KS`Y>IXh!{1-e&s3Hh2!2i#~Aib6;{66>wzJ>j808X&YS@Jjyf$#zj zkp3I^PRIWsEG5x*h?Rt^VGZnoZO{qd4vww18-+&d%O}#ZZl%RtG)F9Ze>q z;4V9Q43FR$^q>%WxH^QmT!f9G4Coo>1mY*cBq+jqah?BqfT;(TKNJ1}DOk=986XH& zkkKl5A4)?P3Z>(hs9|)FgppWlTi(*21%FSV|^}ZR>5?b0ar+W6)wRA zI10bQbtpq^^<1k76=@23o~7qk^&nOct@Mye&!oyiImijh{4HvraGn)vSx;zGi*giN z>pxQ9on*cX^lVDcq8vCqE>b!@4*Cu3G2*n$2rgui3q(lV0$Oz>iSVO-(@@-~)P8p{b~*B$}3Ln3@7~ zDN#XGs8lScgtR)b79n(&>St3muGKxr9)qYLY8@4>5Mcobg<#NaLj6B0C_WouK5JQV zc|cB;%1xLHazYMJynKiTR(U}Q>NhE?KzUG}WuaYZ{!zxIpp3O#fv_@Egi2Oem9Q4n1iGC2aaD7cPqO?j zp(bVOUz}He#h+o>6K`sja}|hfKzx08AL_w-pb4GwYsj(=(}&OmbVwURBlrNCLNoY* zw5cnFc1bnf9MB&p%3(iUeFVIfOa>Qa16wQzKx+LXEW3d z7a|sb3ha@dlYT1e6JQcdgvnMo#R}!rVAH^EwCOC*hj}m;=D=*21v9~b_VE{{P6by+ z^Iir1N5WS86T656tw^B9D+^&c>q|flxD1wp6F&>4fgZW&kxT~ABbtw46lez{2}gjo z(^2|}W#u)TFb%}P5XcR=fCm$??ia&{u%dxtdeA^I6{H1CIvn5yugK^nJcAYR5V{cc zC*ex?0@lLkuoXfeH)Mx=kPWuLXRsbtL5L2=CoHUkHLx0#i8j`Tij#lc<*?$FPH8>` zEpLPkkkdj=J6GXUFs z0{2+H3wJ>IDZN@E7=DMdp!`&j*xUT`8>mFe{AW;8X$NYqTd)Ie!VUNej=**J8h(W1 zkPFljs>n6?71Y#M;R@`9%Ww%U!Ug!n!SO%O!a4W}4#1bN4U*PqJL`6{Wo20f+66i+ z`#}ZX4d22yun$zYJ)ks-R{`w9s7h!#pN_vWRBa`+{CcPzsA*LQwUTPAoqq@RaeckR zsjvq@d8xUT?+G-RLs$JeU#AyfWR7z*JfI3*x9VJ~?N48H(dAk$S zzxc2UVfRplY7ILh)mq0+PRr_CSHO-}rpi!h6sLj-rL_xZuPdz%pIvyR*`ecqngzR~ zr~vBecB0ppb-HQic5Rei8R;z1HVPlWBX|mrLHC*`glh>?5au9!LHHa-$MTPE4$BCI z9<}I^i=Ol9va4slKHvgxP#RrI{XkdA)Rwcix5Gb4mytMKrgbx#1)7Fy3NDuovO;WT z{!syf2^Wwkh%f*&(F_DV$JJ*&dKQ!elxZC6+D6xWWtOy1c7a9^HyrdZ`Xj=@go9up z=n1%4bjjFT7u?_ z&EZ4PBlZuVDd>@VV`u~o^|-wO3-zHMya#pRU8n=Kp*mE9s!#^dX=DGENF}dfWuoO;@D9`jWv)!^T4`BvN~4`>T|2fbVds;y5Ox6*9qq5o z?FV)&wS6DLqoq}#LoH)xl(c!1F5B^T7{@l&fcL;-GA3AO0TqP`C&T$hq7Q_!R*i)ow_fxuQ(k? zlV&W8fp{1PlVK7}gb7xt^_gH`226(ps7M|Q2CwRa+a4u z0)7eMVwl6SuHma#UIr^b=~lvOxC9sB0?Z&?7xK|{WC!c|h;9+#2G|bDPdBBlgt1%r zXERJid`9>wY=rgj39N&)ppA9SPx_~Ldq;Xu`MI_J1)&PD&05zzOtkzH{0QgZ7Tkm@5Kk@ambk(Cb@-S@L|5xg77Ypdi1WHJOd?qK-ik_9--1`$A7SVAO3_YxK>b} zydJUs5W-k~LiiY-LIu|KSpNmf&%wd6I%BLRYL$t6$%@1)(DBXz+KHUvT%=0{Dx3CazhqS zZSoQ7vw_!rMqJX*3zSbTP%qcEIwb=L{XtKRG7)A59rm~MxIK^+ZKR!KBMgQh$ZCbz z3Dt2z2=!QAY4d+RG}iUAebeE(wL95afp(vHVjI3P2bXgCa1642!XY zqAY9PA4ymO^pQyfgoB(Y1yN82lyPY&59OeO6;>py36-D<=!1+J5L?|^(I*Gxi5hIz-xu(heppOgM-zkWiIUVO1y{;t^o? z{Lw7ufLyRk*Z&R)S+e)8kh$4DMUP>7k(9&I<(QiB15;VW1LDugoC21=lv?*%>M-bJXLCp|OLj_U{Olk&fRX2m>8=0c27M|+&R#Wl{f`)38Yo6?Bf zO>za)k&E2xu#B|Saw<8@6?C6&+bpw`vt zs?+iPr?*&M25MrpoLch++r41f9v$n`#3ZBRSof)*;jv~U4j1D9 z!ZF~*^5=L>FjSyqtgA3Sgf8%g&cwZb0V9c5dg6RRA5m2Y6*?X3sX&KGX*3p0sjpk5 zK&A%!*J3|7Hzupi&r&j*D_uKe_n zQhC~scfV%+SSceIgG9zSy0Pu&m1POvjlbPi_pf9cH z`#d=yI|M=y=-QxG$ilKZxF#@JS&mgEx>5y$5(TragxRh2Y>EfPDKj;j)-w^WbjnPp zo(iN6sLrZFC@v?Vd~U^A&Yg~BYeXIE{%YJBGO#C_rHCvIZ-YK2*LoCqz8=Sjmt}oj zE&{?qUoIMW_Jfp&XQjGYiy9_`5%2^RLZZzd18!VDS0% zq`8e=rS)I#bhIc|BrLK>gx6+sq=hRmQqRQwNYG*6fn85G{c(Z>kxCF2sb~ACh$+@5 zy8F7`(b*GYE}5(?U4i_jXvvnY_D-kMENtlt;59{_^z(*g+dSmvur#C(D-u?$NHMR> z#PFqqxZPcL4IUX^bDSq8f7VtqKRQQXaz&CfU;v`dlVG@UVySl3%F^1W@Qv?kvrW<@kP zxwj6?s6(atTwggh?dj9WdN>`qP4d>R(*LlhWbQrvOMa!z8nO*qLWfF2M&CKo|5$g; z^{4KJDOMz$d5sAh=E`LLXzi-cUN?@U3@c1@8+WBBk-v`;c`Ea^+R3YMa`z*LxVL*{ zZCGK+Prs8@L=iQK{ssNiab%uE5NT zNRW;M@!OXl59oiakd?r!ALjB;Vdvs5m;1PkF(YCq@N%;`##Jyyd`hk^+P@iI#3z$^ z731=;kHyh;9Q6p3y&cV6j_#};T|50d6IZ_K?xG%abajQArhYs6;Xig%cO%X>i^$<` znYw#drUvfljnqwTT=R}^!`Z)O+30kv#Hf#aNvL{-j;npQ$AtC{_Q~<0>w6s`CV-fb zLwR@J{yJ4KF=0h04_9GRwmp^m!1Qd-KDU^03fw(0vv)DCjpj?mW-x!Wcg-PoQU^}s zlW9G>yY%7p$(0s9oR+wobHva*as5iJ^2wIG!9ZdnIJMlnImf0!_eh{tY275{ir|W~ zf3`NI=R7y*JGug$zUfS%j&uWm>Y++5xnHXDr>#CLp|jLem0YGJ2_qv&ke&oNS8b^F z)1=SC+`Dq0o>hp^WoY9s-^I--gNR| z<{}9k)6FxbTTMFd4RL#Om5HqON7^jzbdkzvpDEgj1g{^$bdLEHi7Lj`Hy5+}yk!P< za%Ckq(}^~mZVs{yufbCp%*#%$;z6t4@^sj18Pb0_HtY6s?10A74&E|#I zczi!)~R9IA=i{I1PjvM{~7ncTGqAx6h&Y1@`V7uW92 zZ+~(QxQ|4*+1ZtSR3U+m#JyJ!nv5^if2r%QLNqn^NZ{yZQgtKU2-2y34gJS``thh@ zQHkkhnersyC&`<3qn_DKJzt*)v%8xs3qSlj>5(hKr0LG`7?Z!dE5hlM%j~Y=6X1Bu z9PY_RdCipW1l3LX(_FH5cXzph+U4@prTV2VRSWFdypY~ zX76yX$!6nm))(*s7FXu1kzQ-qQdOzopJCOdQqy(wqd{qCuiYlPhpVdNxLMJ|RXV6( z9?vnK+CtD0?6K1iOmS${Bas_+p>+e&Ne&B8q|75g}opsQ^-mF>__Z;xH=9rpqjk%@3lcRT}y{o@k z@eQpL7H+kU8QI$|#Ouc*vv-77YjdY};$9ku6jX|!y}^Bn2LQV>=x6k zFJ0HuKp9^zOgcwSv%RmYq2nEsz8|SSFa`T@CRa6USqplPKB22*m9!gH^qFvUEW5QX zAT7+re&kxn`1j{t^Nh1r*X5M+F8(+&`Q-?A!QD5bfhPK@D^oJ}HQKYBqnL&zEv%e} zBx^pW?D%Ef*uuKShnkK3DM&YSkRWI`Hy2%@3KXsJ{Bg5P_eodMbHw|aS4tOWZl&=l zWU3C}YSh=XA3&jUnK=X4v``7p70BmWLWyoO*QIv1jQi?P(i|D!Dwu0H39^uPnS!2u z-2HlJkGVe_I-!JI201_8FyOW@udRWS!>s4_r*lX_2W%0$yP-WeCAG6EcY4 zTeCpYGw?9S2f8w(I32~von8H7`fyX4&4MbF@*K%_mrDEB?0zlW>EJ8~S8Fve-ANGH zg#>|Qa%=F1OCBsblOZv|C}K3IdEfhm{}*4J=e}rf`fqmV@MOzd9{!;YR*n8%v42eY zA4_Lyr}<`xtDV!Uj43kI72r%+#_Wi51$YJ`fsRaO@KBoVw&^*MlPRJ|DX$Q-9upZ} z#&emETye3*y$ZYcdXA4qc^pr4Gbqgesu1tX)TqSl4cos?` zt}$UnqP+4EqkH+tg{@AP&6#`{F~y4%*A1{NF&b|z+?uS^fW<3rC1%`&7#+lIF`15s zq`mvn+9s^nKel1fk6ooRzCJxjN2{tsys>T4ISRO^vYLmfA#y~jOtFsU3)R?MaN_JhPX=E8dP;(L%9Jk@K|Qjj^U1& zY_zM|Uu~0#UZR^<^LO6&Yqui90LoOXNGXkwpPKHYIUiG2^_=p(irf!x^QzGXcLJTZ zUO^^RJlX9S%?;L*m^;`#wsCl39K}rGu_P!LPlEs8WN2#l<<}n`r2A_y*}i)p_mLa_ zVZXa41HNoSVbs$&d;|K#bZbjo@iUXoKRi(_4>1~#aP-Dk_cAYhd@{!-@O(>m?tpBS zn&ljxf0H)$47L^#qefUU=5|cp=+NrKSi`V&#AuXXBwPMTpFBU4l^AXVRNiYRG3khD z(z`;6tqo4U?as}8PdiMEu3+g-UF+HDN?3mPHsM9;vr+5l-Z6zs6!(f>)grc?|FaNx zlzY6_HKx0sA$pnG_X~EM7pRGLDbL-tS4`WOZdCha$vaItY^|`G80-H0XAM)~vMW=p zdeDm+p8NiR60a5&X&VzssxbGB(<^yRPrq*1_)xu=--gv7M)z%6CIc~Qkh1NMwjDCM zQ*L6o$uXAo%0`SDq|L$PTfF_czewC?L1NUqy12eN{mZ%?8ZE?@U>iD2DJ!bU=7G2F zXZ*dWvh%cWbz;NM1wZ!Y9=prWpn!0F$)*E0%D_k z_3GGeAjhwNhCP|%S4}4kT~Zz7&1X#Kj@{Z8?%vKT?|{syvS&HJn{Bj5hKT>z5j|Zz zx<}#etvh+$>{#H`yA_X~v-T6nA?fty8a<=(dG>bZ)=5((RkyUfwc`IL6&N)_-zZq@bbqWGMZhW$md4i7BRWJdcv= zd2TfKhpeseWj*J|#Dsg!?AQC3JI38}Uez-b6I=l${xMhT&&TP#dUfwrIA*}P8^6Z? zTqI#8+lG0{&zvmB1cq9%@0$;Ax&neHzwg<9>9LD{4i9;<$GsQL_r0dnH{D2SK0V~h z5L={yr>FFa>D|3czZkF3uw_SruJ?W9&e(k!{)g_YURInYdt-P0$CD$h1nu%I`%6iK zjo1)#q(G^s-R=Y?8xW4OFlUmQ%@aPJ%qCM<*he9*3iFw)^&|NmyOMZy_cmu z@|D%wlx}-tFSEXyPv+Xmn|Si?l6rgJ^)-%umzdR?JKLMC?WXp4SFp*Q(kF}e;HF-t zVoIOPB}O&%oO5;i7g!K^Y`w-0Dk_8i>BMB95@{;TxEVCKeiLG>v+;gYvv3=S=2=tI zY968Q2WG=Y4nXi)R~BdU56tt`tn^yUlY_d8Ts~&@0<^u&^$*O^1#CmIVQaLl=cIDp z`@m%5hcxp%N(k}0 zxA;ji-cR}0DQazG-d^O&;yt&ymzk8(CoJ{=U+vJ9J^J*;>h z{BXTvW%9(ByTs_4U%OD=&z9s333oa!Vs!m_L8wdVzAQa{cu+2|O5!%DT6%hC`?t%z zd$RX)-CJ}ijpc|3Sy991Trl?woPS1?o(OS;C`e3tvYVgDuUDGUAAdoNZb;lg$`F&0 zm~)qYE?WCRG0#oRUF^D6j9<@*m9tzP|Cnv8D_m=0bp1^mc)LjC%*IhFLK(7SMAx4v z9+$;E{^aM8A4NvRTN`l*E)b(fVnt7meK^SX@uOULfr+Qg{p`!`gYHFH38N_UB< zJdN1SbJ)7(&(?bN^wxEq4&C>u#6R5~)F?z{ZSOf1GIdKG9NVJE8l6>=`!))gb|oc;Y7ST-s~b!*6%F6S(g()=2on zF|G{GfgMbbF|Hg8c>k9B8%E_+>p#rh8clniWxQpYk9Cy{YF)rHUTJamZjpBvW*I|? zm~odVQqrnh(El{L=dF>N5(JIx=sEG`emZV^SZW_V*tG`0yG__Q8p(7twa0NGT0=tJ zPp@pKKJ&9ZBXudT#?YU4G;!lx;nbTCk}|s@y|Q&S-y?$CclMm_KYr19ZRUZ)^tjaO z$pbo@`QtfHtlO${WM^}Hyeqs!R2NTYT@%t|@zYVSa=Ulp?)z1V(RJ;&$F0w`%;;M@ zF|QL{Oqzl`@byeYoOimKyWB&A|MAm9Mu_y7t|s?HS9s8rZl0>AUVZfF+pf7C$dWFl z^T|DB33S%(ZpKd}tC`(B=iOZIVbg+}eZlq7uKMEcW;ZEHY#>E?N>^`0uWxFtY<7wi z)_J~%7@aWZhR=_#OxG?U2vqn@5?MDeM4N;GKv{RmQ6pFvLTX(~-} z6>u)=X}V2v-PKj4)nr=jUQaVVjEigLY8u_;vTJyK+(0>vuL zZn->4!R4Hdf5yRl_>{?wjX$Vobl@W|+1eW2Nv-U#{R5$Mi#qDdrNRX4#+oJyY#^ z*S(1`8+w~VY#aQwm13{g@743(a8^i6ai;f-sbv0}m7qX|P(CBMyeKh&{!apB-ukWQ zDbi-o^e{0dQy=rLwhgsX?0*=SeaO;=(-KpZAx1Zq`9a0Dow(8FgT$D6eau|84Q@{g zO+x%KSGh5NUB7P=Qw;56jw;18D@B)9i(j3dvbADjidB7#Ynm%Oa`Ir$AuHFyx#Q#= z-(TE^%-zrDSuuNK-@VxVm+dWxQBUHcJkWHW#z&K@Nsyi0yFcd%bnYEu%1mdUCx>`0 z2z#4k%~E=QoB2)$b3TH-LVoyN9`Qwcn3Fj~k!(EaY!lg*!QYdyu8G z*ibWex+~84)-aPg!ByL7owTM`0;8ZLXYR@bSGaRVtofM%a`3iT&nHT|y8p8LtA$sY zQrP9V7;DnapzYJf@f`%p(cky0(87}vW+bL4OH6KJ9)Hv*!{*aFK1+;=jx#OTHgXgx z3X`JLv+09(2Y$mtVCz)z`ji;1iE&e}obJEn%z=}M+qyp?2;@O49~AsQ1fI_o%xdF` z3Z5{^a}5kDzckN~5$UsVaQM=J&a@e$%u7S{7n4GF+w-?O<^8F)BbpS}qw@8mO!!P! zfs{K*p_yjZkIjZ%6zF3UH`DcfwGv7exw<16N<&-FAxq8fW6ZtB*G0_tHrkjW*p# zSt5p%=}7tYg@wHqw7ef|H4QuNOH6uV1|N$0eAI*Abp_;BrOWKcqs*#(x9J1yO$Roo!>yFcPX%M?XoDfoBTk@5AWZ z%FAhO@gJlNu_i`j(qmDQOzoTok2e=oYOA!tlg4{`NUxV`o}RumUeEmWSc&>A8E;ZA zCZ%WAl^7&T6g_gRLE&3f}#5{m;K%>fWI{n7IAv4!&0)?~~b9sVTsX zN#>FR_A)AzcCzOzJX+#6$GZppYgrqUZSKh?juc7fymqr%)8Z0u zo{X0wTU~5!x4m-XVf^6Q?rh!Ht{Rg~@N%-XyN7j%f?KkMPWH5}`IlOT2gkX$a8HQ( zPBtT#b6c|7BRH0n8og!>ei1um^|b@;l{5KNUQ7j+03R$ zhPZZDtU_{?wVx1pdih(f;&zvDKA3FAucY{%6E~oQbBgDz98kF6tsw=nT(|O|zh@*y zjrL2oD|3qFI#<9dNin`4FvX-<#Z@ef6smf+&^ya6JU;JfR`<~0ZDRCYsz%Eif_?OF_V@1Oj2YZ#fh8!&s@$@cfFN@ zlC8FK&r~t8Qs2EteoBnlGsT?Owr8wueKPdfvT#l{yA$$3?@eMAJ68n0d>il&yvrjX{^u)%xum=A$%`>_5D)nc-#ns0R zwn|EWwmL_NUrC|+j{n2~AurD!K5vyLjBjg9_q6WK=yg72`z+VU-zsUN>E;l732sk{ zbZqP0u>aU!X9Pb?+}7$V!Tqf~7S2jpBKy|ycM?9LMRwXYlYWz}=H`s>oI$76c1 zW!_XDfm!A0hHYM0z(IPQ_uCleNNju zwcFI%!fEGdA09iMeV8VVH_p#!1^bF;)z$gh?ZC|a%vJo~TutqM5$WaW5B@$}D?E=i z|LPk5Sssb)W#2(OdE42zdyZXtyHh2poqKTdKgHYkR6CtI>voQZo!@J>Q>T4@Nb;c8 zE}gxJedkTLnN#xh^4ML$zUfrjKq6b(WB$sPpd2z#hUNh&>8oAJv`i=FJ1XE_6Q zGX0xPN?p^e>6p_B&3SSQp1i_yBf9&n|AMGd-5ZgO^_laW6(-Xz1|FwKp&Mi1{wXQW zjoQE?X!qkft~OUzm?2DWf*+A06DiKd=Y3hOS$vAbqS(8%r*77C%juaIh1*5>pF+>X zC9|uf7j?S3hYv`8{gS7jr9UxGzvSts=L=@0=x&!!@V`FhpiTG&D*wmhVDsK?n&aC~ zJoTBs){NZkYLW8OwVn}O@^$97-CT~ct}{8EbFzG+$ShFTv5l^dxH( zF?ygs^3|sK&jS4Qv9#6nJeTaow*S+&F$0}xHkchG3~s!^lU2x1MO)-+5ps>Jtmo@i zO(XyLv8y`tb+*+w=;NB@-dXZz{EJNPSuS77V3w|LD4GU)U77x>?i&t;*|nF`&5Crm zznSRoqwhF)zQyW1y>Z3~zN_W=rlRxiM)ToU6g%`&KEY+zxy}Oj%+&mrgf-N7s`1JTXz+zG{EQ|29I*)&dDx z?`)a=snd}klM6GHkT0OdHNHJ1-n;%veL!LDZ;2Jt$+v9BB{zLKSus8o<-ljA(AO09 zE=lsSamBFy^QIro-XL+~%%7W9q$pA2bI+5UcEy_|FXgDRA~8iTVv4YB$dwe=e=Xi- ze`3tS&&@h*yN?v1q}V;8$GCmJT+pXwR?%)-xo&S(aq6DQOZ1@>F{)_hP3E~uR$>z$ zP_b>*OWnf9pG&P%%WlR^rr17m|CkhdJ{23E>f#7j{~L)ZRuiKpS<&dghFdEJ-%X4; zy2%XFwrRfbr0DSboDmgA6fT*VqBt?d+4giyiZRtw*VNbJ+$AgK_5XEt8SM9_aTdBRM(xR$L zYpdO>QR4SK&%IA3tNQ%>VV>u?=bn4Ed(OFQ61UQE)HM+xc-AXhH^KFfnFk9=079#9<4xM7`f!l=5tjo`; z{&tn5iZ&eWP{Qpdm?kE#+SseLtz_Ib^8OBWmjI#>L$s~Y@8AW~P#eT4l+;1VtYek8 zZBl+IWC(fNC>eE40ow)N&+W{s^X{~JV5{41J1u93k$_+vZ{;<;`}xoQqXh(awxxhL z3zxljJKbeE{sbh;;oPb}cjug#GuDR7V~4=;!=XubqjRhMX)9^9gCY*26)PZELhF}p z?{2s8gRgB6vvyEAAS{~zQ4bLJb|3#eC2=rMWk|F86(!y%361-B+Te4G-EAc=c2F+Y z_1h`h&mA*l^QP6Uf3iVDql7IYckT~k2KHD!*H)6YlPVqoW!Zq>&U7X0jSr)9;y<)O ze7lpP0AaZah`NBVBnEt%cjycc93^G-c8TH8jFG#7^z9u|^g0)O@c?YgT{N5P#^Rkf z^X*;Y^Ky8{NvvH2a~{l(Lx~?sJ}%d;GyU&zuv%i_Mcc)@sQxj8lgCF8SjBX$srXiD zKx5yw1>LsKZW<40&mNw_X>ZQ+zA$I<(rwPVNxKCtMVuzBJ_^^WVQ z#JmE%>YhFHqC!ZGvQg3n>{Afi;awegvexe02FeHRrI2xBkC>Mco?gFhFZrH?#}_fg zfZHSX(d6T>&Gdcr>2WLpi2_*3u6<${GU|D9@XK$~Fq?@m2vOmz_&(B~0MEYzf&=Br z??NKKyV$CbO78BXt|y>0r~Se=w~IV-P=912kGC-M#5q{?1Hv~pbv@p-N&g8v{Uyg) zEf3IAVD~J$eKCQaebQi%@vA6T9iZQ5;OWy=UKf_dIn)_+X{E-DS2>g6Lu`q7uE z@-JG4@c_-L=qvt8{qa@n$(ryB&KU8*u%ai#_*9Z=CvG_5D+w!#ThpiD%d~E|6^g^g4(q9vPM!N3oarM%~lFzjc)FSsW@rv>StSB{mAWf{MSOhL@kFH zIU1KpW-K=`S|_S!j37O_cCBA!FTUdtElJ3ga=V zIv6fK>?!_U#)6<{*~@LM>95~#_UXY5u~vF=oqw}MJvQt^la1?R;T5+eP_wHz$5`(c zE%#Td`QS^~Eiu#Z{Cu>&ZI6>P04rlz>syq26>+d^hGj@h(`5@=ob%S1KDPzqX6huB07Bt$Fbn3Smu@6BTZ#_cF-|iuq{)EL!q6|%N ziIjS_&=P|>yqMzo^`u|d{<(z*OT1c&6s0Xx%c@yAeP`=cFDi3P<$Z2wr{6$NO!pIR6sZb!qlj0lb}<9O8_DF8LvW#3rgO~ zJFsP!VK5dkKEapj__FgMh2MZl)P6*%H^5EgLz-~|`zi3f{7vYl{1d@T%L-fU)*RnI zlUoJF;KTI^W!%Iet;PSN3pbJFy+M_3!CzrAr1mW!6dQ@5+^1ry=T=PoxUL`7o(KdG z1n4NLRy9!lIq#+&?+_J>6oJP^{nw+YQU3wOn^>o?v-(#dG;DTmRVD#!9_sqHfoT z$-6FX*t7;EydeS@!=BOe+lEe|xq#p)t*C0hE)3t}H~|o{Kf3%Q`cV0sy}Vj1pZN?W z(vgTWftJe81;EnPpWLoq?aVX)@NSb3kkJ>EbwhKfFZ~q7`|KN7rH(g=>&iLZ0BBjNyio0nz-dUDi8th-;ar6LB#mGHz zAZ#((HC;d}Y~o)2zXj|q=f52ga>M4<7jy~`mVLm%gsw>o-kf}w_xfmZS(Pv9_SG%E z_~z4PtV7;^dgW*qK1ff^Gfq7nIC^Ux5sskbRM? zTc7UV=7J5C0JLnCoZLz1+w+%*y=?%1(?cx$W_CJNa(xb2y4{M-yMq!ah2^scI_xQxd!R8eMfea6?g58u78gMRC;~*XwA>Jwtar#51U= zqV8d++JP$GH@JH_+v`-zS(o(RACJ4_R!2M1{rK4HsO5cwo23+0$^AHGi&?bfPG8

D&Ee(9thw!yX{?^u8h3(|fqk?Vd>spa0gf??ACT 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 diff --git a/config/jest/setupTests.js b/config/jest/setupTests.js index 3b511ab6..2f95d145 100644 --- a/config/jest/setupTests.js +++ b/config/jest/setupTests.js @@ -4,15 +4,6 @@ import 'whatwg-fetch'; jest.mock('localforage'); -jest.mock('mapbox-gl/dist/mapbox-gl', () => ({ - GeolocateControl: jest.fn(), - Map: jest.fn(() => ({ - addControl: jest.fn(), - on: jest.fn(), - remove: jest.fn(), - })), -})); - // Provide requestAnimationFrame in the Jest/jsdom environment if (!global.requestAnimationFrame) { global.requestAnimationFrame = (cb) => setTimeout(cb, 0); diff --git a/package.json b/package.json index b5cd6754..cb7182c7 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,6 @@ "history": "^4.10.1", "jwt-decode": "^3.1.2", "localforage": "^1.10.0", - "mapbox-gl": "^1.13.3", "qr-scanner": "^1.4.2", "react": "~18.2.0", "react-dom": "~18.2.0", diff --git a/src/components/explorer.jsx b/src/components/explorer.jsx index 34e0ca17..24699a1f 100644 --- a/src/components/explorer.jsx +++ b/src/components/explorer.jsx @@ -5,7 +5,6 @@ import { useEffect, useRef, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { useLocation } from 'react-router'; import { replace } from '../navigation'; -import 'mapbox-gl/dist/mapbox-gl.css'; import { devices as Devices } from '@commaai/api'; import { checkLastRoutesData, selectDevice, updateDevice } from '../actions'; diff --git a/vite.config.js b/vite.config.js index 75c95ec4..d646f186 100644 --- a/vite.config.js +++ b/vite.config.js @@ -29,7 +29,7 @@ export default defineConfig(({ mode }) => { manualChunks: { 'react-vendor': ['react', 'react-dom'], 'mui': ['@mui/material', '@mui/icons-material', '@mui/styles'], - 'mapbox': ['mapbox-gl', 'react-map-gl'], + 'mapbox': ['react-map-gl'], 'sentry': ['@sentry/react'], }, }, From 952dbe00e81d01cb0f423fa7ec08cffa5d3b7a3c Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 2 Nov 2025 22:20:43 -0800 Subject: [PATCH 24/26] remove mui/styles --- package.json | 1 - src/components/AppHeader/index.jsx | 99 ++-- src/components/Dashboard/AddDevice.jsx | 181 ++++--- src/components/Dashboard/DeviceList.jsx | 165 +++--- .../Dashboard/DeviceSettingsModal.jsx | 280 +++++----- src/components/Dashboard/DriveList.jsx | 37 +- src/components/Dashboard/DriveListEmpty.jsx | 13 +- src/components/Dashboard/DriveListItem.jsx | 96 ++-- src/components/DeviceInfo/index.jsx | 392 +++++++------- src/components/DriveView/Media.jsx | 458 ++++++++--------- src/components/Files/UploadQueue.jsx | 269 +++++----- src/components/IosPwaPopup/index.jsx | 89 ++-- src/components/Navigation/index.jsx | 311 +++++------ src/components/Prime/PrimeCheckout.jsx | 486 +++++++++--------- src/components/Prime/PrimeManage.jsx | 447 ++++++++-------- src/components/TimeDisplay/index.jsx | 210 ++++---- src/components/TimeSelect/index.jsx | 98 ++-- src/components/Timeline/index.jsx | 261 +++++----- src/components/anonymous.jsx | 203 ++++---- src/components/explorer.jsx | 83 ++- src/components/utils/InfoTooltip.jsx | 74 ++- src/components/utils/PullDownReload.jsx | 36 +- src/components/utils/SwitchLoading.jsx | 86 ++-- vite.config.js | 2 +- 24 files changed, 2094 insertions(+), 2283 deletions(-) diff --git a/package.json b/package.json index cb7182c7..f21e030a 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,6 @@ "@emotion/styled": "^11.11.5", "@mui/icons-material": "^5.15.15", "@mui/material": "^5.15.15", - "@mui/styles": "^5.15.15", "@sentry/react": "^7.64.0", "@sentry/vite-plugin": "^2.7.0", "dayjs": "^1.11.9", diff --git a/src/components/AppHeader/index.jsx b/src/components/AppHeader/index.jsx index 121ce613..cfa66690 100644 --- a/src/components/AppHeader/index.jsx +++ b/src/components/AppHeader/index.jsx @@ -1,7 +1,7 @@ import MyCommaAuth from '@commaai/my-comma-auth'; import { AppBar, Icon, IconButton, Typography } from '@mui/material'; -import { withStyles } from '@mui/styles'; +import { styled } from '@mui/material/styles'; import { Suspense, useCallback, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; @@ -12,48 +12,45 @@ import { filterRegularClick } from '../../utils'; import PWAIcon from '../PWAIcon'; import AccountMenu from './AccountMenu'; -const styles = () => ({ - header: { - backgroundColor: '#1D2225', - borderBottom: '1px solid rgba(255, 255, 255, 0.1)', - display: 'flex', - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'space-between', - padding: 7.5, - flexWrap: 'wrap', - }, - titleContainer: { - display: 'flex', - alignItems: 'center', - flexWrap: 'nowrap', - }, - logo: { - alignItems: 'center', - display: 'flex', - maxWidth: 200, - textDecoration: 'none', - }, - logoImgLink: { - lineHeight: 0, - }, - logoImg: { - height: 34, - width: 18.9, - margin: '0px 28px', - }, - logoText: { - fontSize: 20, - fontWeight: 800, - }, - accountIcon: { - color: Colors.white30, - height: 34, - width: 34, - }, +const Header = styled('div')({ + backgroundColor: '#1D2225', + borderBottom: '1px solid rgba(255, 255, 255, 0.1)', + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-between', + padding: 7.5, + flexWrap: 'wrap', }); -const AppHeader = ({ classes, drawerIsOpen, viewingRoute, showDrawerButton, forwardRef, handleDrawerStateChanged }) => { +const TitleContainer = styled('div')({ + display: 'flex', + alignItems: 'center', + flexWrap: 'nowrap', +}); + +const LogoImgLink = styled('a')({ + lineHeight: 0, +}); + +const LogoImg = styled('img')({ + height: 34, + width: 18.9, + margin: '0px 28px', +}); + +const LogoText = styled(Typography)({ + fontSize: 20, + fontWeight: 800, +}); + +const StyledAccountIcon = styled(AccountIcon)({ + color: Colors.white30, + height: 34, + width: 34, +}); + +const AppHeader = ({ drawerIsOpen, viewingRoute, showDrawerButton, forwardRef, handleDrawerStateChanged }) => { const dispatch = useDispatch(); const dongleId = useSelector((state) => state.dongleId); const profile = useSelector((state) => state.profile); @@ -80,34 +77,34 @@ const AppHeader = ({ classes, drawerIsOpen, viewingRoute, showDrawerButton, forw return ( <> -

+ {Boolean(MyCommaAuth.isAuthenticated() && profile) && } ); }; -export default withStyles(styles)(AppHeader); +export default AppHeader; diff --git a/src/components/Dashboard/AddDevice.jsx b/src/components/Dashboard/AddDevice.jsx index 22dfe45f..590abae3 100644 --- a/src/components/Dashboard/AddDevice.jsx +++ b/src/components/Dashboard/AddDevice.jsx @@ -1,6 +1,6 @@ import { devices as Devices } from '@commaai/api'; -import { Button, CircularProgress, Divider, Modal, Paper, Typography } from '@mui/material'; -import { withStyles } from '@mui/styles'; +import { Box, Button, CircularProgress, Divider, Modal, Paper, Typography } from '@mui/material'; +import { styled } from '@mui/material/styles'; import AddCircleOutlineIcon from '@mui/icons-material/AddCircleOutline'; import * as Sentry from '@sentry/react'; import QrScanner from 'qr-scanner'; @@ -10,58 +10,52 @@ import { selectDevice, updateDevice } from '../../actions'; import Colors from '../../colors'; import { pairErrorToMessage, verifyPairToken } from '../../utils'; -const styles = (theme) => ({ - titleContainer: { - display: 'flex', - justifyContent: 'space-between', - alignItems: 'baseline', - marginBottom: 5, - }, - addButton: { - width: '100%', - background: Colors.white, - borderRadius: 18, +const StyledButton = styled(Button)({ + width: '100%', + background: Colors.white, + borderRadius: 18, + color: Colors.grey900, + textTransform: 'none', + '&:hover': { + backgroundColor: Colors.white70, color: Colors.grey900, - textTransform: 'none', - '&:hover': { - backgroundColor: Colors.white70, - color: Colors.grey900, - }, }, - retryButton: { - marginTop: 10, - background: Colors.white, - borderRadius: 18, +}); + +const RetryButton = styled(Button)({ + marginTop: 10, + background: Colors.white, + borderRadius: 18, + color: Colors.grey900, + textTransform: 'none', + '&:hover': { + backgroundColor: Colors.white70, color: Colors.grey900, - textTransform: 'none', - '&:hover': { - backgroundColor: Colors.white70, - color: Colors.grey900, - }, }, - modal: { - position: 'absolute', - padding: theme.spacing(2), - width: theme.spacing(50), - maxWidth: '90%', - left: '50%', - top: '50%', - transform: 'translate(-50%, -50%)', - outline: 'none', - }, - divider: { - marginBottom: 10, - }, - videoContainer: { - position: 'relative', - margin: '0 auto', - '& video': { - display: 'block', - width: '100%', - maxWidth: '100%', - }, +}); + +const StyledPaper = styled(Paper)(({ theme }) => ({ + position: 'absolute', + padding: theme.spacing(2), + width: theme.spacing(50), + maxWidth: '90%', + left: '50%', + top: '50%', + transform: 'translate(-50%, -50%)', + outline: 'none', +})); + +const VideoContainer = styled('div', { + shouldForwardProp: (prop) => prop !== 'showOverlay', +})(({ showOverlay }) => ({ + position: 'relative', + margin: '0 auto', + '& video': { + display: 'block', + width: '100%', + maxWidth: '100%', }, - videoContainerOverlay: { + ...(showOverlay && { '&::before': { content: "''", position: 'absolute', @@ -72,31 +66,30 @@ const styles = (theme) => ({ left: -1, zIndex: 3, }, - }, - videoOverlay: { - position: 'absolute', - zIndex: 4, - width: '100%', - height: '100%', - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - flexDirection: 'column', - textAlign: 'center', - '& p': { fontSize: '1rem' }, - }, - pairedDongleId: { - fontWeight: 'bold', - }, - canvas: { - position: 'absolute', - zIndex: 2, - width: '100%', - height: '100%', - }, + }), +})); + +const VideoOverlay = styled('div')({ + position: 'absolute', + zIndex: 4, + width: '100%', + height: '100%', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + flexDirection: 'column', + textAlign: 'center', + '& p': { fontSize: '1rem' }, +}); + +const StyledCanvas = styled('canvas')({ + position: 'absolute', + zIndex: 2, + width: '100%', + height: '100%', }); -const AddDevice = ({ classes, buttonText, buttonStyle, buttonIcon }) => { +const AddDevice = ({ buttonText, buttonStyle, buttonIcon }) => { const dispatch = useDispatch(); const devices = useSelector((state) => state.devices); @@ -324,58 +317,56 @@ const AddDevice = ({ classes, buttonText, buttonStyle, buttonIcon }) => { setModalOpen(true); }; - const videoContainerOverlay = pairLoading || pairDongleId || pairError ? classes.videoContainerOverlay : ''; + const showOverlay = pairLoading || pairDongleId || pairError; return ( <> - + - -
+ + Pair device scan QR code -
- + + {hasCamera === false ? ( <> - Camera not found, please enable camera access. + Camera not found, please enable camera access. You can also scan the QR code on your comma device using any other QR code reader application. ) : ( -
- -
+ + + {pairLoading && } {pairError && ( <> {pairError} - + try again )} {pairDongleId && ( <> {'Successfully paired device '} - {pairDongleId} + + {pairDongleId} + - + close )} -
-
+ +
+
); }; -export default withStyles(styles)(AddDevice); +export default AddDevice; diff --git a/src/components/Dashboard/DeviceList.jsx b/src/components/Dashboard/DeviceList.jsx index 0f892cc4..4d41f0a8 100644 --- a/src/components/Dashboard/DeviceList.jsx +++ b/src/components/Dashboard/DeviceList.jsx @@ -1,7 +1,7 @@ import { devices as Devices } from '@commaai/api'; import MyCommaAuth from '@commaai/my-comma-auth'; import { IconButton, Typography } from '@mui/material'; -import { withStyles } from '@mui/styles'; +import { styled } from '@mui/material/styles'; import SettingsIcon from '@mui/icons-material/Settings'; import * as Sentry from '@sentry/react'; import { useCallback, useState } from 'react'; @@ -15,76 +15,64 @@ import VisibilityHandler from '../VisibilityHandler'; import AddDevice from './AddDevice'; import DeviceSettingsModal from './DeviceSettingsModal'; -const styles = (theme) => ({ - deviceList: { - overflow: 'auto', - }, - device: { - textDecoration: 'none', - alignItems: 'center', - display: 'flex', - justifyContent: 'space-between', - padding: '16px 32px', - '&.isSelected': { - backgroundColor: 'rgba(0, 0, 0, 0.25)', - }, - }, - settingsButton: { - height: 46, - width: 46, - color: Colors.white30, - transition: 'color 150ms cubic-bezier(0.4, 0, 0.2, 1) 0ms', - '&:hover': { - color: Colors.white, - }, - }, - deviceOnline: { - width: 6, - height: 6, - borderRadius: 3, - backgroundColor: Colors.green400, - }, - deviceOffline: { - backgroundColor: Colors.grey400, - }, - deviceInfo: { - display: 'flex', - alignItems: 'center', - }, - deviceName: { - display: 'flex', - flexDirection: 'column', - justifyContent: 'center', - marginLeft: 16, - }, - deviceAlias: { - fontWeight: 600, - }, - deviceId: { - color: '#74838e', - }, - editDeviceIcon: { - color: 'white', - '&:hover': { - color: theme.palette.grey[100], - }, - }, - nameField: { - marginRight: theme.spacing(1), - }, - saveButton: { - marginRight: theme.spacing(1), - }, - textField: { - marginBottom: theme.spacing(1), +const DeviceListContainer = styled('div')({ + overflow: 'auto', +}); + +const DeviceLink = styled('a')({ + textDecoration: 'none', + alignItems: 'center', + display: 'flex', + justifyContent: 'space-between', + padding: '16px 32px', + '&.isSelected': { + backgroundColor: 'rgba(0, 0, 0, 0.25)', }, - addDeviceContainer: { - '&:hover': { backgroundColor: 'rgba(0, 0, 0, 0.25)' }, +}); + +const StyledSettingsButton = styled(IconButton)({ + height: 46, + width: 46, + color: Colors.white30, + transition: 'color 150ms cubic-bezier(0.4, 0, 0.2, 1) 0ms', + '&:hover': { + color: Colors.white, }, }); +const DeviceStatusIndicator = styled('div')(({ isOffline }) => ({ + width: 6, + height: 6, + borderRadius: 3, + backgroundColor: isOffline ? Colors.grey400 : Colors.green400, +})); + +const DeviceInfo = styled('div')({ + display: 'flex', + alignItems: 'center', +}); + +const DeviceName = styled('div')({ + display: 'flex', + flexDirection: 'column', + justifyContent: 'center', + marginLeft: 16, +}); + +const DeviceAlias = styled(Typography)({ + fontWeight: 600, +}); + +const DeviceId = styled(Typography)({ + color: '#74838e', +}); + +const AddDeviceContainer = styled('div')({ + '&:hover': { backgroundColor: 'rgba(0, 0, 0, 0.25)' }, +}); + const DeviceList = (props) => { - const { classes, handleDeviceSelected, selectedDevice } = props; + const { handleDeviceSelected, selectedDevice } = props; const dispatch = useDispatch(); const devices = useSelector((state) => state.devices); const device = useSelector((state) => state.device); @@ -117,32 +105,25 @@ const DeviceList = (props) => { const renderDevice = useCallback( (device) => { const isSelectedCls = selectedDevice === device.dongle_id ? 'isSelected' : ''; - const offlineCls = !deviceIsOnline(device) ? classes.deviceOffline : ''; + const isOffline = !deviceIsOnline(device); return ( - handleDeviceSelected(device.dongle_id))} - href={`/${device.dongle_id}`} - > -
-
 
-
- {deviceNamePretty(device)} - - {device.dongle_id} - -
-
+ handleDeviceSelected(device.dongle_id))} href={`/${device.dongle_id}`}> + +   + + {deviceNamePretty(device)} + {device.dongle_id} + + {(device.is_owner || (profile && profile.superuser)) && ( - handleOpenedSettingsModal(device.dongle_id, ev)}> - - + handleOpenedSettingsModal(device.dongle_id, ev)}> + + )} -
+ ); }, - [classes, handleDeviceSelected, profile, selectedDevice, handleOpenedSettingsModal], + [handleDeviceSelected, profile, selectedDevice, handleOpenedSettingsModal], ); if (devices === null) { @@ -180,17 +161,17 @@ const DeviceList = (props) => { return ( <> -
+ {devicesList.map(renderDevice)} {MyCommaAuth.isAuthenticated() && ( -
+ -
+ )} -
+ ); }; -export default withStyles(styles)(DeviceList); +export default DeviceList; diff --git a/src/components/Dashboard/DeviceSettingsModal.jsx b/src/components/Dashboard/DeviceSettingsModal.jsx index fe81c51a..4d4cfeca 100644 --- a/src/components/Dashboard/DeviceSettingsModal.jsx +++ b/src/components/Dashboard/DeviceSettingsModal.jsx @@ -1,6 +1,6 @@ import { devices as Devices } from '@commaai/api'; import { Button, CircularProgress, Divider, IconButton, Modal, Paper, TextField, Typography } from '@mui/material'; -import { withStyles } from '@mui/styles'; +import { styled } from '@mui/material/styles'; import CheckIcon from '@mui/icons-material/Check'; import SaveIcon from '@mui/icons-material/Save'; import ShareIcon from '@mui/icons-material/Share'; @@ -14,96 +14,108 @@ import { ErrorOutline } from '../../icons'; import { navigate } from '../../navigation'; import UploadQueue from '../Files/UploadQueue'; -const styles = (theme) => ({ - modal: { - position: 'absolute', - padding: theme.spacing(2), - width: theme.spacing(50), - maxWidth: '90%', - left: '50%', - top: '40%', - transform: 'translate(-50%, -50%)', - outline: 'none', - }, - modalUnpair: { - width: theme.spacing(45), - maxWidth: '80%', - }, - titleContainer: { - display: 'flex', - justifyContent: 'space-between', - alignItems: 'baseline', - marginBottom: 5, - }, - buttonGroup: { - textAlign: 'right', - marginTop: theme.spacing(2), - }, - form: { - paddingTop: theme.spacing(1), - paddingBottom: theme.spacing(1), - }, - formRow: { - minHeight: 75, - }, - formRowError: { - padding: 10, - marginBottom: 5, - backgroundColor: Colors.red500, - }, - textField: { - maxWidth: '70%', - }, - fabProgress: { - position: 'absolute', - top: 0, - left: 0, - zIndex: 1, - }, - wrapper: { - margin: theme.spacing(1), - position: 'relative', - display: 'inline-block', - }, - primeManageButton: { - marginTop: 20, - marginRight: 20, - '&:last-child': { marginRight: 0 }, - }, - topButtonGroup: { - display: 'flex', - justifyContent: 'space-between', - flexWrap: 'wrap-reverse', - alignItems: 'baseline', - }, - cancelButton: { - backgroundColor: Colors.grey200, - color: Colors.white, - '&:hover': { - backgroundColor: Colors.grey400, - }, - }, - unpairError: { - marginTop: 15, - padding: 10, - display: 'flex', - alignItems: 'center', - backgroundColor: 'rgba(255, 0, 0, 0.3)', - '& p': { display: 'inline-block', marginLeft: 10 }, - color: Colors.white, - }, - unpairWarning: { - marginTop: 15, - padding: 10, - display: 'flex', - alignItems: 'center', - backgroundColor: Colors.orange200, - '& p': { display: 'inline-block', marginLeft: 10 }, - color: Colors.white, +const StyledPaper = styled(Paper)(({ theme }) => ({ + position: 'absolute', + padding: theme.spacing(2), + width: theme.spacing(50), + maxWidth: '90%', + left: '50%', + top: '40%', + transform: 'translate(-50%, -50%)', + outline: 'none', +})); + +const UnpairPaper = styled(StyledPaper)(({ theme }) => ({ + width: theme.spacing(45), + maxWidth: '80%', +})); + +const TitleContainer = styled('div')({ + display: 'flex', + justifyContent: 'space-between', + alignItems: 'baseline', + marginBottom: 5, +}); + +const ButtonGroup = styled('div')(({ theme }) => ({ + textAlign: 'right', + marginTop: theme.spacing(2), +})); + +const FormContainer = styled('div')(({ theme }) => ({ + paddingTop: theme.spacing(1), + paddingBottom: theme.spacing(1), +})); + +const FormRow = styled('div')({ + minHeight: 75, +}); + +const FormRowError = styled('div')({ + padding: 10, + marginBottom: 5, + backgroundColor: Colors.red500, +}); + +const StyledTextField = styled(TextField)({ + maxWidth: '70%', +}); + +const FabProgress = styled(CircularProgress)({ + position: 'absolute', + top: 0, + left: 0, + zIndex: 1, +}); + +const IconButtonWrapper = styled('div')(({ theme }) => ({ + margin: theme.spacing(1), + position: 'relative', + display: 'inline-block', +})); + +const PrimeManageButton = styled(Button)({ + marginTop: 20, + marginRight: 20, + '&:last-child': { marginRight: 0 }, +}); + +const TopButtonGroup = styled('div')({ + display: 'flex', + justifyContent: 'space-between', + flexWrap: 'wrap-reverse', + alignItems: 'baseline', +}); + +const CancelButton = styled(Button)({ + backgroundColor: Colors.grey200, + color: Colors.white, + '&:hover': { + backgroundColor: Colors.grey400, }, }); -const DeviceSettingsModal = ({ classes, dongleId, isOpen, onClose }) => { +const UnpairError = styled('div')({ + marginTop: 15, + padding: 10, + display: 'flex', + alignItems: 'center', + backgroundColor: 'rgba(255, 0, 0, 0.3)', + '& p': { display: 'inline-block', marginLeft: 10 }, + color: Colors.white, +}); + +const UnpairWarning = styled('div')({ + marginTop: 15, + padding: 10, + display: 'flex', + alignItems: 'center', + backgroundColor: Colors.orange200, + '& p': { display: 'inline-block', marginLeft: 10 }, + color: Colors.white, +}); + +const DeviceSettingsModal = ({ dongleId, isOpen, onClose }) => { const dispatch = useDispatch(); const globalDongleId = useSelector((state) => state.dongleId); const devices = useSelector((state) => state.devices); @@ -268,54 +280,52 @@ const DeviceSettingsModal = ({ classes, dongleId, isOpen, onClose }) => { return ( <> - -
+ + Device settings {device.dongle_id} -
+
- - +
- +
-
+ {error && ( -
+ {error} -
+ )} -
- + callOnEnter(setDeviceAliasAction, ev)} /> {(device.alias !== deviceAlias || hasSavedAlias) && ( -
+ {hasSavedAlias ? : } - {loadingDeviceAlias && } -
+ {loadingDeviceAlias && } + )} -
-
- + + { helperText="give another user read access to this device" /> {(shareEmail.length > 0 || hasShared) && ( -
+ {hasShared ? : } - {loadingDeviceShare && } -
+ {loadingDeviceShare && } + )} -
-
-
- -
-
+ + +
- -
+ + Unpair device {device.dongle_id} -
+ {unpairError && ( -
+ {unpairError} -
+ )} {device.prime && ( -
+ Unpairing will also cancel the comma prime subscription for this device. -
+ )} -
- + {unpaired ? ( Unpaired ) : ( - + )} -
-
+ +
setUploadModal(false)} device={device} /> ); }; -export default withStyles(styles)(DeviceSettingsModal); +export default DeviceSettingsModal; diff --git a/src/components/Dashboard/DriveList.jsx b/src/components/Dashboard/DriveList.jsx index 76385c9e..39fb2435 100644 --- a/src/components/Dashboard/DriveList.jsx +++ b/src/components/Dashboard/DriveList.jsx @@ -1,5 +1,4 @@ -import { Typography } from '@mui/material'; -import { withStyles } from '@mui/styles'; +import { Box, Typography } from '@mui/material'; import { useDispatch, useSelector } from 'react-redux'; import { checkLastRoutesData, checkRoutesData } from '../../actions'; @@ -8,25 +7,7 @@ import VisibilityHandler from '../VisibilityHandler'; import DriveListEmpty from './DriveListEmpty'; import DriveListItem from './DriveListItem'; -const styles = () => ({ - drivesTable: { - display: 'flex', - flexDirection: 'column', - flexGrow: 1, - }, - drives: { - padding: 16, - flex: '1', - }, - endMessage: { - padding: 8, - textAlign: 'center', - marginBottom: 32, - }, -}); - -const DriveList = (props) => { - const { classes } = props; +const DriveList = () => { const dispatch = useDispatch(); const device = useSelector((state) => state.device); const routes = useSelector((state) => state.routes); @@ -37,9 +18,9 @@ const DriveList = (props) => { contentStatus = ; } else if (routes && routes.length > 5) { contentStatus = ( -
+ There are no more routes found in selected time range. -
+ ); } @@ -53,7 +34,7 @@ const DriveList = (props) => { const routesSize = displayRoutes.length; content = ( -
+ {displayRoutes.map((drive, index) => { // when the last item is in view, we fetch the next routes return index === routesSize - 1 ? ( @@ -64,17 +45,17 @@ const DriveList = (props) => { ); })} -
+ ); } return ( -
+ dispatch(checkRoutesData())} minInterval={60} /> {content} {contentStatus} -
+ ); }; -export default withStyles(styles)(DriveList); +export default DriveList; diff --git a/src/components/Dashboard/DriveListEmpty.jsx b/src/components/Dashboard/DriveListEmpty.jsx index 42114cc4..f08d14f1 100644 --- a/src/components/Dashboard/DriveListEmpty.jsx +++ b/src/components/Dashboard/DriveListEmpty.jsx @@ -1,17 +1,10 @@ import { Grid, Typography } from '@mui/material'; -import { withStyles } from '@mui/styles'; import { useWindowWidth } from '../../hooks/window'; -const styles = () => ({ - zeroState: { - flex: '0', - }, -}); - const DriveListEmpty = (props) => { const windowWidth = useWindowWidth(); - const { classes, device, routes } = props; + const { device, routes } = props; let zeroRidesEle = null; if (device && routes === null) { @@ -22,10 +15,10 @@ const DriveListEmpty = (props) => { const containerPadding = windowWidth > 520 ? 36 : 16; return ( - + {zeroRidesEle} ); }; -export default withStyles(styles)(DriveListEmpty); +export default DriveListEmpty; diff --git a/src/components/Dashboard/DriveListItem.jsx b/src/components/Dashboard/DriveListItem.jsx index c940f447..096cead4 100644 --- a/src/components/Dashboard/DriveListItem.jsx +++ b/src/components/Dashboard/DriveListItem.jsx @@ -1,5 +1,5 @@ -import { Grid, Typography } from '@mui/material'; -import { withStyles } from '@mui/styles'; +import { Box, Grid, Typography } from '@mui/material'; +import { styled } from '@mui/material/styles'; import dayjs from 'dayjs'; import { useEffect, useRef, useState } from 'react'; import { useDispatch } from 'react-redux'; @@ -13,44 +13,18 @@ import { filterRegularClick, formatDriveDuration } from '../../utils'; import { isMetric, KM_PER_MI } from '../../utils/conversions'; import Timeline from '../Timeline'; -const styles = () => ({ - drive: { - background: 'linear-gradient(to bottom, #30373B 0%, #1D2225 100%)', - borderTop: '1px solid rgba(255, 255, 255, .05)', - borderRadius: 8, - display: 'flex', - flexDirection: 'column', - marginBottom: 12, - overflow: 'hidden', - padding: 0, - transition: 'background .2s', - textDecoration: 'none', - '&:hover': {}, - }, - driveHeader: { - alignItems: 'center', - }, - driveHeaderIntro: { - display: 'flex', - }, - driveGridItem: { - flexGrow: 1, - }, - driveGridItemRightAlign: { - textAlign: 'right', - }, - driveHeaderIntroSmall: { - justifyContent: 'center', - }, - driveArrow: { - color: Colors.grey500, - height: '100%', - marginLeft: '25%', - width: 32, - }, - firstLine: { - fontWeight: 600, - }, +const DriveLink = styled('a')({ + background: 'linear-gradient(to bottom, #30373B 0%, #1D2225 100%)', + borderTop: '1px solid rgba(255, 255, 255, .05)', + borderRadius: 8, + display: 'flex', + flexDirection: 'column', + marginBottom: 12, + overflow: 'hidden', + padding: 0, + transition: 'background .2s', + textDecoration: 'none', + '&:hover': {}, }); const DriveListItem = (props) => { @@ -58,7 +32,7 @@ const DriveListItem = (props) => { const el = useRef(); const [isVisible, setVisible] = useState(false); const windowWidth = useWindowWidth(); - const { classes, drive } = props; + const { drive } = props; useEffect(() => { const onScroll = () => { @@ -112,35 +86,35 @@ const DriveListItem = (props) => { /* eslint-enable key-spacing, no-multi-spaces */ return ( - -
+ + -
- {startDate} + + {startDate} {`${startTime} to ${endTime}`} -
-
- {duration} + + + {duration} {distance} -
-
- {drive.startLocation?.place} + + + {drive.startLocation?.place} {drive.startLocation?.details} -
-
- {drive.endLocation?.place} + + + {drive.endLocation?.place} {drive.endLocation?.details} -
+
{!small && ( -
- -
+ + + )} -
+ -
+ ); }; -export default withStyles(styles)(DriveListItem); +export default DriveListItem; diff --git a/src/components/DeviceInfo/index.jsx b/src/components/DeviceInfo/index.jsx index d7b773a1..6a7bf4a3 100644 --- a/src/components/DeviceInfo/index.jsx +++ b/src/components/DeviceInfo/index.jsx @@ -1,6 +1,6 @@ import { athena as Athena, devices as Devices } from '@commaai/api'; -import { Button, CircularProgress, Popper, Tooltip, Typography } from '@mui/material'; -import { withStyles } from '@mui/styles'; +import { Box, Button, CircularProgress, Popper, Tooltip, Typography } from '@mui/material'; +import { styled } from '@mui/material/styles'; import AccessTime from '@mui/icons-material/AccessTime'; import * as Sentry from '@sentry/react'; import dayjs from 'dayjs'; @@ -13,171 +13,144 @@ import ResizeHandler from '../ResizeHandler'; import TimeSelect from '../TimeSelect'; import VisibilityHandler from '../VisibilityHandler'; -const styles = (theme) => ({ - container: { - borderBottom: `1px solid ${Colors.white10}`, - paddingTop: 8, - display: 'flex', - flexDirection: 'column', - minHeight: 64, - justifyContent: 'center', - }, - row: { - display: 'flex', - justifyContent: 'space-between', - alignItems: 'center', - marginBottom: 4, - [theme.breakpoints.down('xs')]: { - marginBottom: 8, - }, - }, - columnGap: { - columnGap: theme.spacing(4), - }, - bold: { - fontWeight: 600, - }, - button: { - backgroundColor: Colors.white, - color: Colors.grey900, - textTransform: 'none', - minHeight: 'unset', - marginRight: '8px', - '&:hover': { - background: '#ddd', - color: Colors.grey900, - }, - '&:disabled': { - background: '#ddd', - color: Colors.grey900, - }, - '&:disabled:hover': { - background: '#ddd', - color: Colors.grey900, - }, - }, - buttonOffline: { - background: Colors.grey400, - color: Colors.lightGrey600, - '&:disabled': { - background: Colors.grey400, - color: Colors.lightGrey600, - }, - '&:disabled:hover': { - background: Colors.grey400, - color: Colors.lightGrey600, - }, +const Container = styled(Box)(({ theme }) => ({ + borderBottom: `1px solid ${Colors.white10}`, + paddingTop: 8, + display: 'flex', + flexDirection: 'column', + minHeight: 64, + justifyContent: 'center', +})); + +const Row = styled(Box)(({ theme }) => ({ + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + marginBottom: 4, + [theme.breakpoints.down('xs')]: { + marginBottom: 8, }, - buttonRow: { - justifyContent: 'center', +})); + +const DeviceStat = styled(Box)(({ theme }) => ({ + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + maxWidth: 80, + padding: `0 ${theme.spacing(2)}`, +})); + +const CarBattery = styled(Box)({ + padding: '5px 16px', + borderRadius: 15, + margin: '0 10px', + textAlign: 'center', + '& p': { + fontSize: 14, + fontWeight: 500, + lineHeight: '1.4em', }, - spaceAround: { - display: 'flex', - justifyContent: 'space-around', +}); + +const StyledButton = styled(Button)(({ offline }) => ({ + backgroundColor: offline ? Colors.grey400 : Colors.white, + color: offline ? Colors.lightGrey600 : Colors.grey900, + textTransform: 'none', + minHeight: 'unset', + marginRight: '8px', + '&:hover': { + background: offline ? Colors.grey400 : '#ddd', + color: offline ? Colors.lightGrey600 : Colors.grey900, }, - deviceStatContainer: { - display: 'flex', - flex: 1, - justifySelf: 'start', + '&:disabled': { + background: offline ? Colors.grey400 : '#ddd', + color: offline ? Colors.lightGrey600 : Colors.grey900, }, - deviceStat: { - display: 'flex', - flexDirection: 'column', - alignItems: 'center', - maxWidth: 80, - padding: `0 ${theme.spacing(2)}`, + '&:disabled:hover': { + background: offline ? Colors.grey400 : '#ddd', + color: offline ? Colors.lightGrey600 : Colors.grey900, }, - carBattery: { - padding: '5px 16px', - borderRadius: 15, - margin: '0 10px', +})); + +const SnapshotContainer = styled(Box)({ + borderBottom: `1px solid ${Colors.white10}`, +}); + +const SnapshotContainerLarge = styled(Box)({ + maxWidth: 1050, + margin: '0 auto', + display: 'flex', +}); + +const SnapshotImageContainerLarge = styled(Box)({ + width: '50%', + display: 'flex', + justifyContent: 'center', +}); + +const SnapshotImage = styled('img')({ + display: 'block', + width: '450px !important', + maxWidth: '100%', +}); + +const SnapshotImageError = styled(Box)({ + width: 450, + maxWidth: '100%', + backgroundColor: Colors.grey950, + padding: '0 80px', + margin: '0 auto', + height: '100%', + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + '& p': { textAlign: 'center', - '& p': { - fontSize: 14, - fontWeight: 500, - lineHeight: '1.4em', + fontSize: '1rem', + '&:first-child': { + fontWeight: 600, }, }, - actionButton: { - minWidth: 130, - padding: '5px 16px', - borderRadius: 15, - }, - actionButtonSmall: { - minWidth: 90, - padding: '5px 10px', - borderRadius: 15, - }, - actionButtonIcon: { - minWidth: 60, - padding: '8px 16px', - borderRadius: 15, - }, - snapshotContainer: { - borderBottom: `1px solid ${Colors.white10}`, - }, - snapshotContainerLarge: { - maxWidth: 1050, - margin: '0 auto', - display: 'flex', - }, - snapshotImageContainerLarge: { - width: '50%', - display: 'flex', - justifyContent: 'center', - }, - snapshotImage: { - display: 'block', - width: '450px !important', - maxWidth: '100%', - }, - snapshotImageError: { - width: 450, - maxWidth: '100%', - backgroundColor: Colors.grey950, - padding: '0 80px', - margin: '0 auto', - height: '100%', - display: 'flex', - flexDirection: 'column', - alignItems: 'center', - justifyContent: 'center', - '& p': { - textAlign: 'center', - fontSize: '1rem', - '&:first-child': { - fontWeight: 600, - }, - }, - }, - scrollSnapContainer: { - display: 'flex', - overflowX: 'scroll', - scrollSnapType: 'x mandatory', - scrollBehavior: 'smooth', - '&::-webkit-scrollbar': { - height: '10px', - }, - '&::-webkit-scrollbar-thumb': { - backgroundColor: '#d1d1d1', - borderRadius: '8px', - }, - '&::-webkit-scrollbar-track': { - backgroundColor: '#272c2f', - }, +}); + +const ScrollSnapContainer = styled(Box)({ + display: 'flex', + overflowX: 'scroll', + scrollSnapType: 'x mandatory', + scrollBehavior: 'smooth', + '&::-webkit-scrollbar': { + height: '10px', }, - scrollSnapItem: { - flex: '0 0 auto', - scrollSnapAlign: 'start', - width: '100%', - maxWidth: '450px', - margin: '0', + '&::-webkit-scrollbar-thumb': { + backgroundColor: '#d1d1d1', + borderRadius: '8px', }, - buttonIcon: { - fontSize: 20, - marginLeft: theme.spacing(1), + '&::-webkit-scrollbar-track': { + backgroundColor: '#272c2f', }, - popover: { +}); + +const ScrollSnapItem = styled(Box)({ + flex: '0 0 auto', + scrollSnapAlign: 'start', + width: '100%', + maxWidth: '450px', + margin: '0', +}); + +const StyledPopper = styled(Popper)({ + borderRadius: 22, + padding: '8px 16px', + border: `1px solid ${Colors.white10}`, + backgroundColor: Colors.grey800, + fontSize: 12, + marginTop: 5, + textAlign: 'center', +}); + +const StyledTooltip = styled(Tooltip)({ + '& .MuiTooltip-tooltip': { borderRadius: 22, padding: '8px 16px', border: `1px solid ${Colors.white10}`, @@ -188,7 +161,7 @@ const styles = (theme) => ({ }, }); -const DeviceInfo = ({ classes }) => { +const DeviceInfo = () => { const dongleId = useSelector((state) => state.dongleId); const device = useSelector((state) => state.device); @@ -335,24 +308,24 @@ const DeviceInfo = ({ classes }) => { return ( <> -
- + + {distance} {metric ? 'kilometers' : 'miles'} -
-
- + + + {deviceStats.result.all.routes} drives -
-
- + + + {Math.round(deviceStats.result.all.minutes / 60.0)} hours -
+ ); }; @@ -365,8 +338,18 @@ const DeviceInfo = ({ classes }) => { batteryBackground = batteryVoltage < 11.0 ? Colors.red400 : Colors.green400; } - const actionButtonClass = windowWidth >= 520 ? classes.actionButton : classes.actionButtonSmall; - const buttonOffline = deviceIsOnline(device) ? '' : classes.buttonOffline; + const isOffline = !deviceIsOnline(device); + const buttonSx = { + minWidth: windowWidth >= 520 ? 130 : 90, + padding: '5px 16px', + borderRadius: 15, + }; + + const iconButtonSx = { + minWidth: 60, + padding: '8px 16px', + borderRadius: 15, + }; let error = null; if (snapshot.error && snapshot.error.data && snapshot.error.data.message) { @@ -385,29 +368,24 @@ const DeviceInfo = ({ classes }) => { return ( <> -
+ {deviceIsOnline(device) ? ( {`${windowWidth >= 520 ? 'car ' : ''}battery: ${batteryVoltage ? `${batteryVoltage.toFixed(1)}\u00a0V` : 'N/A'}`} ) : ( - + device offline - + )} -
- - - + + {error} - + ); @@ -416,14 +394,14 @@ const DeviceInfo = ({ classes }) => { const renderSnapshotImage = (src, isFront) => { if (!src) { return ( -
+ {isFront && 'Interior'} snapshot not available {isFront && Enable “Record and Upload Driver Camera” on your device for interior camera snapshots} -
+ ); } - return ; + return ; }; const containerPadding = windowWidth > 520 ? 36 : 16; @@ -433,40 +411,40 @@ const DeviceInfo = ({ classes }) => { <> -
+ {windowWidth >= 768 ? ( -
+ {deviceNamePretty(device)} -
{renderStats()}
-
{renderButtons()}
-
+ {renderStats()} + {renderButtons()} + ) : ( <> -
+ {deviceNamePretty(device)} -
-
{renderButtons()}
- {deviceStats.result &&
{renderStats()}
} + + {renderButtons()} + {deviceStats.result && {renderStats()}} )} -
+ {snapshot.result && ( -
+ {windowWidth >= 640 ? ( -
-
{renderSnapshotImage(snapshot.result.jpegBack, false)}
-
{renderSnapshotImage(snapshot.result.jpegFront, true)}
-
+ + {renderSnapshotImage(snapshot.result.jpegBack, false)} + {renderSnapshotImage(snapshot.result.jpegFront, true)} + ) : ( -
-
{renderSnapshotImage(snapshot.result.jpegBack, false)}
-
{renderSnapshotImage(snapshot.result.jpegFront, true)}
-
+ + {renderSnapshotImage(snapshot.result.jpegBack, false)} + {renderSnapshotImage(snapshot.result.jpegFront, true)} + )} -
+ )} ); }; -export default withStyles(styles)(DeviceInfo); +export default DeviceInfo; diff --git a/src/components/DriveView/Media.jsx b/src/components/DriveView/Media.jsx index 4d5582b9..59ff5764 100644 --- a/src/components/DriveView/Media.jsx +++ b/src/components/DriveView/Media.jsx @@ -1,6 +1,6 @@ import { drives as Drives } from '@commaai/api'; -import { Button, CircularProgress, Divider, ListItem, Menu, MenuItem, Popper, Typography } from '@mui/material'; -import { withStyles } from '@mui/styles'; +import { Box, Button, CircularProgress, Divider, ListItem, Menu, MenuItem, Popper, Typography } from '@mui/material'; +import { styled } from '@mui/material/styles'; import ContentCopyIcon from '@mui/icons-material/ContentCopy'; import ShareIcon from '@mui/icons-material/Share'; import WarningIcon from '@mui/icons-material/Warning'; @@ -25,188 +25,148 @@ import SwitchLoading from '../utils/SwitchLoading'; const publicTooltip = 'Making a route public allows anyone with the route name or link to access it.'; const preservedTooltip = 'Preserving a route will prevent it from being deleted. You can preserve up to 10 routes, or 100 if you have comma prime.'; -const styles = () => ({ - root: { - display: 'flex', - }, - mediaOptionsRoot: { - maxWidth: 964, - margin: '0 auto', - display: 'flex', - justifyContent: 'space-between', - flexWrap: 'wrap', - }, - mediaOptions: { - marginBottom: 12, - display: 'flex', - width: 'max-content', - alignItems: 'center', - border: '1px solid rgba(255,255,255,.1)', - borderRadius: 50, - }, - mediaOption: { - alignItems: 'center', - borderRight: '1px solid rgba(255,255,255,.1)', - display: 'flex', - flexDirection: 'column', - justifyContent: 'center', - cursor: 'pointer', - minHeight: 32, - minWidth: 44, - paddingLeft: 15, - paddingRight: 15, - '&.disabled': { - cursor: 'default', - }, - '&:last-child': { - borderRight: 'none', - }, - }, - mediaOptionDisabled: { - cursor: 'auto', - }, - mediaOptionIcon: { - backgroundColor: '#fff', - borderRadius: 3, - height: 20, - margin: '2px 0', - width: 30, - }, - mediaOptionText: { - fontSize: 12, - fontWeight: 500, - textAlign: 'center', - }, - mediaSource: { - width: '100%', - }, - menuLoading: { - position: 'absolute', - outline: 'none', - zIndex: 5, - top: '50%', - left: '50%', - transform: 'translate(-50%, -50%)', - }, - filesItem: { - justifyContent: 'space-between', - opacity: 1, - }, - switchListItem: { - padding: '12px 16px', - boxSizing: 'content-box', - height: 24, - lineHeight: 1, - '& span': { fontSize: '1rem' }, - }, - offlineMenuItem: { - height: 'unset', - flexDirection: 'column', - alignItems: 'flex-start', - '& div': { - display: 'flex', - }, - '& svg': { marginRight: 8 }, - }, - uploadButton: { - marginLeft: 12, - color: Colors.white, - borderRadius: 13, - fontSize: '0.8rem', - padding: '4px 12px', - minHeight: 19, - backgroundColor: Colors.white05, - '&:hover': { - backgroundColor: Colors.white10, - }, - }, - fakeUploadButton: { - marginLeft: 12, - color: Colors.white, - fontSize: '0.8rem', - padding: '4px 12px', - display: 'flex', - justifyContent: 'center', - alignItems: 'center', +const Root = styled(Box)({ + display: 'flex', +}); + +const MediaOptionsRoot = styled(Box)({ + maxWidth: 964, + margin: '0 auto', + display: 'flex', + justifyContent: 'space-between', + flexWrap: 'wrap', +}); + +const MediaOptions = styled(Box)({ + marginBottom: 12, + display: 'flex', + width: 'max-content', + alignItems: 'center', + border: '1px solid rgba(255,255,255,.1)', + borderRadius: 50, +}); + +const MediaOption = styled(Box)({ + alignItems: 'center', + borderRight: '1px solid rgba(255,255,255,.1)', + display: 'flex', + flexDirection: 'column', + justifyContent: 'center', + cursor: 'pointer', + minHeight: 32, + minWidth: 44, + paddingLeft: 15, + paddingRight: 15, + '&.disabled': { + cursor: 'default', }, - copySegment: { - pointerEvents: 'auto', - opacity: 1, - '& div': { - whiteSpace: 'normal', - padding: '0 6px', - borderRadius: 4, - backgroundColor: Colors.white08, - marginRight: 4, - }, + '&:last-child': { + borderRight: 'none', }, - shareButton: { +}); + +const MediaOptionText = styled(Typography)({ + fontSize: 12, + fontWeight: 500, + textAlign: 'center', +}); + +const MenuLoading = styled(Box)({ + position: 'absolute', + outline: 'none', + zIndex: 5, + top: '50%', + left: '50%', + transform: 'translate(-50%, -50%)', +}); + +const FilesItem = styled(MenuItem)({ + justifyContent: 'space-between', + opacity: 1, +}); + +const SwitchListItem = styled(ListItem)({ + padding: '12px 16px', + boxSizing: 'content-box', + height: 24, + lineHeight: 1, + '& span': { fontSize: '1rem' }, +}); + +const OfflineMenuItem = styled(MenuItem)({ + height: 'unset', + flexDirection: 'column', + alignItems: 'flex-start', + '& div': { display: 'flex', - alignItems: 'center', - justifyContent: 'space-between', - }, - dcameraUploadIcon: { - fontSize: '1rem', - marginLeft: 4, }, - dcameraUploadInfo: { - zIndex: 2000, - textAlign: 'center', - borderRadius: 14, - fontSize: '0.8em', - padding: '6px 8px', - border: `1px solid ${Colors.white10}`, - backgroundColor: Colors.grey800, - color: Colors.white, - '& p': { fontSize: '0.8rem' }, - }, - noPrimePopover: { - borderRadius: 16, - padding: 16, - border: `1px solid ${Colors.white10}`, - backgroundColor: Colors.grey800, - marginTop: 12, - zIndex: 5, - '& p': { - fontSize: '0.9rem', - color: Colors.white, - margin: 0, - }, - }, - noPrimeHeader: { - display: 'flex', - alignItems: 'center', - justifyContent: 'space-between', - marginBottom: 12, - '& p': { - fontSize: '1rem', - fontWeight: 500, - }, + '& svg': { marginRight: 8 }, +}); + +const UploadButton = styled(Button)({ + marginLeft: 12, + color: Colors.white, + borderRadius: 13, + fontSize: '0.8rem', + padding: '4px 12px', + minHeight: 19, + backgroundColor: Colors.white05, + '&:hover': { + backgroundColor: Colors.white10, }, - noPrimeButton: { - padding: '6px 24px', - borderRadius: 15, - textTransform: 'none', - minHeight: 'unset', - color: Colors.white, - backgroundColor: Colors.primeBlue50, - '&:disabled': { - background: '#ddd', - color: Colors.grey900, - }, - '&:hover': { - color: Colors.white, - backgroundColor: Colors.primeBlue200, - }, +}); + +const FakeUploadButton = styled(Box)({ + marginLeft: 12, + color: Colors.white, + fontSize: '0.8rem', + padding: '4px 12px', + display: 'flex', + justifyContent: 'center', + alignItems: 'center', +}); + +const CopySegment = styled(MenuItem)({ + pointerEvents: 'auto', + opacity: 1, + '& div': { + whiteSpace: 'normal', + padding: '0 6px', + borderRadius: 4, + backgroundColor: Colors.white08, + marginRight: 4, }, }); +const ShareButton = styled(MenuItem)({ + display: 'flex', + alignItems: 'center', + justifyContent: 'space-between', +}); + +const DcameraUploadIcon = styled(InfoOutline)({ + fontSize: '1rem', + marginLeft: 4, +}); + +const DcameraUploadInfo = styled(Popper)({ + zIndex: 2000, + textAlign: 'center', + borderRadius: 14, + fontSize: '0.8em', + padding: '6px 8px', + border: `1px solid ${Colors.white10}`, + backgroundColor: Colors.grey800, + color: Colors.white, + '& p': { fontSize: '0.8rem' }, +}); + const MediaType = { VIDEO: 'video', MAP: 'map', }; -const Media = ({ classes, menusOnly }) => { +const Media = ({ menusOnly }) => { // Redux state const dispatch = useDispatch(); const dongleId = useSelector((state) => state.dongleId); @@ -448,53 +408,50 @@ const Media = ({ classes, menusOnly }) => { button = null; } else if (file.url) { button = ( - + ); } else if (file.progress !== undefined) { button = ( -
- {file.current ? `${Math.floor(file.progress * 100)}%` : file.paused ? 'paused' : 'pending'} -
+ {file.current ? `${Math.floor(file.progress * 100)}%` : file.paused ? 'paused' : 'pending'} ); } else if (file.requested) { button = ( -
+ -
+ ); } else if (file.notFound) { button = ( -
setDcamUploadInfo(ev.target) : null} onMouseLeave={type === 'dcameras' ? () => setDcamUploadInfo(null) : null} > not found - {type === 'dcameras' && } -
+ {type === 'dcameras' && } + ); } else if (!canUpload) { button = ( - + ); } else { button = ( - + ); } return ( - + {name} {button} - + ); }; @@ -539,41 +496,41 @@ const Media = ({ classes, menusOnly }) => { transformOrigin={{ vertical: 'top', horizontal: 'right' }} > {!files && ( -
+ -
+ )} {buttons.filter((b) => Boolean(b)).map(renderUploadMenuItem)} - + All logs {Boolean(files && canUpload && !rlogUploadDisabled) && ( - + )} {Boolean(canUpload && rlogUploadDisabled && stats) && ( -
+ {stats.isUploadedRlog ? 'uploaded' : stats.isUploadingRlog ? 'pending' : } -
+ )} -
- + + All files {Boolean(files && canUpload && !allUploadDisabled) && ( - + )} {Boolean(canUpload && allUploadDisabled && stats) && ( -
+ {stats.isUploadedAll ? 'uploaded' : stats.isUploadingAll ? 'pending' : } -
+ )} -
+ {deviceIsOnline(device) || !files ? ( - { @@ -582,29 +539,28 @@ const Media = ({ classes, menusOnly }) => { } : null } - style={files ? { pointerEvents: 'auto' } : { color: Colors.white60 }} - className={classes.filesItem} + sx={files ? { pointerEvents: 'auto' } : { color: Colors.white60 }} disabled={!files} > View upload queue - + ) : ( - +
Device offline
uploading will resume when device is online -
+ )} {stats && stats.isPausedAll && deviceOnCellular(device) && ( - +
Connect to WiFi
uploading paused on cellular connection -
+ )} { onClose={() => setMoreInfoMenu(null)} transformOrigin={{ vertical: 'top', horizontal: windowWidth > 400 ? 260 : 300 }} > - 400 ? '0.8rem' : '0.7rem' }}> + 400 ? '0.8rem' : '0.7rem' }}>
{currentRoute ? `${currentRoute.fullname.replace('|', '/')}/${getSegmentNumber(currentRoute)}` : '---'}
-
+ {typeof navigator.share !== 'undefined' && ( - + Share this route - + )} View in useradmin {Boolean(device?.is_owner || (profile && profile.superuser)) && [ , - + - , - + , + - , + , ]}
setUploadModal(false)} update={Boolean(moreInfoMenu || uploadModal || downloadMenu)} device={device} /> - + make sure to enable the “Record and Upload Driver Camera” toggle - + ); }; @@ -647,28 +603,28 @@ const Media = ({ classes, menusOnly }) => { const renderMediaOptions = (showMapAlways) => { return ( <> -
+ {showMapAlways ? ( -
+ ) : ( -
-
setInView(MediaType.VIDEO)}> - Video -
-
setInView(MediaType.MAP)}> - Map -
-
+ + setInView(MediaType.VIDEO)}> + Video + + setInView(MediaType.MAP)}> + Map + + )} -
-
setDownloadMenu(ev.target)}> - Files -
-
setMoreInfoMenu(ev.target)}> - More info -
-
-
+ + setDownloadMenu(ev.target)}> + Files + + setMoreInfoMenu(ev.target)}> + More info + + +
{renderMenus()} ); @@ -733,27 +689,27 @@ const Media = ({ classes, menusOnly }) => { const mapContainerStyle = showMapAlways ? { width: '40%', marginBottom: 62, marginTop: 46, paddingLeft: 24 } : { width: '100%' }; return ( -
+ setWindowWidth(ww)} /> -
+ {renderMediaOptions(showMapAlways)} {inView === MediaType.VIDEO && } {inView === MediaType.MAP && !showMapAlways && ( -
+ -
+
)} -
+ -
-
+ + {inView === MediaType.VIDEO && showMapAlways && ( -
+ -
+ )} -
+ ); }; -export default withStyles(styles)(Media); +export default Media; diff --git a/src/components/Files/UploadQueue.jsx b/src/components/Files/UploadQueue.jsx index 9d621909..36226f26 100644 --- a/src/components/Files/UploadQueue.jsx +++ b/src/components/Files/UploadQueue.jsx @@ -1,5 +1,5 @@ -import { Button, CircularProgress, Divider, LinearProgress, Modal, Paper, Typography } from '@mui/material'; -import { withStyles } from '@mui/styles'; +import { Box, Button, CircularProgress, Divider, LinearProgress, Modal, Paper, Typography } from '@mui/material'; +import { styled } from '@mui/material/styles'; import HighlightOffIcon from '@mui/icons-material/HighlightOff'; import WarningIcon from '@mui/icons-material/Warning'; import { useCallback, useEffect, useState } from 'react'; @@ -10,108 +10,27 @@ import Colors from '../../colors'; import { deviceIsOnline, deviceOnCellular, deviceVersionAtLeast } from '../../utils'; import ResizeHandler from '../ResizeHandler'; -const styles = (theme) => ({ - modal: { - position: 'absolute', - padding: theme.spacing(2), - width: 'max-content', - maxWidth: '90%', - left: '50%', - top: '50%', - transform: 'translate(-50%, -50%)', - outline: 'none', - }, - titleContainer: { - display: 'flex', - justifyContent: 'space-between', - alignItems: 'baseline', - marginBottom: 5, - }, - buttonGroup: { - textAlign: 'right', - marginTop: theme.spacing(2), - }, - uploadContainer: { - margin: `${theme.spacing(1)} 0`, - color: Colors.white, - textAlign: 'left', - overflowY: 'auto', - }, - uploadTable: { - borderCollapse: 'collapse', - }, - uploadCell: { - height: 25, - }, - cancelCell: { - textAlign: 'center', - '& button': { - minWidth: 'unset', - padding: 0, - fontWeight: 600, - borderRadius: 13, - minHeight: 'unset', - '&:hover': { - backgroundColor: 'transparent', - }, - '& svg': { - fontSize: 18, - }, - }, - }, - segmentName: { - display: 'flex', - flexWrap: 'wrap', - '& span': { - whiteSpace: 'nowrap', - }, - }, - uploadCancelled: { - color: Colors.white, - margin: 1.5, - }, - uploadProgress: { - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - fontSize: '0.8rem', - '& > div': { - width: '80%', - height: 8, - marginRight: 6, - border: 'none', - backgroundColor: Colors.white30, - '& > div': { - backgroundColor: Colors.white80, - transition: 'transform 0.5s linear', - }, - }, - }, - cancelButton: { - marginLeft: 8, - backgroundColor: Colors.grey200, - color: Colors.white, - '&:hover': { - backgroundColor: Colors.grey400, - }, - }, - cellularWarning: { - backgroundColor: Colors.grey500, - padding: `${theme.spacing(1.5)} ${theme.spacing(2)}`, - borderRadius: 4, - display: 'flex', - flexDirection: 'column', - marginBottom: theme.spacing(1), - '& div': { - display: 'flex', - alignItems: 'center', - marginBottom: 2, - '& svg': { marginRight: 8 }, - }, +const StyledPaper = styled(Paper)(({ theme }) => ({ + position: 'absolute', + padding: theme.spacing(2), + width: 'max-content', + maxWidth: '90%', + left: '50%', + top: '50%', + transform: 'translate(-50%, -50%)', + outline: 'none', +})); + +const CancelButton = styled(Button)({ + marginLeft: 8, + backgroundColor: Colors.grey200, + color: Colors.white, + '&:hover': { + backgroundColor: Colors.grey400, }, }); -const UploadQueue = ({ classes, device, open, onClose, update }) => { +const UploadQueue = ({ device, open, onClose, update }) => { const dispatch = useDispatch(); const filesUploading = useSelector((state) => state.filesUploading); const filesUploadingMeta = useSelector((state) => state.filesUploadingMeta); @@ -202,39 +121,62 @@ const UploadQueue = ({ classes, device, open, onClose, update }) => { }} /> - -
+ + Upload queue {device.dongle_id} -
+ -
+ ({ + margin: `${theme.spacing(1)} 0`, + color: Colors.white, + textAlign: 'left', + overflowY: 'auto', + })} + style={{ maxHeight: windowHeight * 0.9 - 98 }} + > {hasUploading ? ( <> {deviceOnCellular(device) && allPaused && ( -
+ ({ + backgroundColor: Colors.grey500, + padding: `${theme.spacing(1.5)} ${theme.spacing(2)}`, + borderRadius: '4px', + display: 'flex', + flexDirection: 'column', + marginBottom: theme.spacing(1), + '& div': { + display: 'flex', + alignItems: 'center', + marginBottom: '2px', + '& svg': { marginRight: '8px' }, + }, + })} + >
Connect to WiFi
uploading paused on cellular connection -
+
)} - + - - - - {windowWidth >= 600 && @@ -245,44 +187,91 @@ const UploadQueue = ({ classes, device, open, onClose, update }) => { const segString = seg.split('|')[1]; return ( - - + {upload.current ? ( - + + ) : ( <> {windowWidth >= 600 && ( - + )} - + )} ); })} -
+ segment - + + type - + + progress - } + + {windowWidth >= 600 && }
-
+ + {segString.substring(0, 12)} {segString.substring(12)} -
-
+ + + {FILE_NAMES[type][0].split('.')[0].substring(0, logNameLength)} - -
+ + div': { + width: '80%', + height: 8, + marginRight: '6px', + border: 'none', + backgroundColor: Colors.white30, + '& > div': { + backgroundColor: Colors.white80, + transition: 'transform 0.5s linear', + }, + }, + }} + > -
-
+ {upload.paused ? 'paused' : 'pending'} - + {isCancelled ? ( - + ) : ( )} -
+ ) : deviceOffline ? (

device offline

@@ -291,19 +280,19 @@ const UploadQueue = ({ classes, device, open, onClose, update }) => { ) : ( )} -
-
- - -
-
+ + +
); }; -export default withStyles(styles)(UploadQueue); +export default UploadQueue; diff --git a/src/components/IosPwaPopup/index.jsx b/src/components/IosPwaPopup/index.jsx index 8eceaca4..702e651d 100644 --- a/src/components/IosPwaPopup/index.jsx +++ b/src/components/IosPwaPopup/index.jsx @@ -1,6 +1,6 @@ import MyCommaAuth from '@commaai/my-comma-auth'; import { Typography } from '@mui/material'; -import { withStyles } from '@mui/styles'; +import { styled } from '@mui/material/styles'; import { Clear } from '@mui/icons-material'; import localforage from 'localforage'; import { useCallback, useEffect, useRef, useState } from 'react'; @@ -10,45 +10,46 @@ import Colors from '../../colors'; import { IosShareIcon } from '../../icons'; import { isIos } from '../../utils/browser.js'; -const styles = () => ({ - box: { - margin: '0 auto', - borderRadius: 22, - padding: '12px 20px', - color: Colors.white, - display: 'flex', - flexDirection: 'column', - backgroundColor: Colors.grey500, - border: `1px solid ${Colors.grey700}`, - }, - hide: { - cursor: 'pointer', - padding: 5, - fontSize: 20, - position: 'relative', - left: -30, - top: -24, - marginBottom: -32, - height: 32, - width: 32, - borderRadius: 16, - backgroundColor: Colors.grey900, - color: Colors.white, - border: `1px solid ${Colors.grey600}`, - }, - title: { - lineHeight: '31px', - fontSize: 20, - fontWeight: 600, - }, - icon: { - display: 'inline', - verticalAlign: 'text-bottom', - margin: '0 3px', - }, +const PopupBox = styled('div')({ + margin: '0 auto', + borderRadius: 22, + padding: '12px 20px', + color: Colors.white, + display: 'flex', + flexDirection: 'column', + backgroundColor: Colors.grey500, + border: `1px solid ${Colors.grey700}`, }); -const IosPwaPopup = ({ classes }) => { +const HideButton = styled(Clear)({ + cursor: 'pointer', + padding: 5, + fontSize: 20, + position: 'relative', + left: -30, + top: -24, + marginBottom: -32, + height: 32, + width: 32, + borderRadius: 16, + backgroundColor: Colors.grey900, + color: Colors.white, + border: `1px solid ${Colors.grey600}`, +}); + +const Title = styled(Typography)({ + lineHeight: '31px', + fontSize: 20, + fontWeight: 600, +}); + +const ShareIconImg = styled('img')({ + display: 'inline', + verticalAlign: 'text-bottom', + margin: '0 3px', +}); + +const IosPwaPopup = () => { const [show, setShow] = useState(false); const windowEventsRef = useRef(0); const location = useLocation(); @@ -114,16 +115,16 @@ const IosPwaPopup = ({ classes }) => { return (
-
- - Add to home screen + + + Add to home screen Install this webapp on your home screen:
- tap share and then ‘Add to Home Screen’ + tap and then ‘Add to Home Screen’
-
+
); }; -export default withStyles(styles)(IosPwaPopup); +export default IosPwaPopup; diff --git a/src/components/Navigation/index.jsx b/src/components/Navigation/index.jsx index 1411750c..5e974943 100644 --- a/src/components/Navigation/index.jsx +++ b/src/components/Navigation/index.jsx @@ -1,6 +1,6 @@ import { athena as Athena, devices as Devices } from '@commaai/api'; -import { Button, Typography } from '@mui/material'; -import { withStyles } from '@mui/styles'; +import { Box, Button, Typography } from '@mui/material'; +import { styled } from '@mui/material/styles'; import { Clear } from '@mui/icons-material'; import * as Sentry from '@sentry/react'; import dayjs from 'dayjs'; @@ -17,120 +17,133 @@ import ResizeHandler from '../ResizeHandler'; import VisibilityHandler from '../VisibilityHandler'; import * as Utils from './utils'; -const styles = () => ({ - mapContainer: { - borderBottom: `1px solid ${Colors.white10}`, - }, - mapError: { - position: 'relative', - marginTop: 20, - marginLeft: 20, - '& p': { color: Colors.white50 }, - }, - geolocateControl: { - display: 'none', - }, - searchSelectBox: { - borderRadius: 22, - padding: '12px 16px', - border: `1px solid ${Colors.white10}`, - backgroundColor: Colors.grey800, - color: Colors.white, - display: 'flex', - flexDirection: 'column', - }, - searchSelectBoxHeader: { - display: 'flex', - width: '100%', - justifyContent: 'space-between', - alignItems: 'flex-start', - marginBottom: 10, - }, - searchSelectBoxTitle: { - flexBasis: 'auto', - }, - searchSelectBoxButtons: { - display: 'flex', - flexWrap: 'wrap-reverse', - justifyContent: 'flex-end', - alignItems: 'flex-end', - }, - bold: { - fontWeight: 600, - }, - primeAdTitle: { - lineHeight: '31px', - fontSize: 20, - fontWeight: 600, - }, - searchSelectButton: { - marginLeft: 8, - padding: '6px 12px', - backgroundColor: Colors.white, - borderRadius: 15, +const MapContainer = styled(Box)({ + borderBottom: `1px solid ${Colors.white10}`, +}); + +const MapError = styled(Box)({ + position: 'relative', + marginTop: 20, + marginLeft: 20, + '& p': { color: Colors.white50 }, +}); + +const GeolocateControlStyled = styled(GeolocateControl)({ + display: 'none', +}); + +const SearchSelectBox = styled(Box)({ + borderRadius: 22, + padding: '12px 16px', + border: `1px solid ${Colors.white10}`, + backgroundColor: Colors.grey800, + color: Colors.white, + display: 'flex', + flexDirection: 'column', +}); + +const SearchSelectBoxHeader = styled(Box)({ + display: 'flex', + width: '100%', + justifyContent: 'space-between', + alignItems: 'flex-start', + marginBottom: 10, +}); + +const SearchSelectBoxTitle = styled(Box)({ + flexBasis: 'auto', +}); + +const SearchSelectBoxButtons = styled(Box)({ + display: 'flex', + flexWrap: 'wrap-reverse', + justifyContent: 'flex-end', + alignItems: 'flex-end', +}); + +const BoldTypography = styled(Typography)({ + fontWeight: 600, +}); + +const PrimeAdTitle = styled(Typography)({ + lineHeight: '31px', + fontSize: 20, + fontWeight: 600, +}); + +const SearchSelectButton = styled(Button)({ + marginLeft: 8, + padding: '6px 12px', + backgroundColor: Colors.white, + borderRadius: 15, + color: Colors.grey900, + textTransform: 'none', + minHeight: 'unset', + flexGrow: 1, + maxWidth: 125, + '&:hover': { + background: '#ddd', color: Colors.grey900, - textTransform: 'none', - minHeight: 'unset', - flexGrow: 1, - maxWidth: 125, - '&:hover': { - background: '#ddd', - color: Colors.grey900, - }, - '&:disabled': { - background: '#ddd', - color: Colors.grey900, - }, - }, - searchSelectBoxDetails: { - color: Colors.white40, - }, - primeAdContainer: { - backgroundColor: Colors.grey500, - border: `1px solid ${Colors.grey700}`, }, - primeAdButton: { - padding: '6px 24px', - color: Colors.white, - backgroundColor: Colors.primeBlue50, - '&:hover': { - color: Colors.white, - backgroundColor: Colors.primeBlue200, - }, - }, - pin: { - width: 20, - height: 32, + '&:disabled': { + background: '#ddd', + color: Colors.grey900, }, - carPinTooltip: { - textAlign: 'center', - borderRadius: 14, - fontSize: '0.8em', - padding: '6px 8px', - border: `1px solid ${Colors.white10}`, - backgroundColor: Colors.grey800, +}); + +const SearchSelectBoxDetails = styled(Typography)({ + color: Colors.white40, +}); + +const PrimeAdContainer = styled(SearchSelectBox)({ + backgroundColor: Colors.grey500, + border: `1px solid ${Colors.grey700}`, +}); + +const PrimeAdButton = styled(SearchSelectButton)({ + padding: '6px 24px', + color: Colors.white, + backgroundColor: Colors.primeBlue50, + '&:hover': { color: Colors.white, + backgroundColor: Colors.primeBlue200, }, - clearSearchSelect: { - padding: 5, - fontSize: 20, - cursor: 'pointer', - position: 'absolute', - left: -6, - top: -8, - height: 24, - width: 24, - borderRadius: 12, - backgroundColor: Colors.grey900, - color: Colors.white, - border: `1px solid ${Colors.grey600}`, - '&:hover': { - backgroundColor: Colors.grey700, - }, +}); + +const Pin = styled(PinCarIcon)({ + width: 20, + height: 32, +}); + +const CarPinTooltip = styled(Box)({ + textAlign: 'center', + borderRadius: 14, + fontSize: '0.8em', + padding: '6px 8px', + border: `1px solid ${Colors.white10}`, + backgroundColor: Colors.grey800, + color: Colors.white, +}); + +const ClearSearchSelect = styled(Clear)({ + padding: 5, + fontSize: 20, + cursor: 'pointer', + position: 'absolute', + left: -6, + top: -8, + height: 24, + width: 24, + borderRadius: 12, + backgroundColor: Colors.grey900, + color: Colors.white, + border: `1px solid ${Colors.grey600}`, + '&:hover': { + backgroundColor: Colors.grey700, }, }); -const Navigation = ({ classes }) => { +const Navigation = () => { // Redux state const dongleId = useSelector((state) => state.dongleId); const device = useSelector((state) => state.device); @@ -474,49 +487,48 @@ const Navigation = ({ classes }) => { } return ( -
- -
-
- {title} - {timeFromNow(carLocation.time)} -
-
- -
-
- + + + + {Utils.formatPlaceName(searchSelect)} {Utils.formatPlaceAddress(searchSelect)} - -
+ + ); }; const renderPrimeAd = () => { return ( -
- + { setShowPrimeAd(false); flyToMarkers(); }} /> -
-
- comma prime -
-
- -
-
- Put your car on the internet with comma prime -
+ + + + Put your car on the internet with comma prime + ); }; @@ -576,14 +588,14 @@ const Navigation = ({ classes }) => { } return ( -
+ {mapError && ( -
+ Could not initialize map. {mapError} -
+ )} { dragRotate={false} onError={(err) => setMapError(err.error.message)} > - { captureClick captureDoubleClick={false} > - toggleCarPinTooltip(true)} - onMouseLeave={() => toggleCarPinTooltip(false)} - alt="car-location" - onClick={() => onCarSelect(carLocation)} - /> -
+ toggleCarPinTooltip(true)} onMouseLeave={() => toggleCarPinTooltip(false)} alt="car-location" onClick={() => onCarSelect(carLocation)} /> + {dayjs(carLocation.time).format('h:mm A')} ,
{timeFromNow(carLocation.time)} -
+ )} {carLocation && Boolean(carLocation.accuracy) && ( @@ -658,8 +663,8 @@ const Navigation = ({ classes }) => { /> )}
-
+ ); }; -export default withStyles(styles)(Navigation); +export default Navigation; diff --git a/src/components/Prime/PrimeCheckout.jsx b/src/components/Prime/PrimeCheckout.jsx index 3aa97c36..8060991d 100644 --- a/src/components/Prime/PrimeCheckout.jsx +++ b/src/components/Prime/PrimeCheckout.jsx @@ -1,6 +1,6 @@ import { billing as Billing } from '@commaai/api'; -import { Button, CircularProgress, IconButton, Typography } from '@mui/material'; -import { withStyles } from '@mui/styles'; +import { Box, Button, CircularProgress, IconButton, Typography } from '@mui/material'; +import { styled } from '@mui/material/styles'; import CheckIcon from '@mui/icons-material/Check'; import KeyboardBackspaceIcon from '@mui/icons-material/KeyboardBackspace'; import * as Sentry from '@sentry/react'; @@ -13,198 +13,191 @@ import { navigate } from '../../navigation'; import { deviceNamePretty } from '../../utils'; import ResizeHandler from '../ResizeHandler'; -const styles = () => ({ - linkHighlight: { - '&:link': { - textDecoration: 'underline', - color: Colors.green300, - }, - '&:visited': { - textDecoration: 'underline', - color: Colors.green300, - }, - '&:active': { - textDecoration: 'underline', - color: Colors.green300, - }, - '&:hover': { - textDecoration: 'underline', - color: Colors.green400, - }, +const LinkHighlight = styled('a')({ + '&:link': { + textDecoration: 'underline', + color: Colors.green300, }, - primeBox: { - display: 'flex', - flexDirection: 'column', - maxWidth: 430, - color: '#fff', + '&:visited': { + textDecoration: 'underline', + color: Colors.green300, }, - primeHeader: { - display: 'flex', - alignItems: 'center', - justifyContent: 'space-between', - maxWidth: 410, - flexDirection: 'row', + '&:active': { + textDecoration: 'underline', + color: Colors.green300, }, - headerDevice: { - display: 'flex', - alignItems: 'center', - '& :first-child': { marginRight: 8 }, + '&:hover': { + textDecoration: 'underline', + color: Colors.green400, }, - primeBlock: { - marginTop: 10, - }, - moreInfoContainer: { - '& p': { display: 'inline' }, - '& button': { display: 'inline', marginLeft: '15px' }, - }, - deviceId: { - color: '#525E66', - }, - leftMargin: { - marginLeft: 10, - }, - deviceBlock: { - marginLeft: 10, - '& aside': { display: 'inline', marginRight: 5 }, - '& span': { display: 'inline' }, - }, - overviewBlockError: { - borderRadius: 12, - marginTop: 8, - padding: '8px 12px', - display: 'flex', - alignItems: 'center', - backgroundColor: 'rgba(255, 0, 0, 0.2)', - '& p': { display: 'inline-block', marginLeft: 10 }, - }, - overviewBlockDisabled: { - marginTop: 12, - borderRadius: 12, - padding: '8px 12px', - display: 'flex', - alignItems: 'center', - backgroundColor: Colors.white08, - '& p': { display: 'inline-block', marginLeft: 10 }, - '& a': { color: Colors.white }, - }, - chargeText: { - fontSize: 13, - }, - buttons: { - width: '100%', - height: 42, - borderRadius: 21, - background: Colors.white, +}); + +const PrimeBox = styled(Box)({ + display: 'flex', + flexDirection: 'column', + maxWidth: 430, + color: '#fff', +}); + +const PrimeHeader = styled(Box)({ + display: 'flex', + alignItems: 'center', + justifyContent: 'space-between', + maxWidth: 410, + flexDirection: 'row', +}); + +const HeaderDevice = styled(Box)({ + display: 'flex', + alignItems: 'center', + '& :first-child': { marginRight: 8 }, +}); + +const DeviceId = styled(Typography)({ + color: '#525E66', +}); + +const OverviewBlockError = styled(Box)({ + borderRadius: 12, + marginTop: 8, + padding: '8px 12px', + display: 'flex', + alignItems: 'center', + backgroundColor: 'rgba(255, 0, 0, 0.2)', + '& p': { display: 'inline-block', marginLeft: 10 }, +}); + +const OverviewBlockDisabled = styled(Box)({ + marginTop: 12, + borderRadius: 12, + padding: '8px 12px', + display: 'flex', + alignItems: 'center', + backgroundColor: Colors.white08, + '& p': { display: 'inline-block', marginLeft: 10 }, + '& a': { color: Colors.white }, +}); + +const ChargeText = styled(Typography)({ + fontSize: 13, +}); + +const StyledButton = styled(Button)({ + width: '100%', + height: 42, + borderRadius: 21, + background: Colors.white, + color: Colors.grey900, + textTransform: 'none', + '&:hover': { + backgroundColor: Colors.white70, color: Colors.grey900, - textTransform: 'none', - '&:hover': { - backgroundColor: Colors.white70, - color: Colors.grey900, - }, - '&:disabled': { - backgroundColor: Colors.white70, - color: Colors.grey900, - }, - '&:disabled:hover': { - backgroundColor: Colors.white70, - color: Colors.grey900, - }, - }, - checkList: { - marginLeft: 12, - }, - checkListItem: { - display: 'flex', - alignItems: 'center', - marginBottom: 4, - '& svg': { - alignSelf: 'flex-start', - fontSize: 21, - }, - '& p': { - fontSize: 14, - margin: '0 0 0 14px', - }, - '& span': { - color: Colors.white70, - fontSize: 12, - }, - }, - learnMore: { - '& a': { color: 'white' }, }, - primeTitle: { - margin: '0 12px', - }, - planBox: { - display: 'flex', - flexDirection: 'row', - justifyContent: 'space-around', - height: 140, - }, - planBoxContainer: { - position: 'relative', - marginLeft: -6, - marginRight: -6, - }, - plan: { - cursor: 'pointer', - WebkitTapHighlightColor: 'transparent', - width: 160, - display: 'flex', - flexDirection: 'column', - alignItems: 'center', - justifyContent: 'space-around', - border: '2px solid transparent', - backgroundColor: Colors.white10, - padding: '8px 0', - borderRadius: 18, - fontWeight: 600, - textAlign: 'center', - position: 'relative', - '&:first-child': { marginRight: 2 }, - '&:last-child': { marginLeft: 2 }, - '& p': { - margin: 0, - }, + '&:disabled': { + backgroundColor: Colors.white70, + color: Colors.grey900, }, - planName: { - fontSize: '1.2rem', + '&:disabled:hover': { + backgroundColor: Colors.white70, + color: Colors.grey900, }, - planPrice: { - fontSize: '1.5rem', +}); + +const CheckList = styled(Box)({ + marginLeft: 12, +}); + +const CheckListItem = styled(Box)({ + display: 'flex', + alignItems: 'center', + marginBottom: 4, + '& svg': { + alignSelf: 'flex-start', + fontSize: 21, }, - planSubtext: { - fontWeight: 'normal', - fontSize: '0.8rem', + '& p': { + fontSize: 14, + margin: '0 0 0 14px', }, - planDisabled: { - backgroundColor: Colors.white05, - color: Colors.white40, - cursor: 'default', + '& span': { + color: Colors.white70, + fontSize: 12, }, - planInfoLoading: { - backgroundColor: Colors.white03, - color: Colors.white20, - cursor: 'default', +}); + +const LearnMore = styled(Typography)({ + '& a': { color: 'white' }, +}); + +const PrimeTitle = styled('h2')({ + margin: '0 12px', +}); + +const PlanBox = styled(Box)({ + display: 'flex', + flexDirection: 'row', + justifyContent: 'space-around', + height: 140, +}); + +const PlanBoxContainer = styled(Box)({ + position: 'relative', + marginLeft: -6, + marginRight: -6, +}); + +const Plan = styled(Box)(({ selected, disabled, loading }) => ({ + cursor: disabled || loading ? 'default' : 'pointer', + WebkitTapHighlightColor: 'transparent', + width: 160, + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'space-around', + border: selected ? '2px solid white' : '2px solid transparent', + backgroundColor: loading ? Colors.white03 : disabled ? Colors.white05 : Colors.white10, + color: loading ? Colors.white20 : disabled ? Colors.white40 : 'inherit', + padding: '8px 0', + borderRadius: 18, + fontWeight: 600, + textAlign: 'center', + position: 'relative', + '&:first-of-type': { marginRight: 2 }, + '&:last-of-type': { marginLeft: 2 }, + '& p': { + margin: 0, }, - planLoading: { - position: 'absolute', - top: 0, - width: '100%', - display: 'flex', - flexDirection: 'column', - alignItems: 'center', - justifyContent: 'center', - height: 140, - '& p': { - marginTop: 10, - fontSize: '0.9rem', - }, +})); + +const PlanName = styled('p')({ + fontSize: '1.2rem', +}); + +const PlanPrice = styled('p')({ + fontSize: '1.5rem', +}); + +const PlanSubtext = styled('p')({ + fontWeight: 'normal', + fontSize: '0.8rem', +}); + +const PlanLoading = styled(Box)({ + position: 'absolute', + top: 0, + width: '100%', + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + height: 140, + '& p': { + marginTop: 10, + fontSize: '0.9rem', }, }); -const PrimeCheckout = ({ classes }) => { +const PrimeCheckout = () => { const dongleId = useSelector((state) => state.dongleId); const device = useSelector((state) => state.device); const subscribeInfo = useSelector((state) => state.subscribeInfo); @@ -290,8 +283,7 @@ const PrimeCheckout = ({ classes }) => { const containerPadding = windowWidth > 520 ? { margin: '18px 24px' } : { margin: '6px 12px' }; const blockMargin = windowWidth > 520 ? { marginTop: 24 } : { marginTop: 8 }; const paddingStyle = windowWidth > 520 ? { paddingLeft: 7, paddingRight: 7 } : { paddingLeft: 8, paddingRight: 8 }; - const selectedStyle = { border: '2px solid white' }; - const plansLoadingClass = !subscribeInfo ? classes.planInfoLoading : ''; + const plansLoading = !subscribeInfo; const disabledDataPlan = Boolean(!subscribeInfo || !dataPlanAvailable()); const boxHeight = windowHeight > 600 ? { height: 140 } : { height: 110 }; @@ -308,128 +300,120 @@ const PrimeCheckout = ({ classes }) => { } else if (!['blue', 'magenta_new', 'webbing'].includes(subscribeInfo.sim_type)) { disabledDataPlanText = [ 'Standard plan not available, old SIM type detected, new SIM cards are available in the ', - + shop - , + , ]; } else if (subscribeInfo.sim_usable === false && subscribeInfo.sim_type === 'blue') { disabledDataPlanText = [ 'Standard plan not available, SIM has been canceled and is therefore no longer usable, new SIM cards are available in the ', - + shop - , + , ]; } else if (subscribeInfo.sim_usable === false) { disabledDataPlanText = [ 'Standard plan not available, SIM is no longer usable, new SIM cards are available in the ', - + shop - , + , ]; } } return ( -
+ -
+ navigate(`/${dongleId}`)}> -
+ {deviceNamePretty(device)} - {`(${device.dongle_id})`} -
-
-

comma prime

-
-
-
+ {`(${device.dongle_id})`} + + + comma prime + + +

24/7 connectivity

-
-
+ +

Take pictures remotely

-
-
+ +

1 year storage of drive videos

-
-
+ +

Simple SSH for developers

-
-
-
-
-
-
setSelectedPlan('nodata') : null} - > -

lite

-

$10/month

-

+ + + + + + setSelectedPlan('nodata') : null}> + lite + $10/month + bring your own
sim card -

-
-
setSelectedPlan('data') : null} - > -

standard

-

$24/month

-

+ + + setSelectedPlan('data') : null}> + standard + $24/month + including data plan
only offered in the U.S. -

-
-
+ + + {!subscribeInfo && ( -
+ Fetching SIM data -
+ )} -
+ {disabledDataPlanText && ( -
+ {disabledDataPlanText} -
+ )} -
- + + {'Learn more about comma prime from our '} - + FAQ - - -
+ + + {error && ( -
+ {error} -
+ )} -
- -
+ + {chargeText && ( -
- {chargeText} -
+ + {chargeText} + )} -
+ ); }; -export default withStyles(styles)(PrimeCheckout); +export default PrimeCheckout; diff --git a/src/components/Prime/PrimeManage.jsx b/src/components/Prime/PrimeManage.jsx index bb5693b0..68af298b 100644 --- a/src/components/Prime/PrimeManage.jsx +++ b/src/components/Prime/PrimeManage.jsx @@ -1,6 +1,6 @@ import { billing as Billing } from '@commaai/api'; -import { Button, CircularProgress, IconButton, Modal, Paper, Typography } from '@mui/material'; -import { withStyles } from '@mui/styles'; +import { Box, Button, CircularProgress, IconButton, Modal, Paper, Typography } from '@mui/material'; +import { styled } from '@mui/material/styles'; import KeyboardBackspaceIcon from '@mui/icons-material/KeyboardBackspace'; import PriorityHighIcon from '@mui/icons-material/PriorityHigh'; import * as Sentry from '@sentry/react'; @@ -14,177 +14,193 @@ import { navigate } from '../../navigation'; import { deviceNamePretty, deviceTypePretty } from '../../utils'; import ResizeHandler from '../ResizeHandler'; -const styles = (theme) => ({ - linkHighlight: { - '&:link': { - textDecoration: 'underline', - color: Colors.green300, - }, - '&:visited': { - textDecoration: 'underline', - color: Colors.green300, - }, - '&:active': { - textDecoration: 'underline', - color: Colors.green300, - }, - '&:hover': { - textDecoration: 'underline', - color: Colors.green400, - }, +const LinkHighlight = styled('a')({ + '&:link': { + textDecoration: 'underline', + color: Colors.green300, }, - primeBox: { - display: 'flex', - flexDirection: 'column', + '&:visited': { + textDecoration: 'underline', + color: Colors.green300, }, - primeContainer: { - borderBottom: `1px solid ${Colors.white10}`, - color: '#fff', + '&:active': { + textDecoration: 'underline', + color: Colors.green300, }, - primeBlock: { - marginTop: 10, - }, - overviewBlock: { - marginTop: 20, + '&:hover': { + textDecoration: 'underline', + color: Colors.green400, }, - overviewBlockError: { - marginTop: 15, - padding: 10, - display: 'flex', - alignItems: 'center', - backgroundColor: 'rgba(255, 0, 0, 0.2)', - '& p': { display: 'inline-block', marginLeft: 10 }, - }, - overviewBlockSuccess: { - marginTop: 15, - padding: 10, - alignItems: 'center', - backgroundColor: 'rgba(0, 255, 0, 0.2)', - '& p': { - display: 'inline-block', - marginLeft: 10, - '&:first-child': { fontWeight: 600 }, - }, +}); + +const PrimeBox = styled(Box)({ + display: 'flex', + flexDirection: 'column', +}); + +const PrimeContainer = styled(Box)({ + borderBottom: `1px solid ${Colors.white10}`, + color: '#fff', +}); + +const OverviewBlock = styled(Box)({ + marginTop: 20, +}); + +const OverviewBlockError = styled(Box)({ + marginTop: 15, + padding: 10, + display: 'flex', + alignItems: 'center', + backgroundColor: 'rgba(255, 0, 0, 0.2)', + '& p': { display: 'inline-block', marginLeft: 10 }, +}); + +const OverviewBlockSuccess = styled(Box)({ + marginTop: 15, + padding: 10, + alignItems: 'center', + backgroundColor: 'rgba(0, 255, 0, 0.2)', + '& p': { + display: 'inline-block', + marginLeft: 10, + '&:first-child': { fontWeight: 600 }, }, - overviewBlockLoading: { - marginTop: 15, - padding: 10, - display: 'flex', - alignItems: 'center', - backgroundColor: 'rgba(0, 0, 0, 0.2)', - '& p': { display: 'inline-block', marginLeft: 10 }, +}); + +const OverviewBlockLoading = styled(Box)({ + marginTop: 15, + padding: 10, + display: 'flex', + alignItems: 'center', + backgroundColor: 'rgba(0, 0, 0, 0.2)', + '& p': { display: 'inline-block', marginLeft: 10 }, +}); + +const OverviewBlockDisabled = styled(Box)({ + marginTop: 12, + borderRadius: 12, + padding: '8px 12px', + display: 'flex', + alignItems: 'center', + backgroundColor: Colors.white08, + '& p': { display: 'inline-block', marginLeft: 10 }, + '& a': { color: 'white' }, +}); + +const ManageItem = styled(Typography)({ + marginLeft: 10, + '& span': { + color: Colors.white70, + fontSize: '0.9em', }, - overviewBlockDisabled: { - marginTop: 12, - borderRadius: 12, - padding: '8px 12px', - display: 'flex', - alignItems: 'center', - backgroundColor: Colors.white08, - '& p': { display: 'inline-block', marginLeft: 10 }, - '& a': { color: 'white' }, +}); + +const StyledButton = styled(Button)({ + marginTop: 10, + background: Colors.white, + borderRadius: 18, + color: Colors.grey900, + textTransform: 'none', + width: 220, + '&:hover': { + backgroundColor: Colors.white70, + color: Colors.grey900, }, - manageItem: { - marginLeft: 10, - '& span': { - color: Colors.white70, - fontSize: '0.9em', - }, + '&:disabled': { + backgroundColor: Colors.white70, + color: Colors.grey900, }, - buttons: { - marginTop: 10, - background: Colors.white, - borderRadius: 18, + '&:disabled:hover': { + backgroundColor: Colors.white70, color: Colors.grey900, - textTransform: 'none', - width: 220, - '&:hover': { - backgroundColor: Colors.white70, - color: Colors.grey900, - }, - '&:disabled': { - backgroundColor: Colors.white70, - color: Colors.grey900, - }, - '&:disabled:hover': { - backgroundColor: Colors.white70, - color: Colors.grey900, - }, }, - cancelButton: { +}); + +const CancelButton = styled(Button)({ + marginTop: 10, + color: Colors.white, + background: 'transparent', + border: `1px solid ${Colors.grey500}`, + borderRadius: 18, + textTransform: 'none', + width: 220, + '&:hover': { + backgroundColor: Colors.white10, color: Colors.white, - background: 'transparent', - border: `1px solid ${Colors.grey500}`, - '&:hover': { - backgroundColor: Colors.white10, - color: Colors.white, - }, - '&:disabled': { - backgroundColor: 'transparent', - color: Colors.grey500, - }, - '&:disabled:hover': { - backgroundColor: 'transparent', - color: Colors.grey500, - }, }, - modal: { - position: 'absolute', - padding: theme.spacing(2), - width: theme.spacing(50), - maxWidth: '90%', - left: '50%', - top: '40%', - transform: 'translate(-50%, -50%)', - '& p': { - marginTop: 10, - }, + '&:disabled': { + backgroundColor: 'transparent', + color: Colors.grey500, }, - closeButton: { - marginTop: 10, - float: 'right', - backgroundColor: Colors.grey200, - color: Colors.white, - '&:hover': { - backgroundColor: Colors.grey400, - }, + '&:disabled:hover': { + backgroundColor: 'transparent', + color: Colors.grey500, }, - cancelModalButton: { - width: 170, +}); + +const StyledModal = styled(Paper)(({ theme }) => ({ + position: 'absolute', + padding: theme.spacing(2), + width: theme.spacing(50), + maxWidth: '90%', + left: '50%', + top: '40%', + transform: 'translate(-50%, -50%)', + '& p': { marginTop: 10, - backgroundColor: Colors.grey200, - color: Colors.white, - '&:hover': { - backgroundColor: Colors.grey400, - }, - '&:disabled': { - backgroundColor: Colors.grey400, - }, - '&:disabled:hover': { - backgroundColor: Colors.grey400, - }, }, - cancelError: { - backgroundColor: 'rgba(255, 0, 0, 0.3)', - marginTop: 10, - padding: 10, - '& p': { margin: 0 }, +})); + +const CloseButton = styled(Button)({ + marginTop: 10, + float: 'right', + backgroundColor: Colors.grey200, + color: Colors.white, + '&:hover': { + backgroundColor: Colors.grey400, }, - cancelSuccess: { - backgroundColor: 'rgba(0, 255, 0, 0.3)', - marginTop: 10, - padding: 10, - '& p': { margin: 0 }, +}); + +const CancelModalButton = styled(Button)({ + width: 170, + marginTop: 10, + backgroundColor: Colors.grey200, + color: Colors.white, + '&:hover': { + backgroundColor: Colors.grey400, }, - paymentElement: { - display: 'flex', - flexWrap: 'wrap', - justifyContent: 'space-between', - maxWidth: 450, + '&:disabled': { + backgroundColor: Colors.grey400, }, + '&:disabled:hover': { + backgroundColor: Colors.grey400, + }, +}); + +const CancelError = styled(Box)({ + backgroundColor: 'rgba(255, 0, 0, 0.3)', + marginTop: 10, + padding: 10, + '& p': { margin: 0 }, +}); + +const CancelSuccess = styled(Box)({ + backgroundColor: 'rgba(0, 255, 0, 0.3)', + marginTop: 10, + padding: 10, + '& p': { margin: 0 }, +}); + +const PaymentElement = styled(Box)({ + marginTop: 20, + display: 'flex', + flexWrap: 'wrap', + justifyContent: 'space-between', + maxWidth: 450, }); -const PrimeManage = ({ classes }) => { +const PrimeManage = () => { const dispatch = useDispatch(); const dongleId = useSelector((state) => state.dongleId); const device = useSelector((state) => state.device); @@ -334,153 +350,144 @@ const PrimeManage = ({ classes }) => { return ( <> -
-
+ + navigate(`/${dongleId}`)}> -
-
+ + comma prime {stripeStatus && ( <> {stripeStatus.paid !== 'paid' && ( -
+ Waiting for confirmed payment -
+ )} {Boolean(stripeStatus.paid === 'paid' && !hasPrimeSub) && ( -
+ Processing subscription -
+ )} {Boolean(stripeStatus.paid === 'paid' && hasPrimeSub) && ( -
+ comma prime activated {subscription.is_prime_sim && ( Connectivity will be enabled as soon as activation propagates to your local cell tower. Rebooting your device may help. )} -
+ )} )} -
+ Device -
- {alias} - - {`(${device.dongle_id})`} + + {alias} + + {` (${device.dongle_id})`} -
-
+ + {hasPrimeSub && ( <> -
+ Plan - + {planName} {` ${planSubtext}`} - -
-
+ + + Joined - {joinDate} -
+ {joinDate} + {!hasCancelAt && ( -
+ Next payment - {nextPaymentDate} -
+ {nextPaymentDate} + )} {hasCancelAt && ( -
+ Subscription end - {cancelAtDate} -
+ {cancelAtDate} + )} -
+ Amount - {`$${(subscription.amount / 100).toFixed(2)}`} -
+ {`$${(subscription.amount / 100).toFixed(2)}`} + {error && ( -
+ {error} -
+ )} -
- + {!hasCancelAt && ( - + )} -
+ {hasPrimeSub && subscription.requires_migration && ( -
+ Your prime subscription will be canceled on May 15th unless you replace the SIM card in your device. A new SIM card can be ordered from the - - shop - - . Use discount code SIMSWAP at checkout to receive a free SIM card. + shop. Use discount code SIMSWAP at checkout to receive a free SIM card. -
+ )} {hasCancelAt && !device.eligible_features?.prime_data && subscription.plan === 'data' && ( -
+ Standard comma prime discontinued for {deviceTypePretty(device.device_type)} -
+ )} )} -
-
+ + setCancelModal(false)}> - + Cancel prime subscription {cancelError && ( -
+ {cancelError} -
+ )} {cancelSuccess && ( -
+ {cancelSuccess} -
+ )} {`Device: ${alias} (${dongleId})`} We're sorry to see you go. Your subscription will be cancelled immediately and can be resumed at any time. - - -
+ +
); }; -export default withStyles(styles)(PrimeManage); +export default PrimeManage; diff --git a/src/components/TimeDisplay/index.jsx b/src/components/TimeDisplay/index.jsx index b757a390..6c684793 100644 --- a/src/components/TimeDisplay/index.jsx +++ b/src/components/TimeDisplay/index.jsx @@ -1,6 +1,6 @@ import { Tooltip } from '@mui/material'; import IconButton from '@mui/material/IconButton'; -import { withStyles } from '@mui/styles'; +import { styled } from '@mui/material/styles'; import Typography from '@mui/material/Typography'; import VolumeOff from '@mui/icons-material/VolumeOff'; import VolumeUp from '@mui/icons-material/VolumeUp'; @@ -17,83 +17,73 @@ import { isIos } from '../../utils/browser.js'; const timerSteps = [0.1, 0.25, 0.5, 1, 2, 4, 8]; -const styles = (theme) => ({ - base: { - display: 'flex', - alignItems: 'center', - backgroundColor: theme.palette.grey[999], - height: '64px', - borderRadius: '32px', - padding: theme.spacing(1), - width: 400, - maxWidth: '100%', - margin: '0 auto', - opacity: 0, - pointerEvents: 'none', - transition: 'opacity 0.1s ease-in-out', - '&.isExpanded': { - opacity: 1, - pointerEvents: 'auto', - }, - '&.isThin': { - height: 50, - paddingBottom: 0, - paddingTop: 0, - }, +const Base = styled('div')(({ theme }) => ({ + display: 'flex', + alignItems: 'center', + backgroundColor: theme.palette.grey[999], + height: '64px', + borderRadius: '32px', + padding: theme.spacing(1), + width: 400, + maxWidth: '100%', + margin: '0 auto', + opacity: 0, + pointerEvents: 'none', + transition: 'opacity 0.1s ease-in-out', + '&.isExpanded': { + opacity: 1, + pointerEvents: 'auto', }, - desiredPlaySpeedContainer: { - marginRight: theme.spacing(1), - display: 'flex', - flexDirection: 'column', - alignItems: 'center', - minWidth: '40px', + '&.isThin': { + height: 50, + paddingBottom: 0, + paddingTop: 0, }, - icon: { - width: '98%', - height: '98%', - '&.dim': { - color: theme.palette.grey[300], - }, - '&.small': { - width: '80%', - height: '80%', - }, - '&.circle': { - border: `1px solid ${theme.palette.grey[900]}`, - borderRadius: '50%', - }, - }, - iconButton: { - width: '40px', - height: '40px', - }, - tinyArrowIcon: { - width: 12, - height: 12, - color: theme.palette.grey[500], - '&[disabled]': { - visibility: 'hidden', - }, - }, - rightBorderBox: { - borderRight: `1px solid ${theme.palette.grey[900]}`, - }, - leftBorderBox: { - borderLeft: `1px solid ${theme.palette.grey[900]}`, - }, - currentTime: { - margin: `0 ${theme.spacing(1)}`, - fontSize: 15, - fontWeight: 500, - display: 'block', - flexGrow: 1, - }, - playbackLabel: { - paddingTop: 4, +})); + +const DesiredPlaySpeedContainer = styled('div')(({ theme }) => ({ + marginRight: theme.spacing(1), + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + minWidth: '40px', +})); + +const StyledIconButton = styled(IconButton)({ + width: '40px', + height: '40px', +}); + +const TinyArrowIcon = styled(IconButton)(({ theme }) => ({ + width: 12, + height: 12, + color: theme.palette.grey[500], + '&[disabled]': { + visibility: 'hidden', }, +})); + +const RightBorderBox = styled('div')(({ theme }) => ({ + borderRight: `1px solid ${theme.palette.grey[900]}`, +})); + +const LeftBorderBox = styled('div')(({ theme }) => ({ + borderLeft: `1px solid ${theme.palette.grey[900]}`, +})); + +const CurrentTime = styled(Typography)(({ theme }) => ({ + margin: `0 ${theme.spacing(1)}`, + fontSize: 15, + fontWeight: 500, + display: 'block', + flexGrow: 1, +})); + +const PlaybackLabel = styled(Typography)({ + paddingTop: 4, }); -const TimeDisplay = ({ classes, isThin, onMuteToggle, isMuted, hasAudio }) => { +const TimeDisplay = ({ isThin, onMuteToggle, isMuted, hasAudio }) => { const dispatch = useDispatch(); const currentRoute = useSelector((state) => selectCurrentRoute(state)); const zoom = useSelector((state) => selectRouteZoom(state)); @@ -201,54 +191,58 @@ const TimeDisplay = ({ classes, isThin, onMuteToggle, isMuted, hasAudio }) => { const isThinCls = isThin ? 'isThin' : ''; return ( -
-
- jumpBack(10000)} aria-label="Jump back 10 seconds"> - - -
-
- jumpForward(10000)} aria-label="Jump forward 10 seconds"> - - -
+ + + jumpBack(10000)} aria-label="Jump back 10 seconds"> + + + + + jumpForward(10000)} aria-label="Jump forward 10 seconds"> + + + {!isThin && ( - + CURRENT PLAYBACK TIME - + )} - + {getDisplayTime()} - + {!isIos() && ( -
- - - + + + + {desiredPlaySpeed}× - - - -
+ + + + )} -
+
- - {isMuted ? : } - + + {isMuted ? ( + ({ width: '80%', height: '80%', color: !hasAudio ? theme.palette.grey[300] : undefined })} /> + ) : ( + + )} +
-
-
- - {isPaused ? : } - -
-
+ + + + {isPaused ? : } + + + ); }; -export default withStyles(styles)(TimeDisplay); +export default TimeDisplay; diff --git a/src/components/TimeSelect/index.jsx b/src/components/TimeSelect/index.jsx index d168db78..67b4c701 100644 --- a/src/components/TimeSelect/index.jsx +++ b/src/components/TimeSelect/index.jsx @@ -1,52 +1,54 @@ import { Button, Divider, Modal, Paper, Typography } from '@mui/material'; -import { withStyles } from '@mui/styles'; +import { styled } from '@mui/material/styles'; import dayjs from 'dayjs'; import { useCallback, useEffect, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { selectTimeFilter } from '../../actions'; import Colors from '../../colors'; -const styles = (theme) => ({ - modal: { - position: 'absolute', - padding: theme.spacing(2), - width: theme.spacing(50), - maxWidth: '90%', - margin: '0 auto', - left: '50%', - top: '40%', - transform: 'translate(-50%, -50%)', - outline: 'none', - }, - buttonGroup: { - marginTop: 20, - textAlign: 'right', - }, - datePickerContainer: { - display: 'flex', - marginBottom: 20, - '& aside': { width: 100 }, - }, - cancelButton: { - backgroundColor: Colors.grey200, - color: Colors.white, - '&:hover': { - backgroundColor: Colors.grey400, - }, +const StyledPaper = styled(Paper)(({ theme }) => ({ + position: 'absolute', + padding: theme.spacing(2), + width: theme.spacing(50), + maxWidth: '90%', + margin: '0 auto', + left: '50%', + top: '40%', + transform: 'translate(-50%, -50%)', + outline: 'none', +})); + +const ButtonGroup = styled('div')(({ theme }) => ({ + marginTop: 20, + textAlign: 'right', +})); + +const DatePickerContainer = styled('div')({ + display: 'flex', + marginBottom: 20, + '& aside': { width: 100 }, +}); + +const CancelButton = styled(Button)({ + backgroundColor: Colors.grey200, + color: Colors.white, + '&:hover': { + backgroundColor: Colors.grey400, }, - saveButton: { - backgroundColor: Colors.white, - color: Colors.grey800, - '&:hover': { - backgroundColor: Colors.white70, - }, +}); + +const SaveButton = styled(Button)({ + backgroundColor: Colors.white, + color: Colors.grey800, + '&:hover': { + backgroundColor: Colors.white70, }, }); const LOOKBACK_WINDOW_MILLIS = 365 * 24 * 3600 * 1000; // 30 days const TimeSelect = (props) => { - const { classes, isOpen, onClose } = props; + const { isOpen, onClose } = props; const dispatch = useDispatch(); const filter = useSelector((state) => state.filter); @@ -87,28 +89,28 @@ const TimeSelect = (props) => { return ( - -
+ + Start date: -
-
+ + End date: -
+ -
- +   - -
-
+ + +
); }; -export default withStyles(styles)(TimeSelect); +export default TimeSelect; diff --git a/src/components/Timeline/index.jsx b/src/components/Timeline/index.jsx index 07845cbc..061de335 100644 --- a/src/components/Timeline/index.jsx +++ b/src/components/Timeline/index.jsx @@ -2,7 +2,8 @@ // rapidly change high level timeline stuff // rapid seeking, etc -import { withStyles } from '@mui/styles'; +import { Box } from '@mui/material'; +import { styled } from '@mui/material/styles'; import dayjs from 'dayjs'; import { useEffect, useRef, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; @@ -15,124 +16,115 @@ import { seek } from '../../timeline/playback'; import { getSegmentNumber } from '../../utils'; import Thumbnails from './thumbnails'; -const styles = () => ({ - base: { - position: 'relative', - }, - segments: { - position: 'relative', - left: '0px', - width: '100%', - overflow: 'hidden', - height: 12, - }, - segment: { - position: 'absolute', - height: 12, - background: theme.palette.states.drivingBlue, +const TimelineBase = styled(Box)({ + position: 'relative', +}); + +const TimelineSegments = styled(Box)({ + position: 'relative', + left: '0px', + width: '100%', + overflow: 'hidden', + height: 12, +}); + +const TimelineSegment = styled(Box)({ + position: 'absolute', + height: 12, + background: theme.palette.states.drivingBlue, +}); + +const StatusGradient = styled(Box)({ + background: 'linear-gradient(rgba(0, 0, 0, 0.0) 4%, rgba(255, 255, 255, 0.025) 10%, rgba(0, 0, 0, 0.1) 25%, rgba(0, 0, 0, 0.4))', + height: 12, + left: 0, + pointerEvents: 'none', + position: 'absolute', + top: 0, + width: '100%', + zIndex: 2, +}); + +const SegmentColor = styled(Box)({ + position: 'absolute', + display: 'inline-block', + height: 12, + width: '100%', + '&.active': {}, + '&.engage': { + background: theme.palette.states.engagedGreen, }, - statusGradient: { - background: 'linear-gradient(rgba(0, 0, 0, 0.0) 4%, rgba(255, 255, 255, 0.025) 10%, rgba(0, 0, 0, 0.1) 25%, rgba(0, 0, 0, 0.4))', - height: 12, - left: 0, - pointerEvents: 'none', - position: 'absolute', - top: 0, - width: '100%', - zIndex: 2, + '&.overriding': { + background: theme.palette.states.engagedGrey, }, - segmentColor: { - position: 'absolute', - display: 'inline-block', - height: 12, - width: '100%', - '&.active': {}, - '&.engage': { - background: theme.palette.states.engagedGreen, - }, - '&.overriding': { - background: theme.palette.states.engagedGrey, + '&.alert': { + '&.userPrompt': { + background: theme.palette.states.alertOrange, }, - '&.alert': { - '&.userPrompt': { - background: theme.palette.states.alertOrange, - }, - '&.critical': { - background: theme.palette.states.alertRed, - }, - }, - '&.bookmark, &.flag': { - // TODO: remove flag selector once 14 days expires old events caches - background: theme.palette.states.userBookmark, - zIndex: 1, - }, - }, - thumbnails: { - height: 20, - width: '100%', - overflow: 'hidden', - whiteSpace: 'nowrap', - userSelect: 'none', - '& > div': { - display: 'inline-block', + '&.critical': { + background: theme.palette.states.alertRed, }, }, - ruler: { - backgroundColor: 'rgb(37, 51, 61)', - touchAction: 'none', - width: '100%', - height: 44, + '&.bookmark, &.flag': { + // TODO: remove flag selector once 14 days expires old events caches + background: theme.palette.states.userBookmark, + zIndex: 1, }, - rulerRemaining: { - backgroundColor: 'rgba(29, 34, 37, 0.9)', - borderLeft: '1px solid #D8DDDF', - position: 'absolute', - left: 0, - height: 44, - opacity: 0.45, - pointerEvents: 'none', - width: '100%', - }, - loopStart: { - backgroundColor: 'rgba(0, 0, 0, 0.5)', - borderRight: '1px solid rgba(0, 0, 0, 0.8)', - position: 'absolute', - left: 0, - height: 44, - pointerEvents: 'none', - }, - loopEnd: { - backgroundColor: 'rgba(0, 0, 0, 0.5)', - borderLeft: '1px solid rgba(0, 0, 0, 0.8)', - position: 'absolute', - right: 0, - height: 44, - pointerEvents: 'none', - }, - dragHighlight: { - pointerEvents: 'none', - background: 'rgba(255, 255, 255, 0.1)', - borderLeft: '1px solid rgba(255, 255, 255, 0.3)', - borderRight: '1px solid rgba(255, 255, 255, 0.3)', - position: 'absolute', - height: 44, - }, - hoverBead: { - zIndex: 3, - textAlign: 'center', - borderRadius: 14, - fontSize: '0.7em', - padding: '3px 4px', - border: `1px solid ${Colors.white10}`, - backgroundColor: Colors.grey800, - color: Colors.white, - position: 'absolute', - top: 83, - left: 0, - width: 80, +}); + +const ThumbnailsContainer = styled(Box)({ + height: 20, + width: '100%', + overflow: 'hidden', + whiteSpace: 'nowrap', + userSelect: 'none', + '& > div': { + display: 'inline-block', }, }); +const Ruler = styled(Box)({ + backgroundColor: 'rgb(37, 51, 61)', + touchAction: 'none', + width: '100%', + height: 44, +}); + +const RulerRemaining = styled(Box)({ + backgroundColor: 'rgba(29, 34, 37, 0.9)', + borderLeft: '1px solid #D8DDDF', + position: 'absolute', + left: 0, + height: 44, + opacity: 0.45, + pointerEvents: 'none', + width: '100%', +}); + +const DragHighlight = styled(Box)({ + pointerEvents: 'none', + background: 'rgba(255, 255, 255, 0.1)', + borderLeft: '1px solid rgba(255, 255, 255, 0.3)', + borderRight: '1px solid rgba(255, 255, 255, 0.3)', + position: 'absolute', + height: 44, +}); + +const HoverBead = styled(Box)({ + zIndex: 3, + textAlign: 'center', + borderRadius: 14, + fontSize: '0.7em', + padding: '3px 4px', + border: `1px solid ${Colors.white10}`, + backgroundColor: Colors.grey800, + color: Colors.white, + position: 'absolute', + top: 83, + left: 0, + width: 80, +}); + const AlertStatusCodes = ['normal', 'userPrompt', 'critical']; function percentFromPointerEvent(ev) { @@ -141,7 +133,7 @@ function percentFromPointerEvent(ev) { return x / boundingBox.width; } -const Timeline = ({ classes, hasRuler, className, route, thumbnailsVisible, zoomOverride }) => { +const Timeline = ({ hasRuler, className, route, thumbnailsVisible, zoomOverride }) => { const dispatch = useDispatch(); const propsZoom = useSelector((state) => selectRouteZoom(state)); const dongleId = useSelector((state) => state.dongleId); @@ -282,7 +274,7 @@ const Timeline = ({ classes, hasRuler, className, route, thumbnailsVisible, zoom minWidth: '1px', }; const statusCls = event.data.alertStatus ? `${AlertStatusCodes[event.data.alertStatus]}` : ''; - return
; + return ; }); }; @@ -301,9 +293,9 @@ const Timeline = ({ classes, hasRuler, className, route, thumbnailsVisible, zoom left: `${startPerc}%`, }; return ( -
+ {renderRouteEvents(route)} -
+ ); }; @@ -370,38 +362,31 @@ const Timeline = ({ classes, hasRuler, className, route, thumbnailsVisible, zoom const baseWidthStyle = { width: '100%' }; return ( -
-
-
+ + + {route && renderRoute()} -
-
-
- {thumbnailsVisible && } -
+ +
+ + {thumbnailsVisible && } + {hasRuler && ( <> -
-
- {draggerStyle &&
} -
+ + + {draggerStyle && } + {hoverString && ( -
+ {hoverString} -
+ )} )} -
-
+
+
); }; -export default withStyles(styles)(Timeline); +export default Timeline; diff --git a/src/components/anonymous.jsx b/src/components/anonymous.jsx index a926900a..ec3b8acd 100644 --- a/src/components/anonymous.jsx +++ b/src/components/anonymous.jsx @@ -1,7 +1,7 @@ /* global AppleID */ import { config as AuthConfig, storage as AuthStorage } from '@commaai/my-comma-auth'; -import { withStyles } from '@mui/styles'; +import { styled } from '@mui/material/styles'; import Typography from '@mui/material/Typography'; import { useEffect } from 'react'; import { useLocation } from 'react-router'; @@ -11,83 +11,90 @@ import { AuthAppleIcon, AuthGithubIcon, AuthGoogleIcon, RightArrow } from '../ic import PWAIcon from './PWAIcon'; -const styles = () => ({ - baseContainer: { - width: '100%', - height: '100vh', - display: 'flex', - flexDirection: 'column', - alignItems: 'center', - justifyContent: 'center', - }, - base: { - overflowY: 'auto', - padding: 20, - display: 'flex', - flexDirection: 'column', - alignItems: 'center', - width: '100%', - }, - logoImg: { - height: 45, - width: 'auto', - }, - logoContainer: { - width: 84, - height: 84, - backgroundColor: Colors.grey900, - borderRadius: 17, - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - flexShrink: 0, - }, - logoSpacer: { - height: 60, - flexShrink: 2, - }, - logoText: { - fontSize: 36, - fontWeight: 800, - textAlign: 'center', - }, - tagline: { - width: 380, - maxWidth: '90%', - textAlign: 'center', - margin: '10px 0 30px', - fontSize: '18px', - }, - logInButton: { - cursor: 'pointer', - alignItems: 'center', - background: '#ffffff', - display: 'flex', - borderRadius: 80, - fontSize: 21, - height: 80, - justifyContent: 'center', - textDecoration: 'none', - width: 400, - maxWidth: '90%', - marginBottom: 10, - '&:hover': { - background: '#eee', - }, - }, - buttonText: { - fontSize: 18, - width: 190, - textAlign: 'center', - color: 'black', - fontWeight: 600, - }, - buttonImage: { - height: 40, +const BaseContainer = styled('div')({ + width: '100%', + height: '100vh', + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', +}); + +const Base = styled('div')({ + overflowY: 'auto', + padding: 20, + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + width: '100%', +}); + +const LogoImg = styled('img')({ + height: 45, + width: 'auto', +}); + +const LogoContainer = styled('div')({ + width: 84, + height: 84, + backgroundColor: Colors.grey900, + borderRadius: 17, + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + flexShrink: 0, +}); + +const LogoSpacer = styled('div')({ + height: 60, + flexShrink: 2, +}); + +const LogoText = styled(Typography)({ + fontSize: 36, + fontWeight: 800, + textAlign: 'center', +}); + +const Tagline = styled(Typography)({ + width: 380, + maxWidth: '90%', + textAlign: 'center', + margin: '10px 0 30px', + fontSize: '18px', +}); + +const LogInButton = styled('a')({ + cursor: 'pointer', + alignItems: 'center', + background: '#ffffff', + display: 'flex', + borderRadius: 80, + fontSize: 21, + height: 80, + justifyContent: 'center', + textDecoration: 'none', + width: 400, + maxWidth: '90%', + marginBottom: 10, + '&:hover': { + background: '#eee', }, }); -const AnonymousLanding = ({ classes }) => { +const ButtonText = styled(Typography)({ + fontSize: 18, + width: 190, + textAlign: 'center', + color: 'black', + fontWeight: 600, +}); + +const ButtonImage = styled('img')({ + height: 40, +}); + +const AnonymousLanding = () => { const location = useLocation(); useEffect(() => { @@ -129,26 +136,26 @@ const AnonymousLanding = ({ classes }) => { }; return ( -
-
-
- comma -
-
 
- comma connect - Manage your comma device, view your drives, and use comma prime features - - - Sign in with Google - - AppleID.auth.signIn()} className={classes.logInButton}> - - Sign in with Apple - - - - Sign in with GitHub - + + + + + +   + comma connect + Manage your comma device, view your drives, and use comma prime features + + + Sign in with Google + + AppleID.auth.signIn()}> + + Sign in with Apple + + + + Sign in with GitHub + Make sure to sign in with the same account if you have previously paired your comma device. @@ -159,10 +166,10 @@ const AnonymousLanding = ({ classes }) => { Try the demo -
+ -
+ ); }; -export default withStyles(styles)(AnonymousLanding); +export default AnonymousLanding; diff --git a/src/components/explorer.jsx b/src/components/explorer.jsx index 24699a1f..026575cc 100644 --- a/src/components/explorer.jsx +++ b/src/components/explorer.jsx @@ -1,5 +1,5 @@ -import { Button, CircularProgress, Divider, Modal, Paper, Typography } from '@mui/material'; -import { withStyles } from '@mui/styles'; +import { Box, Button, CircularProgress, Divider, Modal, Paper, Typography } from '@mui/material'; +import { styled } from '@mui/material/styles'; import localforage from 'localforage'; import { useEffect, useRef, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; @@ -22,41 +22,29 @@ import IosPwaPopup from './IosPwaPopup'; import ResizeHandler from './ResizeHandler'; import PullDownReload from './utils/PullDownReload'; -const styles = (theme) => ({ - window: { - background: 'linear-gradient(180deg, #1D2225 0%, #16181A 100%)', - display: 'flex', - flexDirection: 'column', - }, - modal: { - position: 'absolute', - padding: theme.spacing(2), - width: theme.spacing(50), - maxWidth: '90%', - left: '50%', - top: '40%', - transform: 'translate(-50%, -50%)', - outline: 'none', - '& p': { marginTop: 10 }, - }, - closeButton: { - marginTop: 10, - float: 'right', - backgroundColor: Colors.grey200, - color: Colors.white, - '&:hover': { - backgroundColor: Colors.grey400, - }, - }, - fabProgress: { - marginTop: 10, - }, - pairedDongleId: { - fontWeight: 'bold', +const StyledPaper = styled(Paper)(({ theme }) => ({ + position: 'absolute', + padding: theme.spacing(2), + width: theme.spacing(50), + maxWidth: '90%', + left: '50%', + top: '40%', + transform: 'translate(-50%, -50%)', + outline: 'none', + '& p': { marginTop: 10 }, +})); + +const CloseButton = styled(Button)({ + marginTop: 10, + float: 'right', + backgroundColor: Colors.grey200, + color: Colors.white, + '&:hover': { + backgroundColor: Colors.grey400, }, }); -const ExplorerApp = ({ classes }) => { +const ExplorerApp = () => { const dispatch = useDispatch(); const location = useLocation(); @@ -222,29 +210,38 @@ const ExplorerApp = ({ classes }) => { forwardRef={updateHeaderRef} /> -
+ {noDevicesUpsell ? : currentRoute ? : } -
+ - + Pairing device - {pairLoading && } + {pairLoading && } {pairDongleId && ( {'Successfully paired device '} - {pairDongleId} + + {pairDongleId} + )} {pairError && {pairError}} - - + +
); }; -export default withStyles(styles)(ExplorerApp); +export default ExplorerApp; diff --git a/src/components/utils/InfoTooltip.jsx b/src/components/utils/InfoTooltip.jsx index ecbadc52..e8cf74e1 100644 --- a/src/components/utils/InfoTooltip.jsx +++ b/src/components/utils/InfoTooltip.jsx @@ -1,49 +1,40 @@ import { ClickAwayListener, Tooltip, Typography } from '@mui/material'; -import { withStyles } from '@mui/styles'; +import { styled } from '@mui/material/styles'; import { useState } from 'react'; import { InfoOutline } from '../../icons'; -const styles = (theme) => ({ - arrowPopper: { - opacity: 1, - '& $arrowArrow': { - bottom: 0, - left: 0, - marginBottom: '-0.9em', - width: '3em', - height: '1em', - '&::before': { - borderWidth: '1em 1em 0 1em', - borderColor: `${theme.palette.grey[900]} transparent transparent transparent`, - }, - }, - }, - arrowArrow: { - position: 'absolute', - fontSize: 7, - width: '3em', - height: '3em', - '&::before': { - content: '""', - margin: 'auto', - display: 'block', - width: 0, - height: 0, - borderStyle: 'solid', - }, - }, - tooltip: { +const StyledTooltip = styled(Tooltip)(({ theme }) => ({ + '& .MuiTooltip-tooltip': { background: theme.palette.grey[900], marginBottom: 8, }, - icon: { - marginLeft: theme.spacing(1), - fontSize: 18, + '& .MuiTooltip-popper': { + opacity: 1, + }, +})); + +const ArrowSpan = styled('span')(({ theme }) => ({ + position: 'absolute', + fontSize: 7, + width: '3em', + height: '3em', + bottom: 0, + left: 0, + marginBottom: '-0.9em', + '&::before': { + content: '""', + margin: 'auto', + display: 'block', + width: 0, + height: 0, + borderStyle: 'solid', + borderWidth: '1em 1em 0 1em', + borderColor: `${theme.palette.grey[900]} transparent transparent transparent`, }, -}); +})); -const InfoTooltip = ({ classes, title }) => { +const InfoTooltip = ({ title }) => { const [arrowRef, setArrowRef] = useState(null); const [open, setOpen] = useState(false); @@ -61,7 +52,7 @@ const InfoTooltip = ({ classes, title }) => { return ( - { title={ <> {title} - + } onOpen={onTooltipOpen} onClose={onTooltipClose} open={open} - classes={{ tooltip: classes.tooltip, popper: classes.arrowPopper }} placement="top" > - - + + ); }; -export default withStyles(styles)(InfoTooltip); +export default InfoTooltip; diff --git a/src/components/utils/PullDownReload.jsx b/src/components/utils/PullDownReload.jsx index 311e4ca0..f88f561d 100644 --- a/src/components/utils/PullDownReload.jsx +++ b/src/components/utils/PullDownReload.jsx @@ -1,27 +1,25 @@ -import { withStyles } from '@mui/styles'; +import { styled } from '@mui/material/styles'; import ReplayIcon from '@mui/icons-material/Replay'; import { useCallback, useEffect, useRef, useState } from 'react'; import Colors from '../../colors'; import { isIos } from '../../utils/browser.js'; -const styles = () => ({ - root: { - position: 'absolute', - zIndex: 5050, - top: -48, - left: 'calc(50% - 24px)', - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - width: 48, - height: 48, - backgroundColor: Colors.grey100, - borderRadius: 24, - }, +const Root = styled('div')({ + position: 'absolute', + zIndex: 5050, + top: -48, + left: 'calc(50% - 24px)', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + width: 48, + height: 48, + backgroundColor: Colors.grey100, + borderRadius: 24, }); -const PullDownReload = ({ classes }) => { +const PullDownReload = () => { const [startY, setStartY] = useState(null); const [reloading, setReloading] = useState(false); const dragEl = useRef(null); @@ -90,10 +88,10 @@ const PullDownReload = ({ classes }) => { }, [touchStart, touchMove, touchEnd]); return ( -
+ -
+ ); }; -export default withStyles(styles)(PullDownReload); +export default PullDownReload; diff --git a/src/components/utils/SwitchLoading.jsx b/src/components/utils/SwitchLoading.jsx index 6a5ed6f8..bb589998 100644 --- a/src/components/utils/SwitchLoading.jsx +++ b/src/components/utils/SwitchLoading.jsx @@ -1,52 +1,44 @@ -import { FormControlLabel, Popper, Switch, Typography } from '@mui/material'; -import { withStyles } from '@mui/styles'; +import { Box, FormControlLabel, Popper, Switch, Typography } from '@mui/material'; +import { styled } from '@mui/material/styles'; import { useState } from 'react'; import Colors from '../../colors'; import { ErrorOutline } from '../../icons'; import InfoTooltip from './InfoTooltip'; -const styles = () => ({ - root: { - display: 'flex', - alignItems: 'center', +const StyledSwitch = styled(Switch)({ + '& .MuiSwitch-thumb::before': { + content: "''", + display: 'inline-block', + height: '100%', + width: '100%', + backgroundImage: + "url('data:image/svg+xml;utf8," + + '' + + '\')', + strokeDasharray: '80px, 200px', + animation: 'circular-rotate 1s linear infinite', }, - switchThumbLoading: { - '&::before': { - content: "''", - display: 'inline-block', - height: '100%', - width: '100%', - backgroundImage: - "url('data:image/svg+xml;utf8," + - '' + - '\')', - strokeDasharray: '80px, 200px', - animation: 'circular-rotate 1s linear infinite', - }, - }, - errorIcon: { - color: Colors.red300, - }, - copiedPopover: { - borderRadius: 16, - padding: '8px 16px', - border: `1px solid ${Colors.white10}`, - backgroundColor: Colors.grey800, - marginTop: 12, - zIndex: 50000, - maxWidth: '95%', - '& p': { - maxWidth: 400, - fontSize: '0.9rem', - color: Colors.white, - margin: 0, - }, +}); + +const StyledPopper = styled(Popper)({ + borderRadius: 16, + padding: '8px 16px', + border: `1px solid ${Colors.white10}`, + backgroundColor: Colors.grey800, + marginTop: 12, + zIndex: 50000, + maxWidth: '95%', + '& p': { + maxWidth: 400, + fontSize: '0.9rem', + color: Colors.white, + margin: 0, }, }); -const SwitchLoading = ({ classes, checked, label, loading, tooltip, onChange: propsOnChange }) => { +const SwitchLoading = ({ checked, label, loading, tooltip, onChange: propsOnChange }) => { const [internalLoading, setInternalLoading] = useState(false); const [internalChecked, setInternalChecked] = useState(null); const [error, setError] = useState(null); @@ -75,24 +67,24 @@ const SwitchLoading = ({ classes, checked, label, loading, tooltip, onChange: pr }; const isChecked = internalChecked !== null ? internalChecked : checked; - const loadingCls = loading || internalLoading ? { icon: classes.switchThumbLoading } : {}; + const SwitchComponent = loading || internalLoading ? StyledSwitch : Switch; - const switchEl = ; + const switchEl = ; return ( -
+ {tooltip && } {Boolean(error) && ( <> - setErrorPopper(null)} onMouseEnter={(ev) => setErrorPopper(ev.target)} /> - + setErrorPopper(null)} onMouseEnter={(ev) => setErrorPopper(ev.target)} /> + {error} - + )} -
+ ); }; -export default withStyles(styles)(SwitchLoading); +export default SwitchLoading; diff --git a/vite.config.js b/vite.config.js index d646f186..23d4d06a 100644 --- a/vite.config.js +++ b/vite.config.js @@ -28,7 +28,7 @@ export default defineConfig(({ mode }) => { output: { manualChunks: { 'react-vendor': ['react', 'react-dom'], - 'mui': ['@mui/material', '@mui/icons-material', '@mui/styles'], + 'mui': ['@mui/material', '@mui/icons-material'], 'mapbox': ['react-map-gl'], 'sentry': ['@sentry/react'], }, From e2c7823999c49393687cf836588ed08750ae400f Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 2 Nov 2025 22:34:26 -0800 Subject: [PATCH 25/26] too much pad --- src/components/DeviceInfo/index.jsx | 33 +++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/src/components/DeviceInfo/index.jsx b/src/components/DeviceInfo/index.jsx index 6a7bf4a3..6d6b1d29 100644 --- a/src/components/DeviceInfo/index.jsx +++ b/src/components/DeviceInfo/index.jsx @@ -32,6 +32,16 @@ const Row = styled(Box)(({ theme }) => ({ }, })); +const ButtonRow = styled(Box)({ + display: 'flex', + justifyContent: 'center', + alignItems: 'center', +}); + +const StatsRow = styled(Row)(({ theme }) => ({ + columnGap: theme.spacing(4), +})); + const DeviceStat = styled(Box)(({ theme }) => ({ display: 'flex', flexDirection: 'column', @@ -411,13 +421,24 @@ const DeviceInfo = () => { <> - + {windowWidth >= 768 ? ( - + {deviceNamePretty(device)} - {renderStats()} - {renderButtons()} - + {renderStats()} + {renderButtons()} + ) : ( <> @@ -427,7 +448,7 @@ const DeviceInfo = () => { {deviceStats.result && {renderStats()}} )} - + {snapshot.result && ( {windowWidth >= 640 ? ( From 57fda9b59f4b4c5e7754306b8c635e8ea59eba7d Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 2 Nov 2025 23:26:34 -0800 Subject: [PATCH 26/26] no flashing! --- src/actions/index.js | 12 +++-- src/components/Dashboard/DriveList.jsx | 2 +- src/components/Dashboard/index.jsx | 19 +++----- src/components/DeviceInfo/index.jsx | 62 +++++++++++++++----------- src/components/DriveView/Media.jsx | 9 +++- src/components/DriveView/index.jsx | 7 ++- src/components/Navigation/index.jsx | 26 +++++------ src/components/explorer.jsx | 55 +++++++++-------------- src/reducers/globalState.js | 15 +++++-- src/timeline/segments.js | 5 --- 10 files changed, 111 insertions(+), 101 deletions(-) diff --git a/src/actions/index.js b/src/actions/index.js index 9ed835ff..88ec4201 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -27,10 +27,12 @@ export function checkRoutesData() { // there is already an pending request return routesRequestPromise; } - console.debug('We need to update the segment metadata...'); const { dongleId } = state; const fetchRange = state.filter; + // Use a minimum limit to ensure we always fetch at least some routes + const limit = state.limit || LIMIT_INCREMENT; + // if requested segment range (from URL) not in loaded routes, fetch it explicitly const urlSeg = selectSegmentRange(); if (urlSeg) { @@ -40,7 +42,7 @@ export function checkRoutesData() { }; } else { routesRequest = { - req: Drives.getRoutesSegments(dongleId, fetchRange.start, fetchRange.end, state.limit), + req: Drives.getRoutesSegments(dongleId, fetchRange.start, fetchRange.end, limit), dongleId, }; } @@ -284,7 +286,11 @@ export function selectDevice(dongleId, allowPathChange = true) { dongleId, }); - dispatch(pushTimelineRange(null, null, null, false)); + // Don't clear routes immediately - let them persist while new routes load + // This prevents flashing when switching devices since routes-based conditional rendering + // won't unmount components during the async data fetch + // dispatch(pushTimelineRange(null, null, null, false)); + if ((device && !device.shared) || state.profile?.superuser) { dispatch(primeFetchSubscription(dongleId, device)); dispatch(fetchDeviceOnline(dongleId)); diff --git a/src/components/Dashboard/DriveList.jsx b/src/components/Dashboard/DriveList.jsx index 39fb2435..eef3d51d 100644 --- a/src/components/Dashboard/DriveList.jsx +++ b/src/components/Dashboard/DriveList.jsx @@ -51,7 +51,7 @@ const DriveList = () => { return ( - dispatch(checkRoutesData())} minInterval={60} /> + dispatch(checkRoutesData())} onInit onDongleId minInterval={60} /> {content} {contentStatus} diff --git a/src/components/Dashboard/index.jsx b/src/components/Dashboard/index.jsx index 8a4b4d1c..07b47161 100644 --- a/src/components/Dashboard/index.jsx +++ b/src/components/Dashboard/index.jsx @@ -1,10 +1,9 @@ import { CircularProgress, Grid } from '@mui/material'; -import { lazy, Suspense } from 'react'; +import { lazy, memo, Suspense } from 'react'; import { useSelector } from 'react-redux'; import { withRouter } from 'react-router'; -import DeviceInfo from '../DeviceInfo'; -import Navigation from '../Navigation'; import DriveList from './DriveList'; +import { getPrimeNav } from '../../url'; const Prime = lazy(() => import('../Prime')); @@ -16,9 +15,7 @@ const DashboardLoading = () => ( ); -import { getPrimeNav } from '../../url'; - -const Dashboard = ({ location }) => { +const Dashboard = memo(({ location }) => { const device = useSelector((state) => state.device); const dongleId = useSelector((state) => state.dongleId); @@ -33,15 +30,13 @@ const Dashboard = ({ location }) => { {primeNav ? ( ) : ( - <> - - - - + )}
); -}; +}); + +Dashboard.displayName = 'Dashboard'; export default withRouter(Dashboard); diff --git a/src/components/DeviceInfo/index.jsx b/src/components/DeviceInfo/index.jsx index 6d6b1d29..f27f1670 100644 --- a/src/components/DeviceInfo/index.jsx +++ b/src/components/DeviceInfo/index.jsx @@ -13,15 +13,6 @@ import ResizeHandler from '../ResizeHandler'; import TimeSelect from '../TimeSelect'; import VisibilityHandler from '../VisibilityHandler'; -const Container = styled(Box)(({ theme }) => ({ - borderBottom: `1px solid ${Colors.white10}`, - paddingTop: 8, - display: 'flex', - flexDirection: 'column', - minHeight: 64, - justifyContent: 'center', -})); - const Row = styled(Box)(({ theme }) => ({ display: 'flex', justifyContent: 'space-between', @@ -183,6 +174,7 @@ const DeviceInfo = () => { const snapshotButtonRef = useRef(null); const mounted = useRef(false); + const prevDongleIdRef = useRef(dongleId); // Set mounted on initial mount useEffect(() => { @@ -192,13 +184,11 @@ const DeviceInfo = () => { }; }, []); - // Reset state when dongleId changes + // Clear snapshot when dongleId changes (keep stats and car health for smoother transitions) useEffect(() => { - if (dongleId) { - setDeviceStats({}); - setCarHealth({}); + if (dongleId && prevDongleIdRef.current !== dongleId) { + prevDongleIdRef.current = dongleId; setSnapshot({}); - setWindowWidth(window.innerWidth); } }, [dongleId]); @@ -207,10 +197,10 @@ const DeviceInfo = () => { }; const fetchDeviceInfo = useCallback(async () => { - if (device.shared) { + if (!device || device.shared) { return; } - setDeviceStats({ fetching: true }); + setDeviceStats((prev) => ({ ...prev, fetching: true })); try { const resp = await Devices.fetchDeviceStats(dongleId); if (mounted.current) { @@ -219,9 +209,9 @@ const DeviceInfo = () => { } catch (err) { console.error(err); Sentry.captureException(err, { fingerprint: 'device_info_device_stats' }); - setDeviceStats({ error: err.message }); + setDeviceStats((prev) => ({ ...prev, error: err.message })); } - }, [dongleId, device.shared]); + }, [dongleId, device]); const fetchDeviceCarHealth = useCallback(async () => { if (!deviceIsOnline(device)) { @@ -229,7 +219,7 @@ const DeviceInfo = () => { return; } - setCarHealth({ fetching: true }); + setCarHealth((prev) => ({ ...prev, fetching: true })); try { const payload = { method: 'getMessage', @@ -247,17 +237,17 @@ const DeviceInfo = () => { console.error(err); Sentry.captureException(err, { fingerprint: 'device_info_athena_pandastate' }); } - setCarHealth({ error: err.message }); + setCarHealth((prev) => ({ ...prev, error: err.message })); } } }, [dongleId, device]); const onVisible = useCallback(() => { - if (!device.shared) { + if (device && !device.shared) { fetchDeviceInfo(); fetchDeviceCarHealth(); } - }, [device.shared, fetchDeviceInfo, fetchDeviceCarHealth]); + }, [device, fetchDeviceInfo, fetchDeviceCarHealth]); const takeSnapshot = async () => { setSnapshot((prev) => ({ ...prev, error: null, fetching: true })); @@ -306,9 +296,24 @@ const DeviceInfo = () => { if (!deviceStats.result) { return ( <> -
-
-
+ + + 0 + + miles + + + + 0 + + drives + + + + 0 + + hours + ); } @@ -417,6 +422,11 @@ const DeviceInfo = () => { const containerPadding = windowWidth > 520 ? 36 : 16; const largeSnapshotPadding = windowWidth > 1440 ? '12px 0' : 0; + // Don't render if no device is selected + if (!dongleId || !device) { + return null; + } + return ( <> @@ -445,7 +455,7 @@ const DeviceInfo = () => { {deviceNamePretty(device)} {renderButtons()} - {deviceStats.result && {renderStats()}} + {renderStats()} )} diff --git a/src/components/DriveView/Media.jsx b/src/components/DriveView/Media.jsx index 59ff5764..0c4591fa 100644 --- a/src/components/DriveView/Media.jsx +++ b/src/components/DriveView/Media.jsx @@ -18,7 +18,6 @@ import { deviceIsOnline, deviceOnCellular, getSegmentNumber } from '../../utils' import DriveMap from '../DriveMap'; import DriveVideo from '../DriveVideo'; import UploadQueue from '../Files/UploadQueue'; -import ResizeHandler from '../ResizeHandler'; import TimeDisplay from '../TimeDisplay'; import SwitchLoading from '../utils/SwitchLoading'; @@ -679,6 +678,13 @@ const Media = ({ menusOnly }) => { } }, [currentRoute, device, profile, dongleId, dispatch]); + // Use resize observer to track window width locally + useEffect(() => { + const handleResize = () => setWindowWidth(window.innerWidth); + window.addEventListener('resize', handleResize); + return () => window.removeEventListener('resize', handleResize); + }, []); + if (menusOnly) { // for test return renderMenus(true); @@ -690,7 +696,6 @@ const Media = ({ menusOnly }) => { return ( - setWindowWidth(ww)} /> {renderMediaOptions(showMapAlways)} {inView === MediaType.VIDEO && } diff --git a/src/components/DriveView/index.jsx b/src/components/DriveView/index.jsx index 6ebd8b9a..e6356906 100644 --- a/src/components/DriveView/index.jsx +++ b/src/components/DriveView/index.jsx @@ -1,5 +1,6 @@ import { IconButton, Typography } from '@mui/material'; import dayjs from 'dayjs'; +import { memo } from 'react'; import { useSelector } from 'react-redux'; import { ArrowBackBold, CloseBold } from '../../icons'; import { navigate } from '../../navigation'; @@ -7,7 +8,7 @@ import { selectCurrentRoute, selectRouteZoom } from '../../selectors/route'; import Timeline from '../Timeline'; import Media from './Media'; -const DriveView = () => { +const DriveView = memo(() => { const dongleId = useSelector((state) => state.dongleId); const routes = useSelector((state) => state.routes); const zoom = useSelector(selectRouteZoom); @@ -55,6 +56,8 @@ const DriveView = () => {
); -}; +}); + +DriveView.displayName = 'DriveView'; export default DriveView; diff --git a/src/components/Navigation/index.jsx b/src/components/Navigation/index.jsx index 5e974943..77abf58d 100644 --- a/src/components/Navigation/index.jsx +++ b/src/components/Navigation/index.jsx @@ -168,6 +168,7 @@ const Navigation = () => { // Refs const mounted = useRef(false); + const prevDongleIdRef = useRef(dongleId); const mapContainerRef = useRef(null); const searchSelectBoxRef = useRef(null); const primeAdBoxRef = useRef(null); @@ -323,7 +324,8 @@ const Navigation = () => { } } } - }, [noFly, geoLocateCoords, searchSelect, windowWidth, viewport, itemLngLat, getCarLocation]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [noFly, geoLocateCoords, searchSelect, windowWidth, itemLngLat, getCarLocation]); const checkWebGLSupport = useCallback(() => { const canvas = document.createElement('canvas'); @@ -334,7 +336,7 @@ const Navigation = () => { }, []); const getDeviceLastLocation = useCallback(async () => { - if (device.shared) { + if (!device || device.shared) { return; } try { @@ -349,7 +351,7 @@ const Navigation = () => { Sentry.captureException(err, { fingerprint: 'nav_fetch_location' }); } } - }, [dongleId, device.shared]); + }, [dongleId, device]); const getDeviceNetworkLocation = useCallback(async () => { const payload = { @@ -555,19 +557,12 @@ const Navigation = () => { flyToMarkers(); }, [flyToMarkers]); - // Reset state when dongleId changes + // Clear UI state when dongleId changes (keep location data for smoother transitions) useEffect(() => { - if (dongleId) { - setHasFocus(false); - setCarLastLocation(null); - setCarLastLocationTime(null); - setCarNetworkLocation(null); - setCarNetworkLocationAccuracy(null); - setGeoLocateCoords(null); + if (dongleId && prevDongleIdRef.current !== dongleId) { + prevDongleIdRef.current = dongleId; setSearchSelect(null); setSearchLooking(false); - setNoFly(false); - setWindowWidth(window.innerWidth); setShowPrimeAd(true); } }, [dongleId]); @@ -587,6 +582,11 @@ const Navigation = () => { } } + // Don't render if no device is selected + if (!dongleId || !device) { + return null; + } + return ( diff --git a/src/components/explorer.jsx b/src/components/explorer.jsx index 026575cc..d46ae4da 100644 --- a/src/components/explorer.jsx +++ b/src/components/explorer.jsx @@ -3,20 +3,20 @@ import { styled } from '@mui/material/styles'; import localforage from 'localforage'; import { useEffect, useRef, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; -import { useLocation } from 'react-router'; +import { Route, Switch, useLocation } from 'react-router'; import { replace } from '../navigation'; import { devices as Devices } from '@commaai/api'; -import { checkLastRoutesData, selectDevice, updateDevice } from '../actions'; +import { selectDevice, updateDevice } from '../actions'; import init from '../actions/startup'; import Colors from '../colors'; -import { pause, play } from '../timeline/playback'; import { pairErrorToMessage, verifyPairToken } from '../utils'; -import { getSegmentRange } from '../url'; import AppDrawer from './AppDrawer'; import AppHeader from './AppHeader'; import Dashboard from './Dashboard'; +import DeviceInfo from './DeviceInfo'; import DriveView from './DriveView'; +import Navigation from './Navigation'; import NoDeviceUpsell from './DriveView/NoDeviceUpsell'; import IosPwaPopup from './IosPwaPopup'; import ResizeHandler from './ResizeHandler'; @@ -59,17 +59,6 @@ const ExplorerApp = () => { // Get Redux state const dongleId = useSelector((state) => state.dongleId); const devices = useSelector((state) => state.devices); - const limit = useSelector((state) => state.limit); - const routes = useSelector((state) => state.routes); - - // Calculate current route and zoom from location - const seg = getSegmentRange(location?.pathname || '/'); - const currentRoute = (seg && routes && routes.find((r) => r.log_id === seg.log_id)) || null; - let zoom = null; - if (currentRoute) { - const hasTimes = typeof seg.start === 'number' && typeof seg.end === 'number' && !Number.isNaN(seg.start) && !Number.isNaN(seg.end); - zoom = hasTimes ? { start: seg.start - currentRoute.start_time_utc_millis, end: seg.end - currentRoute.start_time_utc_millis } : { start: 0, end: currentRoute.duration }; - } // Initial mount effect useEffect(() => { @@ -142,22 +131,6 @@ const ExplorerApp = () => { } }, [location.pathname]); - // Handle zoom changes for playback - useEffect(() => { - if (zoom) { - dispatch(play()); - } else { - dispatch(pause()); - } - }, [zoom, dispatch]); - - // Check routes data when dongleId changes - useEffect(() => { - if (dongleId && limit === 0) { - dispatch(checkLastRoutesData()); - } - }, [dongleId, limit, dispatch]); - const closePair = async () => { await localforage.removeItem('pairToken'); if (pairDongleId) { @@ -198,13 +171,16 @@ const ExplorerApp = () => { minHeight: `calc(100vh - ${headerHeight}px)`, }; + // Check if we're viewing a route based on URL + const isViewingRoute = location.pathname.split('/').filter(Boolean).length >= 2; + return (
setWindowWidth(ww)} /> { }} style={containerStyles} > - {noDevicesUpsell ? : currentRoute ? : } + {noDevicesUpsell ? ( + + ) : ( + <> + + + + + + + + + + )} diff --git a/src/reducers/globalState.js b/src/reducers/globalState.js index 4a658847..a7ce4d74 100644 --- a/src/reducers/globalState.js +++ b/src/reducers/globalState.js @@ -52,14 +52,18 @@ export default function reducer(_state, action) { state.profile = action.profile; break; } - case Types.ACTION_SELECT_DEVICE: + case Types.ACTION_SELECT_DEVICE: { + // Check if we're actually switching to a different device + const isDifferentDevice = state.dongleId !== action.dongleId; + state = { ...state, dongleId: action.dongleId, subscription: null, subscribeInfo: null, files: null, - limit: 0, + // Only reset limit if switching to a different device + limit: isDifferentDevice ? 0 : state.limit, }; window.localStorage.setItem('selectedDongleId', action.dongleId); if (state.devices) { @@ -68,16 +72,19 @@ export default function reducer(_state, action) { state.device = newDevice; } } - if (state.routesMeta && state.routesMeta.dongleId !== state.dongleId) { + // Clear routes metadata if switching to a different device + if (isDifferentDevice && state.routesMeta) { state.routesMeta = { dongleId: null, start: null, end: null, }; + // Preserve lastRoutes so DriveList can display them while new routes load + state.lastRoutes = state.routes; state.routes = null; - state.lastRoutes = null; } break; + } case Types.ACTION_SELECT_TIME_FILTER: state = { ...state, diff --git a/src/timeline/segments.js b/src/timeline/segments.js index 80c192fc..181b8431 100644 --- a/src/timeline/segments.js +++ b/src/timeline/segments.js @@ -7,24 +7,19 @@ export function hasRoutesData(state) { return true; } if (!state.routesMeta || !state.routesMeta.dongleId || state.routesMeta.start === null || state.routesMeta.end === null) { - console.debug('No routes data at all'); return false; } if (!state.routes) { - console.debug('Still loading...'); return false; } if (state.dongleId !== state.routesMeta.dongleId) { - console.debug('Bad dongle id'); return false; } const fetchRange = state.filter; if (fetchRange.start < state.routesMeta.start) { - console.debug('Bad start offset'); return false; } if (fetchRange.end > state.routesMeta.end) { - console.debug('Bad end offset'); return false; }
-
-
- {children} -
-
{overlay}
-
- ); -}; - -export default withStyles(styles)(BackgroundImage); From 02d354afc465237d705460bd27466a7282c09e91 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 1 Nov 2025 22:56:38 -0700 Subject: [PATCH 02/26] trimming the fat --- bun.lockb | Bin 499214 -> 497544 bytes package.json | 7 +------ src/icons/360-degrees-video.svg | 6 ------ 3 files changed, 1 insertion(+), 12 deletions(-) delete mode 100644 src/icons/360-degrees-video.svg diff --git a/bun.lockb b/bun.lockb index 2b18a6da6a2714a3ab1c120c1a639c94a6791b0f..e46b413d4c48d84aaf541261a9890309272a3e88 100755 GIT binary patch delta 85113 zcmeFadz_8c-#&idd(UQWOiYf0!H~1TAckm+VQz!LIFAgrG0bMp2aH2|h7?L@#UfPG z5v7s}l}bk{6`e>b9jR0*MWw#iwbt62r*F^a`}|(7=l7rcHG5y{eXaLe>%HFVc&~l$ zJvTqyY}v!jR(Eb6@$2%t2b>>Vce`kI;^T>5)_U;17tf52-Jf^o`dUZ!e|lTfbL*;G zyf&{H-#obHu`nfAR%U))URGv_^^V7~YFJkJ0bosFQP%X*dC*zmwXDk^KMB4za2v3W ziuWUxWlcv$wIE0MEXx5dgiQSc!`}{l#<#3ySq*_jSx6U*4HVY{LB&9^zo^JxW(|TO z4Je115y0#~aY=qrnbja%8&nO*f(7(w;CGOj;TJ#_e1j>d8#1{Za$6wvni{MNq~3h! z1zA8A0wlhJ7I7o65pWr>E-=qzI0VX3koN-X1Dn8V>i2<6gE|3OktiU_D36Al=&5Xf zZf;i5tl~IR&RbB90snX%D`+)A;0_QCfXfZ$2J!;AsP$x+&x}gIvp_$P28{r+W>*6v zft`W)D{p}}8c-Jq8_KH#>GIjrr8Qf7&do9jZ!q zP0ufhEhx$_@E7Qw*T(4O1hN!S)Kuv;E^lfwoSBn9&7WggNR*jXTx_)#esA+&HN?_s zFErE6cmT*&d!V_N?}E(YezLXGRCTf&htn2v{;_0s)K>F#MHX7qZN?6
@>x(x`1b(fc{fHt2nDT6NX%dc$)t` zc(}N{Mpw&1OO?L?8Llg@8E08=dHH$pbjN8R4Vl_a`w_YLbNth@Mnh&f2|#wI?!a0Y z2<4X{zy|yr2_0aWKPLx+z$(ov$SIu}$n(G*tl>{RbWJj|^JfR9`-^52XU)mVD=Dtl zQyX{=dNlMM$ZU_(km=b#aV&e1b$2iAcT7Ojrw57(V&YNW6;SZ!mF4n%jEp&Ino8D@*fY7L!seROuwBCcA)VDwd5LZ{Bkn}g+{z!^z8-F6`P%;MsbvVtrtG)*6Y9*4m&Aiekkkp1srU_Cb5 zTz^qsAaAC%2?QsnSs0k5R{pH(TkoB@ch5rkqq1HjG(uQ2$*5N&CwM$aZ{m(Q3sOIa8{OxL`VK};{0bh9jf zv7VWlf~SF5@EAQC8n+ixbv{{nnfbx#sCwCOZNQsADrV*vWyPY5=Z5NuB8+J4|0VIL5LtS(i`q7iY!x>|yPN%o^ur<LH$66g zhP4)kFh6Vv0yD}iYn;jV!dUGQ*T}ttCgY9)uFYg8RFRqF9$N?>Oi{k zXJkk{&IPdrvuB3n1Cw<@6Q}4=k^+o`URF_2eo<`JylbZF^ob!Cg=$`uRh*wQC(GLC z*R$jrAlooh(+82U8g{H{X@M0jDrz(jhKj{r3p1HzEuF5-JOpIwc|e-~5d5P2jmZX- zRSB8=O+Z#-@(kUB4g;yz7V8hI`4VL6eFM26@M*}@KMEN=u21=^2r$7@1|J1d;humt zWM+N=%d}-;t|x*=FQUK+Yix(G}S2 zQAWRIzRvaRZ0+r%kn17-70B#9ubKFe-ZPLbIJ4P zGblg40q zBSZLr^!kr;HGXXHb%Rd=IlXK#xX$2p28;4@a?m5K%TOWaqt-=WRJpETErWlSYB&B2 ztYL*&<-01xlM&5=n-}ZO`e222ckB|~hh`PWmicpYEPv6=0)J6)Rt$K$vG;WvI|1py zSAgtusD{F;kq_;??|RGX04xK>0>=Wc0LB^g0y}dle0Qk|ls^P)3xyRxD&`;~j-ru3 zPGcBifs#O0ak8yD{oOa}_Km(tw?HJ22Cf57!;app^O>-gP3w%8URxANu7 z5nw<442mpJLguW|$zbIzdYr5TGGUp)28d_ZIE{4FA91Vp;0KWDk;9PLA`bLu(4XLI z0)LfSe+K8Ipg%Kv?K&Ot)moil^aee_pM+v1X zeTPo|5afoC?*!6stANU1m0C_lI>sLZGX7Z
    tobBmGJ0a^M&U}NBPU?boNAj%7t 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 delta 87092 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 F{{sZzY(fA4 diff --git a/package.json b/package.json index 68d11227..fa6165d3 100644 --- a/package.json +++ b/package.json @@ -65,8 +65,6 @@ "@tailwindcss/typography": "^0.5.9", "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", - "@types/react": "^18.2.21", - "@types/react-dom": "^18.2.7", "@vitejs/plugin-react": "^4.0.4", "autoprefixer": "^10.4.15", "camelcase": "^6.3.0", @@ -75,7 +73,6 @@ "eslint-plugin-import": "^2.28.1", "eslint-plugin-jest-dom": "^5.1.0", "eslint-plugin-react": "^7.33.2", - "eslint-plugin-react-hooks": "^4.6.0", "expect-puppeteer": "^9.0.0", "identity-obj-proxy": "^3.0.0", "jest": "^27.5.1", @@ -85,13 +82,11 @@ "jest-puppeteer": "^6.2.0", "postcss": "^8.4.28", "puppeteer": "^19.11.1", - "react-test-renderer": "^18.2.0", "tailwindcss": "^3.3.3", "vite": "^4.5.3", "vite-plugin-pwa": "^0.16.4", "vite-plugin-svgr": "^3.2.0", - "whatwg-fetch": "^3.6.17", - "workbox-window": "^7.0.0" + "whatwg-fetch": "^3.6.17" }, "browserslist": { "production": [ diff --git a/src/icons/360-degrees-video.svg b/src/icons/360-degrees-video.svg deleted file mode 100644 index a058d0ba..00000000 --- a/src/icons/360-degrees-video.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - From ba0d03070b0ffdaa84d05653975fe2cbf02b403b Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 1 Nov 2025 23:09:52 -0700 Subject: [PATCH 03/26] rm analytics --- .eslintrc.js | 3 - index.html | 8 - src/App.jsx | 3 - src/analytics-v2.js | 99 --------- src/analytics.js | 270 ------------------------- src/components/Dashboard/AddDevice.jsx | 4 +- src/components/DeviceInfo/index.jsx | 2 - src/components/DriveView/Media.jsx | 28 +-- src/components/Navigation/index.jsx | 19 +- src/components/Prime/PrimeCheckout.jsx | 3 +- src/components/Prime/PrimeManage.jsx | 8 +- src/components/explorer.jsx | 3 +- src/store.js | 2 - 13 files changed, 6 insertions(+), 446 deletions(-) delete mode 100644 src/analytics-v2.js delete mode 100644 src/analytics.js diff --git a/.eslintrc.js b/.eslintrc.js index 4a14bbac..c4118bf7 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -65,7 +65,4 @@ module.exports = { node: true, browser: true, }, - globals: { - gtag: 'readonly', - }, }; diff --git a/index.html b/index.html index 9876b0eb..13cd65c6 100644 --- a/index.html +++ b/index.html @@ -58,13 +58,5 @@

    - - - diff --git a/src/App.jsx b/src/App.jsx index 4085169e..675ed0da 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -71,9 +71,6 @@ class App extends Component { } this.setState({ initialized: true }); - - // set up analytics, low priority, so we do this last - import('./analytics-v2'); } redirectLink() { diff --git a/src/analytics-v2.js b/src/analytics-v2.js deleted file mode 100644 index ff89b31d..00000000 --- a/src/analytics-v2.js +++ /dev/null @@ -1,99 +0,0 @@ -import { onCLS, onFCP, onFID, onLCP, onTTFB } from 'web-vitals'; - -import { getCommaAccessToken } from '@commaai/my-comma-auth/storage'; - -const ATTRIBUTES = { - app: 'connect', - gitCommit: import.meta.env.VITE_APP_GIT_SHA || 'dev', - environment: import.meta.env.MODE || 'unknown', - ci: new URLSearchParams(window.location.search).get('ci') || false, -}; -const RESERVED_KEYS = new Set(['_id', ...Object.keys(ATTRIBUTES)]); - -const queue = new Set(); -let counter = 0; - -function uniqueId() { - counter += 1; - return `${Date.now()}-${Math.random().toString(10).substring(2, 10)}-${counter}`; -} - -async function flushQueue() { - // TODO: reimplement this properly (on the backend) - if (true) return; // eslint-disable-line - - if (queue.size === 0) return; - - // TODO: flush queue when auth state changes - const accessToken = await getCommaAccessToken(); - - const body = JSON.stringify([...queue]); - - await fetch(`${window.COMMA_URL_ROOT}_/ping`, { - body, - headers: { - Authorization: `JWT ${accessToken}`, - 'Content-Type': 'application/json', - }, - keepalive: true, - method: 'POST', - }); - - queue.clear(); -} - -export function sendEvent(event) { - if (!event.event) { - throw new Error('Analytics event must have an event property'); - } - const collisions = Object.keys(event).filter((key) => RESERVED_KEYS.has(key)); - if (collisions.length > 0) { - throw new Error(`Analytics event cannot have reserved keys ${collisions.join(', ')}`); - } - queue.add({ - _id: uniqueId(), - ...ATTRIBUTES, - ...event, - }); -} - -function sendInitData() { - sendEvent({ - event: 'init', - - webFeatures: { - barcodeDetection: 'BarcodeDetector' in window, - bluetooth: 'bluetooth' in navigator, - gamepad: 'getGamepads' in navigator, - networkInformation: 'connection' in navigator, - serviceWorkers: 'serviceWorker' in navigator, - usb: 'usb' in navigator, - }, - }); -} - -function sendToAnalytics(metric) { - sendEvent({ - event: 'web_vitals', - ...metric, - }); -} - -onCLS(sendToAnalytics); -onFCP(sendToAnalytics); -onFID(sendToAnalytics); -onLCP(sendToAnalytics); -onTTFB(sendToAnalytics); -sendInitData(); - -// Report all available metrics whenever the page is backgrounded or unloaded. -window.addEventListener('visibilitychange', () => { - if (document.visibilityState === 'hidden') { - flushQueue(); - } -}); - -// NOTE: Safari does not reliably fire the `visibilitychange` event when the -// page is being unloaded. If Safari support is needed, you should also flush the -// queue in the `pagehide` event. -window.addEventListener('pagehide', flushQueue); diff --git a/src/analytics.js b/src/analytics.js deleted file mode 100644 index a3377bc6..00000000 --- a/src/analytics.js +++ /dev/null @@ -1,270 +0,0 @@ -import { LOCATION_CHANGE } from 'connected-react-router'; -import * as Sentry from '@sentry/react'; - -import MyCommaAuth from '@commaai/my-comma-auth'; - -import * as Types from './actions/types'; -import { sendEvent } from './analytics-v2'; -import { getDongleID, getZoom } from './url'; -import { deviceIsOnline } from './utils'; - -function getPageViewEventLocation(pathname) { - let pageLocation = pathname; - const dongleId = getDongleID(pageLocation); - if (dongleId) { - pageLocation = pageLocation.replace(dongleId, ''); - } - const zoom = getZoom(pageLocation); - if (zoom) { - pageLocation = pageLocation.replace(zoom.start.toString(), ''); - pageLocation = pageLocation.replace(zoom.end.toString(), ''); - } - - if (pageLocation.endsWith('/')) { - pageLocation = pageLocation.substring(0, pageLocation.length - 1); - } - return pageLocation; -} - -const clusterMap = { - s: 1000, - m: 60000, - h: 3600000, -}; - -export function attachRelTime(obj, key, ms = true, cluster = null) { - if (!obj[key]) { - console.log(`${key} not in obj`); - return; - } - - const now = Date.now(); - let t = obj[key]; - if (ms !== true) { - t *= 1000; - } - - const dt = t - now; - - obj[`rel_${key}_ms`] = dt; - - if (cluster) { - obj[`rel_${key}_${cluster}`] = Math.round(dt / clusterMap[cluster]); - } -} - -function getVideoPercent(state, offset) { - const { zoom } = state; - if (!offset) { - offset = state.offset; - } - return (offset - (zoom.start)) / (zoom.end - zoom.start); -} - -function logAction(action, prevState, state) { - if (MyCommaAuth.isAuthenticated() && !state.profile) { // no startup data yet - return; - } - - let percent; - let params = {}; - - if (import.meta.env.DEV) { - params = { - ...params, - debug_mode: true, - }; - } - - if (state.profile?.superuser) { - params = { - ...params, - traffic_type: 'internal', - }; - } - - if (state.profile?.user_id === 'github_92103660' || new URLSearchParams(window.location.search).get('ci')) { - params = { - ...params, - traffic_type: 'ci', - }; - } - - function tag(event, properties) { - sendEvent({ event, ...properties }); - if (typeof gtag === 'function') { - gtag(event, { - ...params, - ...properties, - }); - } - } - - // eslint-disable-next-line default-case - switch (action.type) { - case LOCATION_CHANGE: - gtag('event', 'page_view', { - page_location: getPageViewEventLocation(action.payload.location.pathname), - }); - return; - - case Types.TIMELINE_PUSH_SELECTION: - if (!prevState.zoom && state.zoom) { - params = { - ...params, - start: state.zoom.start, - end: state.zoom.end, - }; - attachRelTime(params, 'start', true, 'h'); - attachRelTime(params, 'end', true, 'h'); - gtag('event', 'select_zoom', params); - } - return; - - case Types.ACTION_STARTUP_DATA: - gtag('set', { - user_id: state.profile?.user_id, - user_properties: { - superuser: state.profile?.superuser, - has_prime: state.profile?.prime, - devices_count: state.devices?.length, - device_prime_type: state.device?.prime_type, - device_type: state.device?.device_type, - device_version: state.device?.openpilot_version, - device_owner: state.device?.is_owner, - device_online: state.device ? deviceIsOnline(state.device) : undefined, - device_sim_type: state.device?.sim_type, - device_trial_claimed: state.device?.trial_claimed, - }, - }); - - gtag('event', 'page_view', { - ...params, - page_location: getPageViewEventLocation(window.location.pathname), - }); - sendEvent({ - event: 'startup_device', - dongle_id: state.device?.dongle_id, - device_type: state.device?.device_type, - }); - return; - - case Types.ACTION_SELECT_DEVICE: - gtag('event', 'select_device', { - ...params, - device_prime_type: state.device?.prime_type, - device_type: state.device?.device_type, - device_version: state.device?.openpilot_version, - device_owner: state.device?.is_owner, - device_online: state.device ? deviceIsOnline(state.device) : undefined, - device_sim_type: state.device?.sim_type, - device_trial_claimed: state.device?.trial_claimed, - }); - sendEvent({ - event: 'select_device', - dongle_id: state.device?.dongle_id, - device_type: state.device?.device_type, - }); - - gtag('set', { - user_properties: { - device_prime_type: state.device?.prime_type, - device_type: state.device?.device_type, - device_version: state.device?.openpilot_version, - device_owner: state.device?.is_owner, - device_online: state.device ? deviceIsOnline(state.device) : undefined, - device_sim_type: state.device?.sim_type, - device_trial_claimed: state.device?.trial_claimed, - }, - }); - return; - - case Types.ACTION_SELECT_TIME_FILTER: - params = { - ...params, - start: action.start, - end: action.end, - }; - attachRelTime(params, 'start', true, 'h'); - attachRelTime(params, 'end', true, 'h'); - gtag('event', 'select_time_filter', params); - return; - - case Types.ACTION_UPDATE_DEVICE_ONLINE: - if (state.device?.dongleId === action.dongleId) { - gtag('set', { - user_properties: { - device_online: deviceIsOnline(state.device), - }, - }); - } - return; - - case Types.ACTION_SEEK: - if (state.zoom) { - percent = getVideoPercent(state); - gtag('event', 'video_seek', { - ...params, - play_speed: state.desiredPlaySpeed, - play_percentage: percent, - play_percentage_round: Math.round(percent * 10) / 10, - }); - } - return; - - case Types.ACTION_PAUSE: - if (state.zoom) { - percent = getVideoPercent(state); - gtag('event', 'video_pause', { - ...params, - play_speed: state.desiredPlaySpeed, - play_percentage: percent, - play_percentage_round: Math.round(percent * 10) / 10, - }); - } - return; - - case Types.ACTION_PLAY: - if (state.zoom) { - percent = getVideoPercent(state); - gtag('event', 'video_play', { - ...params, - play_speed: state.desiredPlaySpeed, - play_percentage: percent, - play_percentage_round: Math.round(percent * 10) / 10, - }); - } - return; - - case Types.ACTION_LOOP: - if (state.currentRoute && state.zoom && state.loop?.duration !== 0) { - percent = state.loop && state.currentRoute ? state.loop.duration / state.currentRoute.duration : undefined; - gtag('event', 'video_loop', { - ...params, - loop_duration: state.loop?.duration, - loop_duration_percentage: percent, - loop_duration_percentage_round: percent ? Math.round(percent * 10) / 10 : undefined, - }); - } - return; - - case Types.ANALYTICS_EVENT: - tag(action.name, action.parameters); - } -} - -export function analyticsMiddleware({ getState }) { - return (next) => (action) => { - const prevState = getState(); - const res = next(action); - const state = getState(); - - try { - logAction(action, prevState, state); - } catch (err) { - Sentry.captureException(err, { fingerprint: 'analytics_middleware' }); - } - - return res; - }; -} diff --git a/src/components/Dashboard/AddDevice.jsx b/src/components/Dashboard/AddDevice.jsx index 31000c0b..7e1a1499 100644 --- a/src/components/Dashboard/AddDevice.jsx +++ b/src/components/Dashboard/AddDevice.jsx @@ -8,7 +8,7 @@ import AddCircleOutlineIcon from '@material-ui/icons/AddCircleOutline'; import * as Sentry from '@sentry/react'; import { devices as Devices } from '@commaai/api'; -import { selectDevice, updateDevice, analyticsEvent } from '../../actions'; +import { selectDevice, updateDevice } from '../../actions'; import { verifyPairToken, pairErrorToMessage } from '../../utils'; import Colors from '../../colors'; @@ -236,7 +236,6 @@ class AddDevice extends Component { } if (pairDongleId && this.props.devices.length === 0) { - this.props.dispatch(analyticsEvent('pair_device', { method: 'add_device_new' })); window.location = `${window.location.origin}/${pairDongleId}`; return; } @@ -303,7 +302,6 @@ class AddDevice extends Component { const device = await Devices.fetchDevice(resp.dongle_id); if (devices.length > 0) { // state change from no device to a device requires reload. dispatch(updateDevice(device)); - dispatch(analyticsEvent('pair_device', { method: 'add_device_sidebar' })); } this.setState({ pairLoading: false, pairDongleId: resp.dongle_id, pairError: null }); } else { diff --git a/src/components/DeviceInfo/index.jsx b/src/components/DeviceInfo/index.jsx index a74b2acd..64dd1907 100644 --- a/src/components/DeviceInfo/index.jsx +++ b/src/components/DeviceInfo/index.jsx @@ -8,7 +8,6 @@ import { withStyles, Typography, Button, CircularProgress, Popper, Tooltip } fro import AccessTime from '@material-ui/icons/AccessTime'; import { athena as Athena, devices as Devices } from '@commaai/api'; -import { analyticsEvent } from '../../actions'; import Colors from '../../colors'; import { deviceNamePretty, deviceIsOnline } from '../../utils'; import { isMetric, KM_PER_MI } from '../../utils/conversions'; @@ -303,7 +302,6 @@ class DeviceInfo extends Component { const { dongleId } = this.props; const { snapshot } = this.state; this.setState({ snapshot: { ...snapshot, error: null, fetching: true } }); - this.props.dispatch(analyticsEvent('take_snapshot')); try { const payload = { method: 'takeSnapshot', diff --git a/src/components/DriveView/Media.jsx b/src/components/DriveView/Media.jsx index ca91f726..4efb5cf9 100644 --- a/src/components/DriveView/Media.jsx +++ b/src/components/DriveView/Media.jsx @@ -21,9 +21,8 @@ import { bufferVideo } from '../../timeline/playback'; import Colors from '../../colors'; import { InfoOutline } from '../../icons'; import { deviceIsOnline, deviceOnCellular, getSegmentNumber } from '../../utils'; -import { analyticsEvent, updateRoute } from '../../actions'; +import { updateRoute } from '../../actions'; import { fetchEvents } from '../../actions/cached'; -import { attachRelTime } from '../../analytics'; import { setRouteViewed, fetchFiles, doUpload, fetchUploadUrls, fetchAthenaQueue, updateFiles, FILE_NAMES } from '../../actions/files'; const publicTooltip = 'Making a route public allows anyone with the route name or link to access it.'; @@ -273,10 +272,6 @@ class Media extends Component { this.props.dispatch(fetchEvents(this.props.currentRoute)); } - if (prevState.inView && prevState.inView !== this.state.inView) { - this.props.dispatch(analyticsEvent('media_switch_view', { in_view: this.state.inView })); - } - if (this.props.currentRoute && ((!prevState.downloadMenu && downloadMenu) || (!this.props.files && !prevState.moreInfoMenu && moreInfoMenu) || (!prevProps.currentRoute && (downloadMenu || moreInfoMenu)))) { @@ -313,12 +308,6 @@ class Media extends Component { return; } - const event_parameters = { - route_start_time: currentRoute.start_time_utc_millis, - }; - attachRelTime(event_parameters, 'route_start_time', true, 'h'); - this.props.dispatch(analyticsEvent('open_in_useradmin', event_parameters)); - const params = { onebox: currentRoute.fullname }; const win = window.open(`${window.USERADMIN_URL_ROOT}?${qs.stringify(params)}`, '_blank'); if (win.focus) { @@ -344,10 +333,6 @@ class Media extends Component { return; } - this.props.dispatch(analyticsEvent('files_upload', { - type, - })); - const routeNoDongleId = currentRoute.fullname.split('|')[1]; const fileName = `${dongleId}|${routeNoDongleId}--${getSegmentNumber(currentRoute)}/${type}`; @@ -381,10 +366,6 @@ class Media extends Component { return; } - this.props.dispatch(analyticsEvent('files_upload_all', { - types: types.length === 1 && types[0] === 'logs' ? 'logs' : 'all', - })); - const uploading = {}; const adjusted_start_time = currentRoute.start_time_utc_millis + loop.startTime; for (let i = 0; i < currentRoute.segment_numbers.length; i++) { @@ -458,13 +439,6 @@ class Media extends Component { downloadFile(file, type) { const { currentRoute } = this.props; - const eventParameters = { - type, - route_start_time: currentRoute.start_time_utc_millis, - }; - attachRelTime(eventParameters, 'route_start_time', true, 'h'); - this.props.dispatch(analyticsEvent('download_file', eventParameters)); - window.location.href = file.url; } diff --git a/src/components/Navigation/index.jsx b/src/components/Navigation/index.jsx index fcc506f7..b11a1127 100644 --- a/src/components/Navigation/index.jsx +++ b/src/components/Navigation/index.jsx @@ -8,7 +8,7 @@ import { Clear } from '@material-ui/icons'; import dayjs from 'dayjs'; import { athena as Athena, devices as Devices } from '@commaai/api'; -import { primeNav, analyticsEvent } from '../../actions'; +import { primeNav } from '../../actions'; import { DEFAULT_LOCATION, MAPBOX_STYLE, MAPBOX_TOKEN, networkPositioning, reverseLookup } from '../../utils/geocode'; import Colors from '../../colors'; import { PinCarIcon } from '../../icons'; @@ -212,17 +212,6 @@ class Navigation extends Component { this.updateDevice(); } - if (!prevState.hasFocus && this.state.hasFocus) { - this.props.dispatch(analyticsEvent('nav_focus', { - has_car_location: Boolean(carLastLocation || carNetworkLocation), - })); - } - - if (search && prevState.search !== search) { - this.props.dispatch(analyticsEvent('nav_search', { - panned: this.state.noFly || this.state.searchLooking, - })); - } } componentWillUnmount() { @@ -334,12 +323,6 @@ class Navigation extends Component { title: '', }; - this.props.dispatch(analyticsEvent('nav_search_select', { - source: 'car', - panned: this.state.noFly, - distance: item.distance, - })); - this.setState({ noFly: false, searchSelect: item, diff --git a/src/components/Prime/PrimeCheckout.jsx b/src/components/Prime/PrimeCheckout.jsx index ec2efa87..d763a3ad 100644 --- a/src/components/Prime/PrimeCheckout.jsx +++ b/src/components/Prime/PrimeCheckout.jsx @@ -12,7 +12,7 @@ import { billing as Billing } from '@commaai/api'; import { deviceNamePretty } from '../../utils'; import ResizeHandler from '../ResizeHandler'; import Colors from '../../colors'; -import { primeNav, analyticsEvent } from '../../actions'; +import { primeNav } from '../../actions'; import { ErrorOutline, InfoOutline } from '../../icons'; const styles = () => ({ @@ -254,7 +254,6 @@ class PrimeCheckout extends Component { subscribeInfo.sim_id, plan, ); - dispatch(analyticsEvent('prime_checkout', { plan })); window.location = resp.url; } catch (err) { // TODO show error messages diff --git a/src/components/Prime/PrimeManage.jsx b/src/components/Prime/PrimeManage.jsx index e715a458..5f9547db 100644 --- a/src/components/Prime/PrimeManage.jsx +++ b/src/components/Prime/PrimeManage.jsx @@ -13,7 +13,7 @@ import { deviceNamePretty, deviceTypePretty } from '../../utils'; import ResizeHandler from '../ResizeHandler'; import Colors from '../../colors'; import { ErrorOutline, InfoOutline } from '../../icons'; -import { primeNav, primeGetSubscription, analyticsEvent } from '../../actions'; +import { primeNav, primeGetSubscription } from '../../actions'; const styles = (theme) => ({ linkHighlight: { @@ -219,10 +219,6 @@ class PrimeManage extends Component { }, this.fetchStripeSession); } - if ((subscription?.user_id && prevState.stripeStatus?.paid !== 'paid' && stripeStatus?.paid === 'paid') - || (stripeStatus?.paid === 'paid' && !prevProps.subscription?.user_id && subscription?.user_id)) { - this.props.dispatch(analyticsEvent('prime_paid', { plan: subscription.plan })); - } } componentWillUnmount() { @@ -231,7 +227,6 @@ class PrimeManage extends Component { cancelPrime() { this.setState({ canceling: true }); - this.props.dispatch(analyticsEvent('prime_cancel', { plan: this.props.subscription.plan })); Billing.cancelPrime(this.props.dongleId).then((resp) => { if (resp.success) { this.setState({ canceling: false, cancelError: null, cancelSuccess: 'Cancelled subscription.' }); @@ -248,7 +243,6 @@ class PrimeManage extends Component { } async gotoUpdate() { - this.props.dispatch(analyticsEvent('prime_stripe_update', { plan: this.props.subscription.plan })); try { const resp = await Billing.getStripePortal(this.props.dongleId); window.location = resp.url; diff --git a/src/components/explorer.jsx b/src/components/explorer.jsx index 9e504733..5d61fac9 100644 --- a/src/components/explorer.jsx +++ b/src/components/explorer.jsx @@ -15,7 +15,7 @@ import IosPwaPopup from './IosPwaPopup'; import AppDrawer from './AppDrawer'; import PullDownReload from './utils/PullDownReload'; -import { analyticsEvent, selectDevice, updateDevice, checkLastRoutesData } from '../actions'; +import { selectDevice, updateDevice, checkLastRoutesData } from '../actions'; import init from '../actions/startup'; import Colors from '../colors'; import { play, pause } from '../timeline/playback'; @@ -119,7 +119,6 @@ class ExplorerApp extends Component { const device = await Devices.fetchDevice(resp.dongle_id); this.props.dispatch(updateDevice(device)); - this.props.dispatch(analyticsEvent('pair_device', { method: 'url_string' })); } else { await localforage.removeItem('pairToken'); console.log(resp); diff --git a/src/store.js b/src/store.js index d0f2a6e8..5b1e379d 100644 --- a/src/store.js +++ b/src/store.js @@ -8,7 +8,6 @@ import reducers from './reducers'; import composeEnhancers from './devtools'; import initialState from './initialState'; import { onHistoryMiddleware } from './actions/history'; -import { analyticsMiddleware } from './analytics'; export const history = createBrowserHistory(); @@ -18,7 +17,6 @@ const store = Redux.createStore( thunk, onHistoryMiddleware, routerMiddleware(history), - analyticsMiddleware, )), ); From c7f4a0cfcbeb271fa2583497237d581c96a9e67b Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 1 Nov 2025 23:12:26 -0700 Subject: [PATCH 04/26] rm global package --- bun.lockb | Bin 497544 -> 496127 bytes package.json | 1 - src/components/anonymous.jsx | 5 ++--- src/devtools.js | 7 +++++-- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/bun.lockb b/bun.lockb index e46b413d4c48d84aaf541261a9890309272a3e88..15db841d625be656870ab2d3ed7703e5daf68052 100755 GIT binary patch delta 94063 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 delta 93795 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 diff --git a/package.json b/package.json index fa6165d3..cae25c77 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,6 @@ "connected-react-router": "^4.5.0", "dayjs": "^1.11.9", "debounce": "^1.2.1", - "global": "^4.4.0", "history": "^4.10.1", "jwt-decode": "^3.1.2", "localforage": "^1.10.0", diff --git a/src/components/anonymous.jsx b/src/components/anonymous.jsx index 92de1a3b..c4be74c7 100644 --- a/src/components/anonymous.jsx +++ b/src/components/anonymous.jsx @@ -2,7 +2,6 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; import Obstruction from 'obstruction'; -import window from 'global/window'; import PropTypes from 'prop-types'; import qs from 'query-string'; @@ -94,14 +93,14 @@ const styles = () => ({ class AnonymousLanding extends Component { UNSAFE_componentWillMount() { - if (typeof window.sessionStorage !== 'undefined' && sessionStorage.getItem('redirectURL') === null) { + if (typeof window !== 'undefined' && typeof window.sessionStorage !== 'undefined' && sessionStorage.getItem('redirectURL') === null) { const { pathname } = this.props; sessionStorage.setItem('redirectURL', pathname); } } componentDidMount() { - const q = new URLSearchParams(window.location.search); + const q = typeof window !== 'undefined' ? new URLSearchParams(window.location.search) : new URLSearchParams(''); if (q.has('r')) { sessionStorage.setItem('redirectURL', q.get('r')); } diff --git a/src/devtools.js b/src/devtools.js index fcef7918..531ffe84 100644 --- a/src/devtools.js +++ b/src/devtools.js @@ -1,8 +1,11 @@ -import window from 'global/window'; import { compose } from 'redux'; function getComposeEnhancers() { - if (import.meta.env.VITE_APP_DEVTOOLS && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) { + if ( + import.meta.env.VITE_APP_DEVTOOLS && + typeof window !== 'undefined' && + window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ + ) { return window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__; } return compose; From ccba49aa72aafd89cb2c09dad374eca4c72838bb Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 1 Nov 2025 23:19:28 -0700 Subject: [PATCH 05/26] rm raf and env-cmd --- bun.lockb | Bin 496127 -> 492986 bytes config/jest/setupTests.js | 8 ++++++++ jest-puppeteer.config.js | 2 +- package.json | 4 +--- src/components/DriveMap/index.jsx | 3 +-- src/components/TimeDisplay/index.jsx | 5 ++--- src/components/Timeline/index.jsx | 5 ++--- 7 files changed, 15 insertions(+), 12 deletions(-) diff --git a/bun.lockb b/bun.lockb index 15db841d625be656870ab2d3ed7703e5daf68052..a50abb12a03364cf291109ad327106d0e74109d1 100755 GIT binary patch delta 89873 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 BN@f56 delta 92928 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 diff --git a/config/jest/setupTests.js b/config/jest/setupTests.js index 3289b687..3b511ab6 100644 --- a/config/jest/setupTests.js +++ b/config/jest/setupTests.js @@ -12,3 +12,11 @@ jest.mock('mapbox-gl/dist/mapbox-gl', () => ({ remove: jest.fn(), })), })); + +// Provide requestAnimationFrame in the Jest/jsdom environment +if (!global.requestAnimationFrame) { + global.requestAnimationFrame = (cb) => setTimeout(cb, 0); +} +if (!global.cancelAnimationFrame) { + global.cancelAnimationFrame = (id) => clearTimeout(id); +} diff --git a/jest-puppeteer.config.js b/jest-puppeteer.config.js index 93887da5..b131758e 100644 --- a/jest-puppeteer.config.js +++ b/jest-puppeteer.config.js @@ -8,7 +8,7 @@ module.exports = { args: [`--window-size=${width},${height}`], }, server: { - command: 'env-cmd .env.development bun run start --port 3003', + command: 'bun run start --port 3003', port: 3003, launchTimeout: 15000, debug: true, diff --git a/package.json b/package.json index cae25c77..df07c776 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "0.8.0", "scripts": { "start": "vite", - "build:development": "env-cmd .env.development vite build --mode development", + "build:development": "vite build --mode development", "build:production": "vite build", "serve": "vite preview", "lint": "eslint --ext .js,.jsx,.ts,.tsx src", @@ -44,7 +44,6 @@ "prop-types": "^15.8.1", "qr-scanner": "^1.4.2", "query-string": "^6.14.1", - "raf": "^3.4.1", "react": "~18.2.0", "react-dom": "~18.2.0", "react-map-gl": "^5.3.21", @@ -67,7 +66,6 @@ "@vitejs/plugin-react": "^4.0.4", "autoprefixer": "^10.4.15", "camelcase": "^6.3.0", - "env-cmd": "^8.0.2", "eslint": "^8.48.0", "eslint-plugin-import": "^2.28.1", "eslint-plugin-jest-dom": "^5.1.0", diff --git a/src/components/DriveMap/index.jsx b/src/components/DriveMap/index.jsx index 7abcc0ac..a84b4632 100644 --- a/src/components/DriveMap/index.jsx +++ b/src/components/DriveMap/index.jsx @@ -1,7 +1,6 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; import Obstruction from 'obstruction'; -import raf from 'raf'; import ReactMapGL, { LinearInterpolator } from 'react-map-gl'; @@ -118,7 +117,7 @@ class DriveMap extends Component { } } - raf(this.updateMarkerPos); + requestAnimationFrame(this.updateMarkerPos); } moveViewportTo(pos) { diff --git a/src/components/TimeDisplay/index.jsx b/src/components/TimeDisplay/index.jsx index 1a340b1a..7e76a6f4 100644 --- a/src/components/TimeDisplay/index.jsx +++ b/src/components/TimeDisplay/index.jsx @@ -1,7 +1,6 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; import Obstruction from 'obstruction'; -import raf from 'raf'; import dayjs from 'dayjs'; import { withStyles } from '@material-ui/core/styles'; @@ -131,7 +130,7 @@ class TimeDisplay extends Component { componentDidMount() { this.mounted = true; - raf(this.updateTime); + requestAnimationFrame(this.updateTime); } componentWillUnmount() { @@ -172,7 +171,7 @@ class TimeDisplay extends Component { this.setState({ displayTime: newDisplayTime }); } - raf(this.updateTime); + requestAnimationFrame(this.updateTime); } decreaseSpeed() { diff --git a/src/components/Timeline/index.jsx b/src/components/Timeline/index.jsx index a3b7c66d..be062b27 100644 --- a/src/components/Timeline/index.jsx +++ b/src/components/Timeline/index.jsx @@ -5,7 +5,6 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; import Obstruction from 'obstruction'; import { withStyles } from '@material-ui/core/styles'; -import raf from 'raf'; import document from 'global/document'; import dayjs from 'dayjs'; @@ -182,7 +181,7 @@ class Timeline extends Component { componentDidMount() { this.mounted = true; - raf(this.getOffset); + requestAnimationFrame(this.getOffset); this.componentDidUpdate({}); } @@ -284,7 +283,7 @@ class Timeline extends Component { if (!this.mounted) { return; } - raf(this.getOffset); + requestAnimationFrame(this.getOffset); let offset = currentOffset(); if (this.seekIndex) { offset = this.seekIndex; From faca7195289568c26ca5b967275536fd98a9a0f2 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 1 Nov 2025 23:23:47 -0700 Subject: [PATCH 06/26] lil more cleanup --- bun.lockb | Bin 492986 -> 492215 bytes jest.config.js | 3 --- package.json | 6 +----- src/components/Timeline/index.jsx | 1 - src/index.jsx | 4 ++-- 5 files changed, 3 insertions(+), 11 deletions(-) diff --git a/bun.lockb b/bun.lockb index a50abb12a03364cf291109ad327106d0e74109d1..11f0834d4378d8621fac0f51972a1affe6a088fc 100755 GIT binary patch delta 73329 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 diff --git a/jest.config.js b/jest.config.js index e94bc4c0..22aef47c 100644 --- a/jest.config.js +++ b/jest.config.js @@ -30,9 +30,6 @@ const config = { 'node_modules/(?!(.*@commaai.*)/)', ], modulePaths: ['/src'], - moduleNameMapper: { - '^.+\\.module\\.(css|sass|scss)$': 'identity-obj-proxy', - }, }; module.exports = config; diff --git a/package.json b/package.json index df07c776..294d2bfb 100644 --- a/package.json +++ b/package.json @@ -13,11 +13,8 @@ "test-puppeteer-build": "JEST_PUPPETEER_CONFIG=jest-puppeteer.build.config.js bun run test-puppeteer" }, "repository": "https://github.com/commaai/connect.git", - "author": "Chris Vickery ", + "author": "Vehicle Researcher ", "contributors": [ - "Joost Wooning ", - "Chris Vickery ", - "Cameron Clough " ], "private": true, "packageManager": "bun@1.3.1", @@ -71,7 +68,6 @@ "eslint-plugin-jest-dom": "^5.1.0", "eslint-plugin-react": "^7.33.2", "expect-puppeteer": "^9.0.0", - "identity-obj-proxy": "^3.0.0", "jest": "^27.5.1", "jest-chain-transform": "^0.0.5", "jest-environment-jsdom": "^27.5.1", diff --git a/src/components/Timeline/index.jsx b/src/components/Timeline/index.jsx index be062b27..e3a92e34 100644 --- a/src/components/Timeline/index.jsx +++ b/src/components/Timeline/index.jsx @@ -5,7 +5,6 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; import Obstruction from 'obstruction'; import { withStyles } from '@material-ui/core/styles'; -import document from 'global/document'; import dayjs from 'dayjs'; import Measure from 'react-measure'; diff --git a/src/index.jsx b/src/index.jsx index 6eb34e44..8cb074ad 100644 --- a/src/index.jsx +++ b/src/index.jsx @@ -18,8 +18,8 @@ if (window.SENTRY_ENV) { console.info('mode:', import.meta.env.MODE || 'unknown'); console.info('connect version:', import.meta.env.VITE_APP_GIT_SHA || 'dev'); -if (import.meta.env.VITE_APP_GIT_COMMIT_TIMESTAMP) { - console.info('commit date:', import.meta.env.VITE_APP_GIT_COMMIT_TIMESTAMP || 'unknown'); +if (import.meta.env.VITE_APP_GIT_TIMESTAMP) { + console.info('commit date:', import.meta.env.VITE_APP_GIT_TIMESTAMP || 'unknown'); } ReactDOM.createRoot(document.getElementById('root')).render(( From 0406956cc79e036a77cbe166d16e2f75b81b2c3b Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 1 Nov 2025 23:38:11 -0700 Subject: [PATCH 07/26] rm connected-react-router --- bun.lockb | Bin 492215 -> 489702 bytes package.json | 4 +- src/App.jsx | 9 +- src/actions/history.js | 52 ---------- src/actions/history.test.js | 150 +++++++-------------------- src/actions/index.js | 12 +-- src/actions/index.test.js | 18 ++-- src/components/IosPwaPopup/index.jsx | 11 +- src/components/anonymous.jsx | 10 +- src/components/explorer.jsx | 13 +-- src/history.js | 5 + src/historySync.js | 50 +++++++++ src/index.jsx | 6 ++ src/navigation.js | 12 +++ src/store.js | 11 +- 15 files changed, 144 insertions(+), 219 deletions(-) delete mode 100644 src/actions/history.js create mode 100644 src/history.js create mode 100644 src/historySync.js create mode 100644 src/navigation.js diff --git a/bun.lockb b/bun.lockb index 11f0834d4378d8621fac0f51972a1affe6a088fc..14ad4088d41d35bd2505bc235f686a3b145ec780 100755 GIT binary patch delta 99118 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

    Jd!g{NQlqK` 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 Mdos;UKK=6l0FK}+H2?qr diff --git a/package.json b/package.json index 294d2bfb..1212a3cd 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,6 @@ "@material-ui/icons": "^1.1.1", "@sentry/react": "^7.64.0", "@sentry/vite-plugin": "^2.7.0", - "connected-react-router": "^4.5.0", "dayjs": "^1.11.9", "debounce": "^1.2.1", "history": "^4.10.1", @@ -51,8 +50,7 @@ "react-router-dom": "^5.3.4", "reduce-reducers": "^1.0.4", "redux": "^4.2.1", - "redux-thunk": "^2.4.2", - "web-vitals": "^3.4.0" + "redux-thunk": "^2.4.2" }, "devDependencies": { "@swc/core": "^1.3.80", diff --git a/src/App.jsx b/src/App.jsx index 675ed0da..8e633fb2 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,7 +1,7 @@ import React, { Component, lazy, Suspense } from 'react'; import { Provider } from 'react-redux'; import { Route, Switch, Redirect } from 'react-router'; -import { ConnectedRouter } from 'connected-react-router'; +import { Router } from 'react-router'; import qs from 'query-string'; import localforage from 'localforage'; import * as Sentry from '@sentry/react'; @@ -12,7 +12,8 @@ import MyCommaAuth, { config as AuthConfig, storage as AuthStorage } from '@comm import { athena as Athena, auth as Auth, billing as Billing, request as Request } from '@commaai/api'; import { getZoom, getSegmentRange } from './url'; -import store, { history } from './store'; +import store from './store'; +import { history } from './history'; import ErrorFallback from './components/ErrorFallback'; @@ -137,9 +138,9 @@ class App extends Component { return ( - + {content} - + ); } diff --git a/src/actions/history.js b/src/actions/history.js deleted file mode 100644 index b139baa1..00000000 --- a/src/actions/history.js +++ /dev/null @@ -1,52 +0,0 @@ -import { LOCATION_CHANGE } from 'connected-react-router'; -import { getDongleID, getZoom, getSegmentRange, getPrimeNav } from '../url'; -import { primeNav, selectDevice, pushTimelineRange, updateSegmentRange } from './index'; -import { drives as Drives } from '@commaai/api'; - -export const onHistoryMiddleware = ({ dispatch, getState }) => (next) => async (action) => { - if (!action) { - return; - } - - if (action.type === LOCATION_CHANGE && ['POP', 'REPLACE'].includes(action.payload.action)) { - const state = getState(); - - next(action); // must be first, otherwise breaks history - - const pathDongleId = getDongleID(action.payload.location.pathname); - if (pathDongleId && pathDongleId !== state.dongleId) { - dispatch(selectDevice(pathDongleId, false)); - } - - const pathZoom = getZoom(action.payload.location.pathname); - const pathSegmentRange = getSegmentRange(action.payload.location.pathname); - - if ((pathZoom !== state.zoom) && pathZoom && !pathSegmentRange) { - const [start, end] = [pathZoom.start, pathZoom.end]; - - Drives.getRoutesSegments(pathDongleId, start, end).then((routesData) => { - if (routesData && routesData.length > 0) { - const log_id = routesData[0].fullname.split('|')[1]; - const duration = routesData[0].end_time_utc_millis - routesData[0].start_time_utc_millis; - - dispatch(pushTimelineRange(log_id, null, null, true)); - dispatch(updateSegmentRange(log_id, 0, duration)); - } - }).catch((err) => { - console.error('Error fetching routes data for log ID conversion', err); - }); - } - - - if (pathSegmentRange !== state.segmentRange) { - dispatch(pushTimelineRange(pathSegmentRange?.log_id, pathSegmentRange?.start, pathSegmentRange?.end, false)); - } - - const pathPrimeNav = getPrimeNav(action.payload.location.pathname); - if (pathPrimeNav !== state.primeNav) { - dispatch(primeNav(pathPrimeNav)); - } - } else { - next(action); - } -}; diff --git a/src/actions/history.test.js b/src/actions/history.test.js index 08eddbd2..7e7a2181 100644 --- a/src/actions/history.test.js +++ b/src/actions/history.test.js @@ -1,136 +1,62 @@ /* eslint-env jest */ -/* eslint-disable no-import-assign */ -import { routerMiddleware, LOCATION_CHANGE } from 'connected-react-router'; -import thunk from 'redux-thunk'; - -import { history } from '../store'; -import { onHistoryMiddleware } from './history'; +import { history } from '../history'; +import installHistorySync from '../historySync'; import * as actionsIndex from './index'; +import { drives as Drives } from '@commaai/api'; jest.mock('./index', () => ({ selectDevice: jest.fn(), pushTimelineRange: jest.fn(), primeNav: jest.fn(), + updateSegmentRange: jest.fn(), })); -const create = (initialState) => { - const store = { - getState: jest.fn(() => initialState), - dispatch: jest.fn(), - }; - const next = jest.fn(); - - const middleware = (s) => (n) => (action) => { - routerMiddleware(history)(s)(n)(action); - onHistoryMiddleware(s)(n)(action); - thunk(s)(n)(action); - }; - const invoke = (action) => middleware(store)(next)(action); +jest.mock('@commaai/api', () => ({ + drives: { + getRoutesSegments: jest.fn(), + }, +})); - return { store, next, invoke }; -}; +const makeStore = (initialState) => ({ + getState: jest.fn(() => initialState), + dispatch: jest.fn(), +}); beforeEach(() => { jest.clearAllMocks(); }); -describe('history middleware', () => { - it('passes through non-function action', () => { - const { next, invoke } = create(); - const action = { type: 'TEST' }; - invoke(action); - expect(next).toHaveBeenCalledWith(action); - }); - - it('calls the function', () => { - const { invoke } = create(); - const fn = jest.fn(); - invoke(fn); - expect(fn).toHaveBeenCalled(); - }); - - it('passes dispatch and getState', () => { - const { store, invoke } = create(); - invoke((dispatch, getState) => { - dispatch('TEST DISPATCH'); - getState(); - }); - expect(store.dispatch).toHaveBeenCalledWith('TEST DISPATCH'); - }); - - it('should call select dongle with history', async () => { - const fakeInner = { id: 'kahjfiowenv' }; - actionsIndex.selectDevice.mockReturnValue(fakeInner); - - const { store, next, invoke } = create({ - dongleId: null, - zoom: null, - primeNav: false, - }); - - const action = { - type: LOCATION_CHANGE, - payload: { - action: 'POP', - location: { pathname: '0000aaaa0000aaaa' }, - }, - }; - invoke(action); - expect(next).toHaveBeenCalledWith(action); - expect(store.dispatch).toHaveBeenCalledTimes(2); - expect(store.dispatch).toHaveBeenCalledWith(fakeInner); +describe('history sync', () => { + it('dispatches selectDevice when dongle changes', () => { + const store = makeStore({ dongleId: null, zoom: null, primeNav: false }); + installHistorySync(store, history); + history.push('/0000aaaa0000aaaa'); + expect(store.dispatch).toHaveBeenCalled(); expect(actionsIndex.selectDevice).toHaveBeenCalledWith('0000aaaa0000aaaa', false); }); - it('should call select zoom with history', async () => { - const fakeInner = { id: 'asdfsd83242' }; - actionsIndex.pushTimelineRange.mockReturnValue(fakeInner); - - const { store, next, invoke } = create({ - dongleId: '0000aaaa0000aaaa', - zoom: null, - primeNav: false, - }); - - const action = { - type: LOCATION_CHANGE, - payload: { - action: 'POP', - location: { pathname: '0000aaaa0000aaaa/00000000--000f00000d/1230/1234' }, + it('dispatches conversion for zoom route', async () => { + Drives.getRoutesSegments.mockResolvedValueOnce([ + { + fullname: '0000aaaa0000aaaa|00000000--000f00000d', + start_time_utc_millis: 1000, + end_time_utc_millis: 2000, }, - }; - invoke(action); - expect(next).toHaveBeenCalledWith(action); - expect(store.dispatch).toHaveBeenCalledTimes(1); - expect(store.dispatch).toHaveBeenCalledWith(fakeInner); - expect(actionsIndex.pushTimelineRange).toHaveBeenCalledWith("00000000--000f00000d", 1230000, 1234000, false); + ]); + const store = makeStore({ dongleId: '0000aaaa0000aaaa', zoom: null, primeNav: false }); + installHistorySync(store, history); + history.push('/0000aaaa0000aaaa/1230/1234'); + // Allow async conversion to resolve + await new Promise((r) => setTimeout(r, 0)); + expect(actionsIndex.pushTimelineRange).toHaveBeenCalledWith('00000000--000f00000d', null, null, true); + expect(actionsIndex.updateSegmentRange).toHaveBeenCalledWith('00000000--000f00000d', 0, 1000); }); - it('should call prime nav with history', async () => { - const fakeInner = { id: 'n27u3n9va' }; - const fakeInner2 = { id: 'vmklxmsd' }; - actionsIndex.pushTimelineRange.mockReturnValue(fakeInner); - actionsIndex.primeNav.mockReturnValue(fakeInner2); - - const { store, next, invoke } = create({ - dongleId: '0000aaaa0000aaaa', - zoom: { start: 1230, end: 1234 }, - primeNav: false, - }); - - const action = { - type: LOCATION_CHANGE, - payload: { - action: 'POP', - location: { pathname: '0000aaaa0000aaaa/prime' }, - }, - }; - invoke(action); - expect(next).toHaveBeenCalledWith(action); - expect(store.dispatch).toHaveBeenCalledTimes(2); - expect(store.dispatch).toHaveBeenCalledWith(fakeInner); - expect(store.dispatch).toHaveBeenCalledWith(fakeInner2); + it('dispatches primeNav and clears selection for prime route', () => { + const store = makeStore({ dongleId: '0000aaaa0000aaaa', zoom: { start: 1, end: 2 }, segmentRange: undefined, primeNav: false }); + installHistorySync(store, history); + history.push('/0000aaaa0000aaaa/prime'); expect(actionsIndex.pushTimelineRange).toHaveBeenCalledWith(undefined, undefined, undefined, false); expect(actionsIndex.primeNav).toHaveBeenCalledWith(true); }); -}); \ No newline at end of file +}); diff --git a/src/actions/index.js b/src/actions/index.js index c523161d..308cdffc 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -1,6 +1,4 @@ -import { push } from 'connected-react-router'; import * as Sentry from '@sentry/react'; -import document from 'global/document'; import { athena as Athena, billing as Billing, devices as Devices, drives as Drives } from '@commaai/api'; import MyCommaAuth from '@commaai/my-comma-auth'; @@ -8,6 +6,7 @@ import * as Types from './types'; import { resetPlayback, selectLoop } from '../timeline/playback'; import {hasRoutesData } from '../timeline/segments'; import { getDeviceFromState, deviceVersionAtLeast } from '../utils'; +import { navigate } from '../navigation'; let routesRequest = null; let routesRequestPromise = null; @@ -169,7 +168,7 @@ function updateTimeline(state, dispatch, log_id, start, end, allowPathChange) { if (allowPathChange) { const desiredPath = urlForState(state.dongleId, log_id, Math.floor(start/1000), Math.floor(end/1000), false); if (window.location.pathname !== desiredPath) { - dispatch(push(desiredPath)); + navigate(desiredPath); } } } @@ -300,7 +299,7 @@ export function selectDevice(dongleId, allowPathChange = true) { if (allowPathChange) { const desiredPath = urlForState(dongleId, null, null, null, null); if (window.location.pathname !== desiredPath) { - dispatch(push(desiredPath)); + navigate(desiredPath); } } }; @@ -321,10 +320,10 @@ export function primeNav(nav, allowPathChange = true) { } if (allowPathChange) { - const curPath = document.location.pathname; + const curPath = window.location.pathname; const desiredPath = urlForState(state.dongleId, null, null, null, nav); if (curPath !== desiredPath) { - dispatch(push(desiredPath)); + navigate(desiredPath); } } }; @@ -461,4 +460,3 @@ export function updateRoute(fullname, route) { route, }; } - diff --git a/src/actions/index.test.js b/src/actions/index.test.js index 133accf5..fb242bf8 100644 --- a/src/actions/index.test.js +++ b/src/actions/index.test.js @@ -1,15 +1,11 @@ /* eslint-env jest */ -import { push } from 'connected-react-router'; +import { navigate } from '../navigation'; import { pushTimelineRange } from './index'; -jest.mock('connected-react-router', () => { - const originalModule = jest.requireActual('connected-react-router'); - return { - __esModule: true, - ...originalModule, - push: jest.fn(), - }; -}); +jest.mock('../navigation', () => ({ + navigate: jest.fn(), + replace: jest.fn(), +})); describe('timeline actions', () => { it('should push history state when editing zoom', () => { @@ -23,6 +19,6 @@ describe('timeline actions', () => { zoom: {}, })); actionThunk(dispatch, getState); - expect(push).toBeCalledWith('/statedongle/log_id'); + expect(navigate).toBeCalledWith('/statedongle/log_id'); }); -}); \ No newline at end of file +}); diff --git a/src/components/IosPwaPopup/index.jsx b/src/components/IosPwaPopup/index.jsx index 3246478c..cbbc4bfb 100644 --- a/src/components/IosPwaPopup/index.jsx +++ b/src/components/IosPwaPopup/index.jsx @@ -1,6 +1,5 @@ import React, { Component } from 'react'; -import { connect } from 'react-redux'; -import Obstruction from 'obstruction'; +import { withRouter } from 'react-router'; import localforage from 'localforage'; import { withStyles, Typography } from '@material-ui/core'; import { Clear } from '@material-ui/icons'; @@ -85,7 +84,7 @@ class IosPwaPopup extends Component { window.removeEventListener('click', this.onWindowClick); } - if (prevProps.pathname !== this.props.pathname) { + if (prevProps.location?.pathname !== this.props.location?.pathname) { this.hide(); } } @@ -138,8 +137,4 @@ class IosPwaPopup extends Component { } } -const stateToProps = Obstruction({ - pathname: 'router.location.pathname', -}); - -export default connect(stateToProps)(withStyles(styles)(IosPwaPopup)); +export default withRouter(withStyles(styles)(IosPwaPopup)); diff --git a/src/components/anonymous.jsx b/src/components/anonymous.jsx index c4be74c7..cab469b0 100644 --- a/src/components/anonymous.jsx +++ b/src/components/anonymous.jsx @@ -1,7 +1,6 @@ /* global AppleID */ import React, { Component } from 'react'; -import { connect } from 'react-redux'; -import Obstruction from 'obstruction'; +import { withRouter } from 'react-router'; import PropTypes from 'prop-types'; import qs from 'query-string'; @@ -175,12 +174,7 @@ class AnonymousLanding extends Component { } AnonymousLanding.propTypes = { - pathname: PropTypes.string.isRequired, classes: PropTypes.object.isRequired, }; -const stateToProps = Obstruction({ - pathname: 'router.location.pathname', -}); - -export default connect(stateToProps)(withStyles(styles)(AnonymousLanding)); +export default withRouter(withStyles(styles)(AnonymousLanding)); diff --git a/src/components/explorer.jsx b/src/components/explorer.jsx index 5d61fac9..e2f6e46a 100644 --- a/src/components/explorer.jsx +++ b/src/components/explorer.jsx @@ -2,7 +2,8 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; import Obstruction from 'obstruction'; import localforage from 'localforage'; -import { replace } from 'connected-react-router'; +import { withRouter } from 'react-router'; +import { replace } from '../navigation'; import { withStyles, Button, CircularProgress, Divider, Modal, Paper, Typography } from '@material-ui/core'; import 'mapbox-gl/src/css/mapbox-gl.css'; @@ -85,7 +86,7 @@ class ExplorerApp extends Component { const q = new URLSearchParams(window.location.search); if (q.has('r')) { - this.props.dispatch(replace(q.get('r'))); + replace(q.get('r')); } this.props.dispatch(init()); @@ -135,9 +136,10 @@ class ExplorerApp extends Component { } componentDidUpdate(prevProps, prevState) { - const { pathname, zoom, dongleId, limit } = this.props; + const { location, zoom, dongleId, limit } = this.props; + const pathname = location?.pathname; - if (prevProps.pathname !== pathname) { + if (prevProps.location?.pathname !== pathname) { this.setState({ drawerIsOpen: false }); } @@ -252,11 +254,10 @@ class ExplorerApp extends Component { const stateToProps = Obstruction({ zoom: 'zoom', - pathname: 'router.location.pathname', dongleId: 'dongleId', devices: 'devices', currentRoute: 'currentRoute', limit: 'limit', }); -export default connect(stateToProps)(withStyles(styles)(ExplorerApp)); +export default withRouter(connect(stateToProps)(withStyles(styles)(ExplorerApp))); diff --git a/src/history.js b/src/history.js new file mode 100644 index 00000000..2de80a22 --- /dev/null +++ b/src/history.js @@ -0,0 +1,5 @@ +import { createBrowserHistory } from 'history'; + +export const history = createBrowserHistory(); +export default history; + diff --git a/src/historySync.js b/src/historySync.js new file mode 100644 index 00000000..3eb1818f --- /dev/null +++ b/src/historySync.js @@ -0,0 +1,50 @@ +import { getDongleID, getZoom, getSegmentRange, getPrimeNav } from './url'; +import { primeNav, selectDevice, pushTimelineRange, updateSegmentRange } from './actions'; +import { drives as Drives } from '@commaai/api'; + +export function installHistorySync(store, history) { + async function handle(location, action) { + const state = store.getState(); + const pathname = location.pathname; + + const pathDongleId = getDongleID(pathname); + if (pathDongleId && pathDongleId !== state.dongleId) { + store.dispatch(selectDevice(pathDongleId, false)); + } + + const pathZoom = getZoom(pathname); + const pathSegmentRange = getSegmentRange(pathname); + + if ((pathZoom !== state.zoom) && pathZoom && !pathSegmentRange) { + try { + const routesData = await Drives.getRoutesSegments(pathDongleId, pathZoom.start, pathZoom.end); + if (routesData && routesData.length > 0) { + const log_id = routesData[0].fullname.split('|')[1]; + const duration = routesData[0].end_time_utc_millis - routesData[0].start_time_utc_millis; + + store.dispatch(pushTimelineRange(log_id, null, null, true)); + store.dispatch(updateSegmentRange(log_id, 0, duration)); + } + } catch (err) { + console.error('Error fetching routes data for log ID conversion', err); + } + } + + if (pathSegmentRange !== state.segmentRange) { + store.dispatch(pushTimelineRange(pathSegmentRange?.log_id, pathSegmentRange?.start, pathSegmentRange?.end, false)); + } + + const pathPrimeNav = getPrimeNav(pathname); + if (pathPrimeNav !== state.primeNav) { + store.dispatch(primeNav(pathPrimeNav)); + } + } + + // Subscribe to future changes + history.listen(handle); + // Handle the current location once on startup + handle(history.location, 'POP'); +} + +export default installHistorySync; + diff --git a/src/index.jsx b/src/index.jsx index 8cb074ad..198e534b 100644 --- a/src/index.jsx +++ b/src/index.jsx @@ -5,6 +5,9 @@ import * as Sentry from '@sentry/react'; import './index.css'; import App from './App'; +import store from './store'; +import { history } from './history'; +import installHistorySync from './historySync'; import Theme from './theme'; if (window.SENTRY_ENV) { @@ -28,3 +31,6 @@ ReactDOM.createRoot(document.getElementById('root')).render(( )); + +// Install router -> store sync +installHistorySync(store, history); diff --git a/src/navigation.js b/src/navigation.js new file mode 100644 index 00000000..c2c15aff --- /dev/null +++ b/src/navigation.js @@ -0,0 +1,12 @@ +import { history } from './history'; + +export function navigate(path) { + history.push(path); +} + +export function replace(path) { + history.replace(path); +} + +export default { navigate, replace }; + diff --git a/src/store.js b/src/store.js index 5b1e379d..02277ece 100644 --- a/src/store.js +++ b/src/store.js @@ -1,23 +1,18 @@ import * as Redux from 'redux'; -import { connectRouter, routerMiddleware } from 'connected-react-router'; import thunk from 'redux-thunk'; -import { createBrowserHistory } from 'history'; import reduceReducers from 'reduce-reducers'; import reducers from './reducers'; import composeEnhancers from './devtools'; import initialState from './initialState'; -import { onHistoryMiddleware } from './actions/history'; - -export const history = createBrowserHistory(); +import { history } from './history'; const store = Redux.createStore( - connectRouter(history)(reduceReducers(initialState, ...reducers)), + reduceReducers(initialState, ...reducers), composeEnhancers(Redux.applyMiddleware( thunk, - onHistoryMiddleware, - routerMiddleware(history), )), ); +export { history }; export default store; From ff6003c244c6f828bd3ec5d1fa0d97e22a302ec5 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 1 Nov 2025 23:40:24 -0700 Subject: [PATCH 08/26] lil more --- README.md | 8 ++++---- src/components/explorer.jsx | 2 +- vite.config.js | 11 +++++++++++ 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 59b2d0f5..c885689d 100644 --- a/README.md +++ b/README.md @@ -3,12 +3,12 @@ # comma connect -The frontend to the comma connect progressive web app. This a react app using [Create React App](https://github.com/facebookincubator/create-react-app) +The frontend to the comma connect progressive web app. This is a React app built with Vite. ## Development -* Install Bun: https://bun.sh -* Install dependencies: `bun install` -* Start dev server: `bun run start` +- Install Bun: https://bun.sh +- Install dependencies: `bun install` +- Start dev server: `bun run start` ### Other scripts - Run unit tests: `bun run test` diff --git a/src/components/explorer.jsx b/src/components/explorer.jsx index e2f6e46a..3c85d323 100644 --- a/src/components/explorer.jsx +++ b/src/components/explorer.jsx @@ -6,7 +6,7 @@ import { withRouter } from 'react-router'; import { replace } from '../navigation'; import { withStyles, Button, CircularProgress, Divider, Modal, Paper, Typography } from '@material-ui/core'; -import 'mapbox-gl/src/css/mapbox-gl.css'; +import 'mapbox-gl/dist/mapbox-gl.css'; import { devices as Devices } from '@commaai/api'; diff --git a/vite.config.js b/vite.config.js index 4c29d977..39fd834f 100644 --- a/vite.config.js +++ b/vite.config.js @@ -22,6 +22,17 @@ export default defineConfig(({ mode }) => { build: { // Required for Sentry sourcemap: true, + chunkSizeWarningLimit: 1500, + rollupOptions: { + output: { + manualChunks: { + 'react-vendor': ['react', 'react-dom'], + 'mui': ['@material-ui/core', '@material-ui/icons'], + 'mapbox': ['mapbox-gl', 'react-map-gl'], + 'sentry': ['@sentry/react'], + }, + }, + }, }, plugins: [ // TODO: compression plugin From b17823eb4a96896f14969ff18a66c68b5212ee46 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 2 Nov 2025 13:49:34 -0800 Subject: [PATCH 09/26] clicking around works now --- src/actions/history.test.js | 28 ++-- src/actions/index.js | 80 ++++------- src/actions/types.js | 4 - src/components/AppDrawer/index.jsx | 7 +- src/components/AppHeader/index.jsx | 11 +- .../Dashboard/DeviceSettingsModal.jsx | 5 +- src/components/Dashboard/index.jsx | 9 +- src/components/DeviceInfo/index.jsx | 7 +- src/components/DriveMap/index.jsx | 11 +- src/components/DriveVideo/index.jsx | 18 +-- src/components/DriveView/Media.jsx | 22 ++-- src/components/DriveView/index.jsx | 32 ++--- src/components/Files/UploadQueue.jsx | 7 +- src/components/Navigation/index.jsx | 4 +- src/components/Prime/PrimeCheckout.jsx | 4 +- src/components/Prime/PrimeManage.jsx | 5 +- src/components/TimeDisplay/index.jsx | 10 +- src/components/Timeline/index.jsx | 24 ++-- src/components/explorer.jsx | 28 ++-- src/historySync.js | 23 ++-- src/initialState.js | 8 +- src/reducers/globalState.js | 124 +----------------- src/selectors/route.js | 56 ++++++++ src/timeline/playback.js | 10 +- src/url.js | 9 +- 25 files changed, 225 insertions(+), 321 deletions(-) create mode 100644 src/selectors/route.js diff --git a/src/actions/history.test.js b/src/actions/history.test.js index 7e7a2181..da83659c 100644 --- a/src/actions/history.test.js +++ b/src/actions/history.test.js @@ -3,11 +3,11 @@ import { history } from '../history'; import installHistorySync from '../historySync'; import * as actionsIndex from './index'; import { drives as Drives } from '@commaai/api'; +import { replace } from '../navigation'; jest.mock('./index', () => ({ selectDevice: jest.fn(), pushTimelineRange: jest.fn(), - primeNav: jest.fn(), updateSegmentRange: jest.fn(), })); @@ -17,6 +17,14 @@ jest.mock('@commaai/api', () => ({ }, })); +jest.mock('../navigation', () => { + const { history } = require('../history'); + const mock = { + replace: jest.fn((path) => history.replace(path)), + }; + return mock; +}); + const makeStore = (initialState) => ({ getState: jest.fn(() => initialState), dispatch: jest.fn(), @@ -35,7 +43,7 @@ describe('history sync', () => { expect(actionsIndex.selectDevice).toHaveBeenCalledWith('0000aaaa0000aaaa', false); }); - it('dispatches conversion for zoom route', async () => { + it('dispatches conversion for zoom route (canonicalize URL)', async () => { Drives.getRoutesSegments.mockResolvedValueOnce([ { fullname: '0000aaaa0000aaaa|00000000--000f00000d', @@ -48,15 +56,19 @@ describe('history sync', () => { history.push('/0000aaaa0000aaaa/1230/1234'); // Allow async conversion to resolve await new Promise((r) => setTimeout(r, 0)); - expect(actionsIndex.pushTimelineRange).toHaveBeenCalledWith('00000000--000f00000d', null, null, true); - expect(actionsIndex.updateSegmentRange).toHaveBeenCalledWith('00000000--000f00000d', 0, 1000); + expect(replace).toHaveBeenCalledWith('/0000aaaa0000aaaa/00000000--000f00000d/1230/1234'); + // After replace, pathSegmentRange processing should dispatch updates + await new Promise((r) => setTimeout(r, 0)); + expect(actionsIndex.pushTimelineRange).toHaveBeenCalledWith('00000000--000f00000d', 1230000, 1234000, false); }); - it('dispatches primeNav and clears selection for prime route', () => { - const store = makeStore({ dongleId: '0000aaaa0000aaaa', zoom: { start: 1, end: 2 }, segmentRange: undefined, primeNav: false }); + it('handles prime route via URL (no dispatch)', () => { + history.replace('/'); + const store = makeStore({ dongleId: '0000aaaa0000aaaa', zoom: { start: 1, end: 2 }, segmentRange: undefined }); installHistorySync(store, history); + store.dispatch.mockClear(); history.push('/0000aaaa0000aaaa/prime'); - expect(actionsIndex.pushTimelineRange).toHaveBeenCalledWith(undefined, undefined, undefined, false); - expect(actionsIndex.primeNav).toHaveBeenCalledWith(true); + // no store dispatch needed for prime; components derive from URL + expect(store.dispatch).not.toHaveBeenCalled(); }); }); diff --git a/src/actions/index.js b/src/actions/index.js index 308cdffc..5772dcb4 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -5,6 +5,7 @@ import MyCommaAuth from '@commaai/my-comma-auth'; import * as Types from './types'; import { resetPlayback, selectLoop } from '../timeline/playback'; import {hasRoutesData } from '../timeline/segments'; +import { selectSegmentRange } from '../selectors/route'; import { getDeviceFromState, deviceVersionAtLeast } from '../utils'; import { navigate } from '../navigation'; @@ -31,10 +32,11 @@ export function checkRoutesData() { const { dongleId } = state; const fetchRange = state.filter; - // if requested segment range not in loaded routes, fetch it explicitly - if (state.segmentRange) { + // if requested segment range (from URL) not in loaded routes, fetch it explicitly + const urlSeg = selectSegmentRange(); + if (urlSeg) { routesRequest = { - req: Drives.getRoutesSegments(dongleId, undefined, undefined, undefined, `${dongleId}|${state.segmentRange.log_id}`), + req: Drives.getRoutesSegments(dongleId, undefined, undefined, undefined, `${dongleId}|${urlSeg.log_id}`), dongleId, }; } else { @@ -142,7 +144,7 @@ export function checkLastRoutesData() { }; } -export function urlForState(dongleId, log_id, start, end, prime) { +export function urlForState(dongleId, log_id, start, end) { const path = [dongleId]; if (log_id) { @@ -151,8 +153,6 @@ export function urlForState(dongleId, log_id, start, end, prime) { path.push(start); path.push(end); } - } else if (prime) { - path.push('prime'); } return `/${path.join('/')}`; @@ -166,7 +166,7 @@ function updateTimeline(state, dispatch, log_id, start, end, allowPathChange) { } if (allowPathChange) { - const desiredPath = urlForState(state.dongleId, log_id, Math.floor(start/1000), Math.floor(end/1000), false); + const desiredPath = urlForState(state.dongleId, log_id, Math.floor(start/1000), Math.floor(end/1000)); if (window.location.pathname !== desiredPath) { navigate(desiredPath); } @@ -176,13 +176,8 @@ function updateTimeline(state, dispatch, log_id, start, end, allowPathChange) { export function popTimelineRange(log_id, allowPathChange = true) { return (dispatch, getState) => { const state = getState(); - if (state.zoom.previous) { - dispatch({ - type: Types.TIMELINE_POP_SELECTION, - }); - - const { start, end } = state.zoom.previous; - updateTimeline(state, dispatch, log_id, start, end, allowPathChange); + if (allowPathChange && state.dongleId) { + navigate(`/${state.dongleId}/${log_id || ''}`.replace(/\/$/, '')); } }; } @@ -190,19 +185,18 @@ export function popTimelineRange(log_id, allowPathChange = true) { export function pushTimelineRange(log_id, start, end, allowPathChange = true) { return (dispatch, getState) => { const state = getState(); - - if (state.zoom?.start !== start || state.zoom?.end !== end || state.segmentRange?.log_id !== log_id) { - dispatch({ - type: Types.TIMELINE_PUSH_SELECTION, - log_id, - start, - end, - }); + if (allowPathChange && state.dongleId) { + const desiredPath = urlForState(state.dongleId, log_id, Math.floor((start||0)/1000), Math.floor((end||0)/1000)); + if (window.location.pathname !== desiredPath) { + navigate(desiredPath); + } + } + // update loop to reflect new selection + if (start != null && end != null) { + dispatch(resetPlayback()); + dispatch(selectLoop(start, end)); } - - updateTimeline(state, dispatch, log_id, start, end, allowPathChange); }; - } @@ -262,14 +256,7 @@ export function fetchDeviceOnline(dongleId) { }; } -export function updateSegmentRange(log_id, start, end) { - return { - type: Types.ACTION_UPDATE_SEGMENT_RANGE, - log_id, - start, - end, - }; -} +// segment range is derived from URL; no update action needed export function selectDevice(dongleId, allowPathChange = true) { return (dispatch, getState) => { @@ -288,7 +275,6 @@ export function selectDevice(dongleId, allowPathChange = true) { }); dispatch(pushTimelineRange(null, null, null, false)); - dispatch(updateSegmentRange(null, null, null)); if ((device && !device.shared) || state.profile?.superuser) { dispatch(primeFetchSubscription(dongleId, device)); dispatch(fetchDeviceOnline(dongleId)); @@ -297,7 +283,7 @@ export function selectDevice(dongleId, allowPathChange = true) { dispatch(checkRoutesData()); if (allowPathChange) { - const desiredPath = urlForState(dongleId, null, null, null, null); + const desiredPath = urlForState(dongleId, null, null, null); if (window.location.pathname !== desiredPath) { navigate(desiredPath); } @@ -305,29 +291,7 @@ export function selectDevice(dongleId, allowPathChange = true) { }; } -export function primeNav(nav, allowPathChange = true) { - return (dispatch, getState) => { - const state = getState(); - if (!state.dongleId) { - return; - } - - if (state.primeNav !== nav) { - dispatch({ - type: Types.ACTION_PRIME_NAV, - primeNav: nav, - }); - } - - if (allowPathChange) { - const curPath = window.location.pathname; - const desiredPath = urlForState(state.dongleId, null, null, null, nav); - if (curPath !== desiredPath) { - navigate(desiredPath); - } - } - }; -} +// prime view is now derived from URL export function fetchSharedDevice(dongleId) { return async (dispatch) => { diff --git a/src/actions/types.js b/src/actions/types.js index b9dc4aa1..cfa917ca 100644 --- a/src/actions/types.js +++ b/src/actions/types.js @@ -1,5 +1,3 @@ -export const TIMELINE_PUSH_SELECTION = 'TIMELINE_PUSH_SELECTION'; -export const TIMELINE_POP_SELECTION = 'TIMELINE_POP_SELECTION'; // init export const ACTION_STARTUP_DATA = 'ACTION_STARTUP_DATA'; @@ -16,7 +14,6 @@ export const ACTION_UPDATE_ROUTE_LOCATION = 'ACTION_UPDATE_ROUTE_LOCATION'; export const ACTION_UPDATE_SHARED_DEVICE = 'ACTION_UPDATE_SHARED_DEVICE'; export const ACTION_UPDATE_DEVICE_ONLINE = 'ACTION_UPDATE_DEVICE_ONLINE'; export const ACTION_UPDATE_DEVICE_NETWORK = 'ACTION_UPDATE_DEVICE_NETWORK'; -export const ACTION_PRIME_NAV = 'ACTION_PRIME_NAV'; export const ACTION_PRIME_SUBSCRIPTION = 'ACTION_PRIME_SUBSCRIPTION'; export const ACTION_PRIME_SUBSCRIBE_INFO = 'ACTION_PRIME_SUBSCRIBE_INFO'; @@ -29,7 +26,6 @@ export const ACTION_BUFFER_VIDEO = 'action_buffer_video'; export const ACTION_RESET = 'action_reset'; // segments -export const ACTION_UPDATE_SEGMENT_RANGE = 'update_segment_range'; export const ACTION_ROUTES_METADATA = 'routes_metadata'; // files diff --git a/src/components/AppDrawer/index.jsx b/src/components/AppDrawer/index.jsx index 46d75a1a..7c1e56da 100644 --- a/src/components/AppDrawer/index.jsx +++ b/src/components/AppDrawer/index.jsx @@ -1,6 +1,5 @@ import React, { useCallback, useEffect, useRef } from 'react'; import { connect } from 'react-redux'; -import Obstruction from 'obstruction'; import { Link } from 'react-router-dom'; import Drawer from '@material-ui/core/Drawer'; @@ -57,9 +56,9 @@ const AppDrawer = ({ ); }; -const stateToProps = Obstruction({ - selectedDongleId: 'dongleId', - device: 'device', +const stateToProps = (state) => ({ + selectedDongleId: state.dongleId, + device: state.device, }); export default connect(stateToProps)(AppDrawer); diff --git a/src/components/AppHeader/index.jsx b/src/components/AppHeader/index.jsx index b7b575f3..9fe33544 100644 --- a/src/components/AppHeader/index.jsx +++ b/src/components/AppHeader/index.jsx @@ -1,6 +1,5 @@ import React, { Suspense, useCallback, useState } from 'react'; import { connect } from 'react-redux'; -import Obstruction from 'obstruction'; import { withStyles } from '@material-ui/core/styles'; import { Typography, IconButton, Icon, AppBar } from '@material-ui/core'; @@ -58,7 +57,7 @@ const styles = () => ({ const AppHeader = ({ profile, classes, dispatch, drawerIsOpen, viewingRoute, showDrawerButton, - forwardRef, handleDrawerStateChanged, primeNav, dongleId, + forwardRef, handleDrawerStateChanged, dongleId, }) => { const [anchorEl, setAnchorEl] = useState(null); @@ -136,11 +135,9 @@ const AppHeader = ({ ); }; -const stateToProps = Obstruction({ - dongleId: 'dongleId', - filter: 'filter', - profile: 'profile', - primeNav: 'primeNav', +const stateToProps = (state) => ({ + dongleId: state.dongleId, + profile: state.profile, }); export default connect(stateToProps)(withStyles(styles)(AppHeader)); diff --git a/src/components/Dashboard/DeviceSettingsModal.jsx b/src/components/Dashboard/DeviceSettingsModal.jsx index 2c99eb74..7fb1fa14 100644 --- a/src/components/Dashboard/DeviceSettingsModal.jsx +++ b/src/components/Dashboard/DeviceSettingsModal.jsx @@ -19,7 +19,8 @@ import ShareIcon from '@material-ui/icons/Share'; import WarningIcon from '@material-ui/icons/Warning'; import { devices as Devices } from '@commaai/api'; -import { primeNav, selectDevice, updateDevice } from '../../actions'; +import { selectDevice, updateDevice } from '../../actions'; +import { navigate } from '../../navigation'; import Colors from '../../colors'; import { ErrorOutline } from '../../icons'; import UploadQueue from '../Files/UploadQueue'; @@ -233,7 +234,7 @@ class DeviceSettingsModal extends Component { if (intv) { clearInterval(intv); } - this.props.dispatch(primeNav(true)); + navigate(`/${this.props.globalDongleId || this.props.dongleId}/prime`); this.props.onClose(); }; diff --git a/src/components/Dashboard/index.jsx b/src/components/Dashboard/index.jsx index 1bd585ef..888d5b3d 100644 --- a/src/components/Dashboard/index.jsx +++ b/src/components/Dashboard/index.jsx @@ -1,6 +1,7 @@ import React, { lazy, Suspense } from 'react'; import { connect } from 'react-redux'; import Obstruction from 'obstruction'; +import { withRouter } from 'react-router'; import { CircularProgress, Grid } from '@material-ui/core'; @@ -18,7 +19,10 @@ const DashboardLoading = () => ( ); -const Dashboard = ({ primeNav, device, dongleId }) => { +import { getPrimeNav } from '../../url'; + +const Dashboard = ({ location, device, dongleId }) => { + const primeNav = getPrimeNav(location?.pathname || '/'); if (!device || !dongleId) { return ; } @@ -42,8 +46,7 @@ const Dashboard = ({ primeNav, device, dongleId }) => { const stateToProps = Obstruction({ dongleId: 'dongleId', - primeNav: 'primeNav', device: 'device', }); -export default connect(stateToProps)(Dashboard); +export default withRouter(connect(stateToProps)(Dashboard)); diff --git a/src/components/DeviceInfo/index.jsx b/src/components/DeviceInfo/index.jsx index 64dd1907..55567df6 100644 --- a/src/components/DeviceInfo/index.jsx +++ b/src/components/DeviceInfo/index.jsx @@ -1,6 +1,5 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; -import Obstruction from 'obstruction'; import * as Sentry from '@sentry/react'; import dayjs from 'dayjs'; @@ -571,9 +570,9 @@ class DeviceInfo extends Component { } } -const stateToProps = Obstruction({ - dongleId: 'dongleId', - device: 'device', +const stateToProps = (state) => ({ + dongleId: state.dongleId, + device: state.device, }); export default connect(stateToProps)(withStyles(styles)(DeviceInfo)); diff --git a/src/components/DriveMap/index.jsx b/src/components/DriveMap/index.jsx index a84b4632..dc08de56 100644 --- a/src/components/DriveMap/index.jsx +++ b/src/components/DriveMap/index.jsx @@ -1,6 +1,7 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; -import Obstruction from 'obstruction'; + +import { selectCurrentRoute } from '../../selectors/route'; import ReactMapGL, { LinearInterpolator } from 'react-map-gl'; @@ -306,10 +307,10 @@ class DriveMap extends Component { } } -const stateToProps = Obstruction({ - offset: 'offset', - currentRoute: 'currentRoute', - startTime: 'startTime', +const stateToProps = (state) => ({ + offset: state.offset, + currentRoute: selectCurrentRoute(state), + startTime: state.startTime, }); export default connect(stateToProps)(DriveMap); diff --git a/src/components/DriveVideo/index.jsx b/src/components/DriveVideo/index.jsx index b35f95b7..e53ed58a 100644 --- a/src/components/DriveVideo/index.jsx +++ b/src/components/DriveVideo/index.jsx @@ -3,7 +3,7 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; import { CircularProgress, Typography } from '@material-ui/core'; import debounce from 'debounce'; -import Obstruction from 'obstruction'; +import { selectCurrentRoute } from '../../selectors/route'; import ReactPlayer from 'react-player/file'; import { video as Video } from '@commaai/api'; @@ -323,14 +323,14 @@ class DriveVideo extends Component { } } -const stateToProps = Obstruction({ - dongleId: 'dongleId', - desiredPlaySpeed: 'desiredPlaySpeed', - offset: 'offset', - startTime: 'startTime', - isBufferingVideo: 'isBufferingVideo', - routes: 'routes', - currentRoute: 'currentRoute', +const stateToProps = (state) => ({ + dongleId: state.dongleId, + desiredPlaySpeed: state.desiredPlaySpeed, + offset: state.offset, + startTime: state.startTime, + isBufferingVideo: state.isBufferingVideo, + routes: state.routes, + currentRoute: selectCurrentRoute(state), }); export default connect(stateToProps)(DriveVideo); diff --git a/src/components/DriveView/Media.jsx b/src/components/DriveView/Media.jsx index 4efb5cf9..19ac764d 100644 --- a/src/components/DriveView/Media.jsx +++ b/src/components/DriveView/Media.jsx @@ -864,16 +864,18 @@ class Media extends Component { } } -const stateToProps = Obstruction({ - dongleId: 'dongleId', - device: 'device', - routes: 'routes', - currentRoute: 'currentRoute', - loop: 'loop', - filter: 'filter', - files: 'files', - profile: 'profile', - isBufferingVideo: 'isBufferingVideo', +import { selectCurrentRoute } from '../../selectors/route'; + +const stateToProps = (state) => ({ + dongleId: state.dongleId, + device: state.device, + routes: state.routes, + currentRoute: selectCurrentRoute(state), + loop: state.loop, + filter: state.filter, + files: state.files, + profile: state.profile, + isBufferingVideo: state.isBufferingVideo, }); export default connect(stateToProps)(withStyles(styles)(Media)); diff --git a/src/components/DriveView/index.jsx b/src/components/DriveView/index.jsx index e0aa1abf..91f2942e 100644 --- a/src/components/DriveView/index.jsx +++ b/src/components/DriveView/index.jsx @@ -1,11 +1,11 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; -import Obstruction from 'obstruction'; import dayjs from 'dayjs'; import { IconButton, Typography } from '@material-ui/core'; -import { popTimelineRange, pushTimelineRange, updateSegmentRange } from '../../actions'; +import { navigate } from '../../navigation'; +import { selectRouteZoom, selectCurrentRoute } from '../../selectors/route'; import { ArrowBackBold, CloseBold } from '../../icons'; import { filterRegularClick } from '../../utils'; @@ -19,25 +19,20 @@ class DriveView extends Component { } onBack(zoom, currentRoute) { - if (zoom.previous) { - this.props.dispatch(popTimelineRange(currentRoute?.log_id)); - } else if (currentRoute) { - this.props.dispatch( - pushTimelineRange(currentRoute.log_id, null, null), - ); + if (currentRoute) { + navigate(`/${this.props.dongleId}/${currentRoute.log_id}`); } } close() { - this.props.dispatch(pushTimelineRange(null, null, null)); - this.props.dispatch(updateSegmentRange(null, null, null)); + navigate(`/${this.props.dongleId}`); } render() { const { dongleId, zoom, currentRoute, routes } = this.props; const currentRouteBoundsSelected = zoom.start === 0 && zoom.end === currentRoute?.duration; - const backButtonDisabled = !zoom?.previousZoom && currentRouteBoundsSelected; + const backButtonDisabled = currentRouteBoundsSelected; // FIXME: end time not always same day as start time const start = currentRoute.start_time_utc_millis + zoom.start; @@ -63,9 +58,8 @@ class DriveView extends Component { {`${startTime} - ${endTime}`}

    X6|(n!VxCbSHlLjwa%PBGKwQ^-EOb$75_hnuD|hA<$rkB{nuAI` z?@*7$CpCJtA5^j6f@F(WE2M9yr7w=o+)_C?q`^=VT*?{cisos3by-{o$JWC){C;7f7-WYAJ z6EkKG7P^=OUn(&8i*+*_lD4M6Qd}8d8kYXvMXa@qmAa$HXwxE^@*N=!O-0)i<~==A zxlKoFn3m)-($VI_Xf|KI8Dk2>a1T%?!7TobOUl$3W@GDm-6Fw!9YZS36Fs&3B(&Ai z#}i-Z{>eIJJ0}|d($w;1q6z<&TCE?;(-Y*^di?OorN{h9}y+?Z@pY@8?Lb-!JOicg<2H#wxuIJ1hlt}$3B_24a|2S0s3hRts~^`+y? zX<7V;1#OWy>-^EzHy``%aIyt0vnH03{=aoSJAMHsOBoh(AHQWzPjm+6;S^o}mS@tr zxMJ<5(V-i1&_-GT5VHL(lURnF_rGP{EyGASfu%NI$|jkJMD!X-=5iV5ftaXCp8h_6 z?Tef{LY^IRc!!~Abd|S4iuFA=w{g<0h1yDS-wb(Cn`>pMcMUAm&wJxi4Vk&NZ)bN8 z>E@VnnUHeiV&&#pmjf0xoxbhVG&?K{;CUTv_G62i&&wi{|;9%$3q{05As`p@$ znTn+={bbKc+%{)}DW9)8uaBVl%u&ssce2@`v|=Y4{|;C-#8Nv~mw$?%*r#cpQOUXX zm~1jupu`DSXm2i|x&O^~-_H9XX=x9gwB}nO6Dl6gRp;Q|n(kaw6|eP^O*`Vcey}XY zr=3${b##*yU3F=)nSq7FF~xjbfrWp$+@1k5_w%|R_?6!Mz@1B!ZkMM|;h8(~U%K<` z8wGxz7EOrmFt{!DnQCTSB#rdAEpf9=HJ##c3r;l$+wjRjjF)v&<*;tQ?7K&EI?i+3 z=)N9> zGh}<%=H}GXY$Mxo?X1^Pm`XIo4l9jeKh9WEui;_$)~07NI5gGlCl}WlEYz)6GIYr| z=y<26?zG&wq@OyMBj+_*0 z&d@3aW|`AUD~1?>ROevKHSY%B2iCFDqB?c0kQ3u~24y>N%QJ@Ex5V~J$nFb!rDQG2 zT%Cxi3GvUa=davP8d=Ysrh5$apJmpthWdw5X0OlQoMoPCwY6ZD397;EpWRB!XPJ6U z(LL+8DA%jc($%xf0akd9ZL`dbI^_8srP4X+UvGbl@`DQLvnGv4YIC}pkoua+6%=TQFj%PRF zSrWUSPqwjFke;(LTX3m=7>KUfCZrbi^~^DWPBJe%+w`kNMas@L?U>J8waG}$JMx2u zb>ctUuiYwZVrn(pY{k+QkA-$5TP)u=qfDwfTBlhS!)KeDSj4=Ih35AGl}3HCBcWVI zw?#xapQ0=yMDu!3flHyMX1trv3W?^E=imG=28oJ%4&!-)-TZR72h|J7n=+4`EZF4rh-w4>&vv zf4j3CHRhOu^=UKv8sL~~PB94nTJ~p{>lyZe(}ssWKmLPfXVu-IL*|-dbt%VaEHt^N zJ6rB*-PtoUxJ&9@XH1)GI$;s>>OrxPxEd~t=ckRyvt{ZHtCq|&)ST z;q|DiN7H^rPOHA2jSjn#RvY~Dq1_Tp2qD@XNvzNAh-VaYmt{5Ejd>=qDVLI%p$ zry9CpQwS%4-Td~Jlzoh=nb(zdfu~J+{?T>%xat=)<60H8=RT_?{%LS{?rf|^wEDgI z`({<+6l4CsPAXed)ue=T5Bs;jj_WnA9Lif&PHxz z7tS?fw6FWG)1l+LS!TaS{+ERR;TmsO!|u0N-wpgW({pL8w&!V?ir)|90SotC0R3jy z_2sega<#bg2yUC=M6~ZjZZ0!@+p_&yQiH}!!t|1?% zx|b^?^1kOP@7^U?zrqZ_!oeQe|i|o z$P75e%+5rW?qf5JAXo6mo(0D7qyo?5+9r9PY;osgr)aHX?UkmrN{q6X%m2xBy=oO# z+KW1z?!Z1^=g&;~j(l9kMo@T1%JlDBMihwW>v)uXlnuvadkhqoAfNez1G*g7aJ8k?37%$SG2!57*Eeyfv&%Q+$om5cKgx0XX{O) zevAR@@h3<24W?gbZeSX2;3Sw`4E>U?-E=7 zIWx(p>B{-ZsqV8vdiz!A^}$tV@8po18%0JBVT|2or8HikHWeiri&v) z`MI(c?tJR>e%;r*A0~|O>i@Z!N?g}`EVP>zdOpqNi>11xsLi*Zn;lC18Wx4H*fD;< zls&(n*5@x)O9X84?3I1lw(_i{VhEoPuOvj z2ni#k#uuv}#NOHYgB>^8>(fo99dTWUuuzMvXz|^eKUR$7LwP&ygH2|JQjgy3vFLgI zz44XD7x!$_yX)PS5bmrKk9JElsb>1xUUuqijchij6n7gI#j%*{Jv!jx)IBSbQ~!gI zU_v^l&M?258KO_4t@@_fVv2R6WZ_#pyNI=aXxzBnoy<*=Et+gGov?@*goW~d(71ij zm|y+Q+WAL&EhmI!RpNt2?ccxJY&=hq*r^}eVm?#cCs?Sx8y}C~QF?!Lijw8~!V@yK zbn!|ZqSokhVs~#wd)58IJXOj1VWE7xy2kWfxvpi^u2>H^CQQSITdg}eutN6!{uGPGi9Je1K8bu?flyBYr zbw4fqtu|ZmrP)th*B&hLVsYk0w}o$R8?n^3DD8FW%eg&BJmXeR!yH|C>8njY%ot%C zM0!;sLMKuoN5@Z}*!k#!pk#~uUzvkSy%rYAf7=_~H?04->ak>tfrMxfZ=3n^ z8y%Z1o|zmn_bU_Jlek}Dp@unKy6EIOo4V+NX*J9rR@|EJz1^hYli%J-4)Nb+`V!aG zbem@#mNay0n4?ze*BstuQF4%4&uwP0QlH3iZjN`npXWuNx(VuTHX*c|u#^xza6Uav z&HCp4-AH#xj6P%BwarxO&DthaFXl;mFWd8gXn<+d%jxS#+-{~};R+*ZT>~~e3O+F- zap7iv@8#P)`M)%InypH!*bZ~77Z;aTN3#-kSVf3=wdLQ>+okz{-IGRC&R54Z8BaTN zx(3iM+R@0C^==Mm`yWljU|hQf*5mai|3Ih9?)sDuT|4ZE zp2U&|&c8jEZ$Fm)SH)j0*sCgL7sYPOSJ~M`x9#i_l=^EJSm*FROw37}%zjnhPQ%X2 zPAgjXWdAaR{@3GIb*Jb15Xm`P-;bbkl7}%51}&Y3EYp} z|J9$K*3IS{`EPCX-}a!Lx?Sp5^~TF~uWHkOuygmJ=Q|`Sv7MtG!*1bHUe=^ASnLF2)V*b@8c3o}PQ-kC-vrBEq=Qiuq7}B*y*WX-(x%|2B4D1*$r||Nz-RthN zTxB(<6S&H!zHFW*a82^R>{+)ATD`%?doDkS_SYk9FE7kqI(GfnAKE&sk3{(z)!eaM z4FGo2}I)y;QjS+o*iMs=-(m@J+9o9ozUcorPtGYo6=>(_iX1sy923 zlzh$Xea##k%gxiPEt(QnH$Jg-_Fa#9FDH+&kWr*QKIKv3;Bge?Zy#lh)C2HoubaN( z=!n+W&70%c&tM-Tu-6|+FtCv6Xlu*X$w`K!Ew*ew`6XQ=cZ-XEpu}ppCOi;;LNQ} zg*FoqN8L8lCeSK}Z+qJ9t<;4V*8gCgRv-F!qzpgSWFpN?=p7@R@Rdf@=9i>;t zJDW~U;8|hoX@($2ySpawE&72>yWREN8LiC_e16i~9~HNX!<~^;3}@_LU$AoZw~TXr zl<@m!mo{qIWzXO!`N3ucwBI4s=HntzYPYX_SN>^}zH_qT9cCXnsm!puA$2gz8sYV?rj8 z;-I#s*(9Eh{os*jr|D|rE+ZRFDKv)CaWAii@BP?pokZ!fr1p&eCXPPI|^$4--;^yQMuLc^qduG`@a) z03l^)%u@WgO01bWnJklt>reG_WXaOES-wm>4daeWlg)c#cF3a6Q%{F98q;^{$+hcO zVWCImI9HlKHFqadv6EQnBe_a}zt1bX-A|vDT6eFJ&rG{1G@7-?=Tq#tmzg=mnLVM* zb5FJ_-+11?$62o42nc`EO*>hJx z(IYgGX>a{eq(*?R!#f-$z>}_t$E5Tm1P#gtCB9yoW8ba-GEm3RN`F&a%_M|SC`As? z#BkV(f30hq=D(HSQH}W4V@bagqAINFAGx9L^)3quv4;CMUgqgkwZFHwyLg=k=C4pG zT_&x()w-lQ-`hmI?F=gY>gxYZxvlRUP;Qg(wljOot0VtSq04wa>u>Ea`^nfr5ih>Y zIq>g~km*4+<_3L}H+VXhpZb~x)2Ph9f1_7lh@mdL5zZvO!!_vLX?!syzth{@-XEvC z5Or)(RkjMOD%%Ohl)yrhKuq4R^G{jLFQj^FIi@UMokazw={ucM`JU5!A=i2^)`ZO9 zvNtT1DL;df+E3BmNM#1-_+ctDc?MrDIG5VnJ;v(JdGq8C-bePhyTSd$?w_em`k8!y zKGM(IJ#r^^D%kA7(NgxO$_#~&ex4Cl(EGz0BR0m}Cay|LwcqkH(`M3wCyA@-eEHMG z&MOCR&|ZNiWh|JFPR^tpW7e7b`wSVDy=?{}W(oLsr?)zAC>{(3&oJ#*%nGc#vq&YUyn{-k&J zfYPgbvyo?RdrwL*MB_U=Q(jWn^7y8}?MAT+^+Sy%Z)?K%phblX`;4owjmg%9-GXf~ zz2QL57vj4@{^7R8Rl~tv-SMp4@mOr7{HzT+djo#q$!1%SLRWN}K;3EkA_%aC1D%2b zSt%>`M-31Rp`BK&?XO#0iA)mvyN&fBB^Ok|AUua@?-jVJBLU+Y+Ng5tfi*7m6wxf7|=12$r zCj{Lq)BNr5+HsZbRg?7PPsi#PZ_neLC0h^(D-$gS&{U`Y*jnLZ5?83IqXtct3^a$J zGMXPQrA>>W+;wXV6rT&)HXF$A6rL!#=)Dxry#^Y$6n;w@AS*^htzv@{aiRi-l%q{| zBA?H}rmt~{5gWBBPA&a+?T+VTUBajxbD~&480X+_rs{zBdqvxi6=i>ZjhM>`yk_Ad0_IU zous&;MeLq9R-=|HFy@+oU?C@0y*1YVR!_Dq%u$Hnw;GLR2&>rDnf=tA)~mhdLhn5#PWU*z*bq?x{qY~lTiJa7?5*{+|vSDQw0 zUuSGFaR^kU+7WWkZGH}Yk?3N>{uEeQXz`Ex=!bnU5#bF~N4;!E?@b5LS21{N!rR~H z_!VOY~UT* zc`t#HHAVn{rRndsx$dMUli9P0nD$ls4y{+^9Oq4Q)`IO=_4%#GGufN6@UF}NE*IdM z@m^NS%%<@i&WgAo&6^&s)%%CrCg+PVjX~zxP{hH${?NZyYeP%wXbchG)%n(=`RSlT zyY<7L^3$OkCxr4e9DSOb(3|{<;t!a<~ljoV*? z$5U2S(!z|~0Ouaj`41~#^Oe7YY1*nWP2YfJjr3#EXK0(j>hX2Uggl5u#(`B#SVd_~ z=Qbus_$*yoV_N+cRA3`+2CRb7RjTuC%XX(54?;)b4n9K;pT~Xc#<(`&vCttq!dg?j7WX!itQNhZK7$3s{9t`ub7Jjo^E0K(HHn<7Qx&wRSfr3a&!r zNRjXkfiB9AW^V*{5Bt%DjhNp9QpsTx-al$Wy*A+;DU*4dfXV7TAgI3&v=iUb4TV;4 z4`c%jn}J!9fhEQjVfq>`R&V)_nOjXJe9uz=?rQ^rc`qMEpa!; z79!5lAUeMyo3hSG85y8`DkJ-gjy>vm@h+AyA5t(A0x0#ESuo0n=)seBF!_J4?^pPQ zduZXzf<`3x*>-yL?Ja@;$*wsat^&o_E<+Ooowxntk2AZhvG#c!gYbxT-*}2a+xW ztfl4@o}qX5UDI3>UxPktkG1F>TT>mbs*1= zV^g+fc;GijpGWO&K6Z3BVw}2FLMK>H5b}$AJ_l2jRC(n>eGtbx`&rWY`{^ne?@K)i> zS>=cA`RMAu%`Mg#Xs;F#3XPFuijPw8VSRP#yF=ehY1cwCX0=B?={KWISYI)u+@;MVYz8E*y~SD8O8xTTu_NQAP=Y~bRgPOI-L){m%o6ct43G6%D6 zbqg|m1H1AqAiMyvD6C#)hfAMV1_b*ps8VQ4dv(iqVZCYnBa2KWYG1yc$u7PnEk|Ev zrhr&9a_lL$&&OyR*-b!f)6Fd@m$9GtM%$Dwd!mEw#ToSF?-qqe&AU-0o0A@=--zNvdh7T0dObT6-d zKv^>gplt{hF?LG_V6Y#IKCGRvr$~A`muG0$Ou1!b?YGR`koik6|MafnVE(+O&;JTz zjXw1^mgQ@{XGybqzDUAr)nBgEZl7Lx&3v+$7PNIAVhW2Nb^7<{`9APVOfA`Lq3$$w zKY{@bhH~};kCw$o*)H5JM}_t87u-#9yT{R)@R4E9NI3wRMvClSX7^#)y60!+1A=`s zG)9Wz!?_n14`bOI0}fIE#AHq_}$R^HZo#kN5U&seBvK`5;}0AnxcmgX_J zBY7RfaKtK*{#**XlSv?0h8?1VbT49{RCG{3v=m01Pm{dcqcdL$q?8RPh1)ts3B8^R&0D7+N5%9sKO10XJCcKY)7 zc|&^xf_*i(_9Zi~CGm2W3Cp4U0u1b-VlwvcJ+=P=uUrKSaS(RpaqwQ`_9*u_$hVNaZd!Np zI)M^saV}ZvoYEmei*p;aNbgy<_oIbov|{08e9%iXy+Z@~t!wOahYt*idQ?j{iWYX# zP{^`spmfJaINaUb`A*MnZa?fZe?&&A(#8q0l|Jafw#~cm+(YYcly@-qkh4NYVIuTX zhNA~tp{`p_kH2%i8gHhtCBwv>f}3a%^_JleZO8$W z0l{lM0hgQb#1q#bQyhy?&KbO-u*tPP*Yw`W|u*$4#-e zfx}^gzukYmf#YVzS|?g_wJz=}d|Y)WL%;=|+t`k88cpHnz|l^CVCmdx6Vo%Gt8)+_ z;BT2v1ET4pb4V>s0tDL!m-kQp=2QD{UljsT9{yv@hw>O=1t8ew^td#sej}whO4jD$ z7j{0{$p{p4;GJFm;|&8kfAq6ws)|G1_}&vurkk)aC!%T8`OdFYT*< z)1Ed8-f_?B@6mMcJc=m(ir%eU(D$@g2KCY`&*5ml$8XKq#S3HJZG$2Sf&xbYg2Q50 zeYA(k<3lW@kSoQsK#jC$@fsJlEzvoQlS-%yWrn=GojYAXMgIJ2BPY*JyZ~fr;R`l4 z%dt9^=NoJ%gy!_3*o#o!rNGW1*{CN$C0&MhuL11Mv|H@fqJ5%(V;#HWK0U*SltTi-KYmB?i64g!0R*oOz=phD zG{0% zFXS&TGI@>j!!=}Qe}QsStfos#7qvcoc27@tAmyw0AWw}&E)ay(1X7D z{55>#PsS1Aqd|^nwP@CuGx2UUW7uRv)q%3Dl$?b@)HtNYZV{+BSQSC`d^rsuzctiU0f z5)U65S~C7h3l5{$$YJn`T5hhEnZp8gz6w4_vLrHD0hu<03jV<2Dd#EzAPFRjT1$&A zHDFGI_{j^@jJB_ouw6kdOXgqtPMOkF$&1pvJd87OaRrCDj;)sz)<}uyi7^W0w|&K% ztV4YLB?IoSDe{~*R12=#`09qn4|%Kzm4JznRr|7_RLV?#Q>)H((L>)w5vDG34qd#4 zl(Q|tH!ZCk6|yK5gAG~P#N=O!Ns=Wn%A0SDuo_c`)7I-SW9h>+?Kxqpxco-#>Fu5E zXXBR|;Ps%S_+g`x@h=iRQd2Sv8%hlJd(na%W$LIA^bCC!8x9yJz9x(yzZHd^Y)V+tuS`st6+N z5l`I6#RWC<(H@ax1o#$w6+cNcerkh{-3~cW^;TQgHGdwvP z`@;^;uy=-c!DJ(l^y@Nu;^mox6_(;9m>K`vLUP>Ln*?WQNAq}KIBlhP|gg> zysvcuBhJVfOTCLht!W&MD+ZOD4Vs=CR(`zj#0PnmfTJmhgesmLM^hgmrH8{jbh%jH zM2W(GjImyMuFzd+=Ct!VKw+%dlU^QAJ`aKP{&-sb7*A~S#Nyr9y|UILwdcXq#v6|! z!vNgSC;UU`E622C3l?`<8P^p@%KZ~hk&vRN50OE~63-7b8Lb>2;*o5x9K!E*3e1c(}MQ8$il zF}CsM{XfY$fk^pqlI9N&&h6Z8TaDyBW)=t>ywS&>l=3pZ?!1=fqRQlgRilnm*O?{o zJu4nL@puVC3R=W9}49wF?5eP3%*Bg;;d>`Uluu zM2j;<_Epg0(cP;(SXB-OMzOmEZ7G^U`M{-=pQBaN(Ow@7yt;~ za*cGj`SGCWNug#46I!@VvrXRR?By}*CYoDDOr^fu_XE+_qx!0woA!IvG(#*y3!jA> zX)-!YPwIlJD+d4Tlu-A?^hm{|WY5RlV0WZz$*FZj4m`?|X ywowd^G`^T7>>mCM5j-t>uHQpVDwg-y{mlz~CeF|Wm#;80p+@=L2{kHo81f%a^EtEt delta 100138 zcmeFad3a6N;{U(*kxjOm4noYLh8Qbqh%q9ZM9gDjc5q0@JP>0NMbTEpt}Zo4(a_RT zV_QmFy|~rV+d-8Uy%eQwT3W4Ezwh^2>yUeIKll0kzR&af{qcL8NAh0p*IIk+HSe|e z*|=O(Yw!HpOItK<{poxCkG)v?&GMB#o4BXis@w%}WqOb7ajWV#9XD3ra%aNsMsrIU z{5+HYSe=|+n**dVjPWVS$-eQK#@jB#C~X+Id!Y|O(|r@NvXLgcgkh9}F9a_ST>-5i zW0>Y;!kcl{9*x2D9Vs~3ukAOPnj?-DuS$JTT}*~0_E98L3x%zP#)YF>8RhMZCHy?c%CK6o7y~O++@RX%o0^| zDr=gU;FAOH94gMnE3J>7;2W2cl|0@z!8?6&22$KKRc@VYsk%0R;)J;kYAat8p2uH6 zI<`qb9YeO|3TPwvr=YBRN?plwa`OOKtW#)u*76M~i@QndQYagFrq+pC2SeG|QBYPt zvc9S=3Y;|w1x;dU@o9s2HcL||o5R;Y=}XXxhVxyCdO1^d5i)#9Q+?@%F*ze8xeX4T zTh=TJ}C!j3KgvM&Xy$@xP`)ECkc-HMi6T_$n-3jG5+6m49_kz|&P!@SX zGg*|J+~)u|Fm5zeCkThEQDtr5}+t+?z|R;Q4<;ik80)4f5b4*{<#@Y z7IYGn1v%4FwIy=#CVD6MPQdd#`=J~<+n{AI*mD;mz+N1U1KE4iy@`n!=tfp@YGT%; zgydO|s+uN2%Oie#e9DxB3EuRH8NR8$HR zs>a76GhsqPdg>~8I|m88$pMVGP^_zdfyI4hjPj5)Vcy%`yO zbwm#+d0|IY<3FG*h(F!OrfSNoomBjbomCeMhBDn*a5nXaTHk@POQs^8ExiQFMQdDV zv_JdeZDh#4+W}?M#YY-OE$DeD4{X#;@$nfMnbT8!hJU>thvOqI?*!>9FD`S_B@r%XWAe}XTKbUpj1bQnUu<~T(M9M6j6 z_)ETA7a%jA3XqUQ7mK2|T;#U_X`7E+{kJs&yTdqx~tJkN=7`#Wx)# z@!h*r`&&pCB**aAJZ+%riglVM6fC1y%{Ofk_}^SoGOTaMf?gU;)$nl z+NDf1%A+965Ici}iPH_^B;uLzG$>o-u=cM(neQg8T}P;{$wuMjtmCyP2N$CiNWek( z6qFg~LD`haP$uMp(L8m^B)^XurB3uQl(Xa=C})i?Jv}A8xi9;Z(du}A3;AoF?#oC? zoa!@z#;TR{A!rUu?5}Al;F4?s*>}@WVJ4Jn4+#(x$u<`{RljZ z(KJzIS6}toWXF>XDZ4G5QZ@S9YKlIA#^DM#~ ztAhCS3>N4iBX_o5MxvdNGIeqqXQ{)Jy~!yFXewXExU7W43C221ys9{C5tN5#XdR_B zT5BsP+ov{^^)IdUXB3+LqSgj;i1St=WiY`*9GL=AIxdR}GNNjKl<9GjR!Rj&;zNoFc`j zny2C$A{|G_i|`zHlQWu6_a-G8-tOq1*r+e;EgthCdFi3B|lj$V~8Mv_=PW z2Gm-thM<75E1rb1fEA!D*r2B|9_u4;9)W7my-QSrR?nyd>Ot95C7>M3qYz&j>W1f- z-waQ!k+0@dDJW0$(^92N5nlyc#RstkqD*9)X8kMyHgs6qHWlo_u?dU9;X(tVSB*}dV(zd}4K^Z}FwKe7T% z$B01yJaKDE;8o>cBlvw!q6;ae@pV1`-sv8&q`;iUr@$f9kO_t$114yX0@42h&Vts{zJf03&q&8B=aj8kEO-pf#W^pe&gGekig~9p_VfA7^g`caDD#>XmmPh7peO$YTSxsz$i8 zMOC6UI4c{V_1aU)pVaD|JQed7OXq(W-dYvu<%ElO__21W^e_wlIkdBR&>BD-FZWwEK zGGDAgk0WEY?jHaw*>WhmEeFaIWF)EWd=>c0@C$aSbRTMMjf}}FKr2G;B0uU4D7(Az zVbzj99a1+^r{Eic&wd*f!W_u$yGJ$Ur%1qk#(u3Ep)9d4BP%l@F~jh}H-T?-#4wsd zuRzN{pLkELO%tIZ@caK}7!O02K$&g?_(M=k$H^JE-|Pa<^R$M_eaUfTR2!fZPS5~a z4%!0x&08wtx1r?ELmNZ0pj^8igYvkT6Nb?W+7!MS)PgpIo;zq5q0rZ%EKoj_$B%(B z{hKGz{;bjVQ)(3*31tQgq0As03AyT4f!2fGIG{3k3(5kng0diKQ0DXbepS#Ioh}Ia zDELors^i~+wuWB~Wq~r^%uyxm4ZxB%))BwFp-T7;ln1;3tqaY8@`S^oY>`gT+R*aQ z=Fs!68^$Bhm!Ujv0hASqfp&q`)BY|B%6zuxAizF)23iN|gR&-_p)61^lqb5jPu2Jk zl<_}YR2k3vT20qyz{9}fp=_~8tu>%5z^%PX--R;W1ZZbyPD2D(vd=LH`#{%2+e71_ z;m~tWsx`%XO*L5@l(Pe?E+6n1A0VFd`&F$Qpj!e@XZn&-o8vCue?R8G_x`p> z72ChO`ERk`{ZSPoAvxZco{*W5kUTLlVN!gizqof6sp?g}snX%$-6UTt4ATGruB|7a zT-R>?qn9PFw`# zdA^1+-6vAHO#P~AJ{`)2OqDl9hH)GT*uehBAcx=?|Ii)PVtcgD$QqxHot1GDoGqA| zkd9{<8Aj3!lop@&epmV6#x$8(zoETsQA`u#>K|%7{2a;>ZoaDySf#c3pQ;7sLd)_5 z-pqJj=lor86321mEH+Ge{A?)GO*Ku)t3cV~EnTL(05pKIVm-k}vqn`*n6hSP02r|f zo*7)z{NFR$8eqyMES}L{<+FUJ^IO%1Ib}+jvL|w(Z28Ri^pvbg@y58Ui4%Fj@C2%I zW+9%Z{~J8ZJKdW#BN6S>(^kGKl=VziH(^GmH@*4949v39D&N*n7UMLOBc}O7l0TaJ zJ^(Wu$K3G21F&hyIPrAsa&f%jEn~_H%0MU&d}^@sQEwn;2W0_%MmpC2i7Kii#>aaT zr=W0^tEvj(!9nwhiQY*WiC#X@HbRk~%`5o$gyxvXDMlR$uqx{k7NSOMs0!6o#{MgN zV#*}$Iuc8Pv!|wc6Ed5pBpcrBgcLSTesxvj^lY_Jnw*jVimKL7Et3Lei;SUSYUK7p zfK59@E1x2zW@Z>gH5H$d=*vP!8X2kHX}mM{PaR)29v|W}ei|S?9crtZ$_E2@67eoP zTckoA)p9;4yX;*k&$kyUzsBfYSCwcZlm|?UPZ-Z8!UIQ{@h~JLUlpPbT#J@r2L5L) z6YHs#Xb2_$9?CB5^{_gw3zVKW1qsQ9aY?7c@j3EgjUO-ppYHe**3uatL^0T8xNONy z)#Qu`DM<)lZ)nO3>t|5zbrwL`W&Y=BN8mBY?p-Bz!Mou%LYZGq;~WK+>jS4lS<)d* zR89O3bCbZ?0{-ht*`}(-`B0`$%}A6j<<;r@m!+Zb9JHS|GiAYhX|JzextWdATeszr zk%(Z^g+n>0d>N_f2}xe#nHGva($HC1b7;O5nO%` zu&ATT7~`8)ZsQ6f*l=HVGUc7{GAMhbLKihOoUW$aD@}kt0^SA6Elnk8Q|R>wQ*L?Q zgOWc7Z3*>3!=T-vSo(77L+f(3{(+3SM>-AV-s%99U9dv?qRyt=i+usD0)7n2CSD6= z!IneW!$V_K%e@ZI7JEsnFFTcArW)^~B0P>45-+?j+c!SPi>7!aRxNP#pvV#VX*o3i2$U)X(uxhFhC<}BF%0Y=|eR>9iQizJ3(Srdv16 zSys18&Vf;Ch^&Lw2F}y^FqG$?2<6b(HAY?1`oLF%Zwuut^r(~7br8$BVJwDc{4}k3Pq7BUAyugOV>yP(67a%9fm}@+&MDw&?j?%N|K1@_K&x5ZFUoTmma1)d*;vaJUFJ3F_coWJK`oGh?oTR$+7&NCA zBHluPO_PX>nbFKNHP*&MIkw{T313P#C|BsAP}aDcF6hrFs4QTXig!af z%}c;bFg&bGUmstdM5Ij9;VV-C7n*=oUD2W7$h`!fH2tig0u zkU}U==wGMQKI;B9%D+$hxiV%ePyE{qb)f%};ooQZcY^)}(!VfvLwe5Mk7ucxwuI*x zD2sxzz$KupslUeljULj-uJzw5@mpKj0uZTIp4usXo2&FAC~N*Elw)8WlwGz!^JFN; z%wtfFnF#HhLfHi&P!?pDuIT&FI`D_IuaIrk%vth7lM2@xZf^0|qpNDZcC!8djfu=>Eoh^Nb$ zQRZ^T>=$jf#8@1P^ObNSVLWa6rsEwEZSHrrjEJ@xV)PGn&SgZ|vk+2A**iO( zyphr7W#`yPv?yjuBr+)}!eY$`bEz|I6w6&OD%x&>N!I;d36h<#(b48sXZq-9w^iLR z`XlD+QmU~^IXil_vxb0nakhS#a z7Gv~cQC@`I4%chO1vo{6BkafFSb`GbunUvr0Bp3AG%m_jr;amuoX2_#(>_Il7ImH9 z#(C_;b@5so4lo^WUWDsrU1#xlk97t6$bQb#GRkxO8qqv@^?+l;lvG)VAMO;qEhzR=@2wqyPQXz*bI+-6_72AY)3}89%=2I0bJ7B->rbw zdvM+5f^C&*Ac5<#9bL#X1Sz zL8d4jfoF9xGzg(yGPD+ zrd5L@1FkQe>Pgq%yE_9P_t;f?_%DAL12M#@SvYtKEDKRm?rL77Q>FV_M_{QP7~!td6R&Y188$icV>t!0 z+Sv)9Y$18!a=p>h8Mn~m`mv|872=C^euVrz*6FawW0&cr)+|#DD1)>1hGi?3lJjRS zTuZU7i5X?@L=Y#&#KQI0^;<7z!(xx!5o;;Sh>H!bRk?5+c(Q`7*LyoNp7hv%=p=>{ zIVi#&(np=m#h$a4!?ks0ACGeVy^pisc1s;J9TpOF1UqRE98QeEz-`iTI1D@-$4)AZPLK^N4ksf|?JSw+TsY>b zr|ThD&N?iS{UYo;a4d|=xv;Zq-~d$?*&g;3xO)Z1mBw3`%iD3>E1c^WW%Wg zQ-dnN@owrG2*bQe$|d@7I9)-^op<1PnCih_;8-NNrr4c_`v)PK$(jxq;q-}%vi2b) zFDCZy49T3i&+j=xRUtr*hR3x-{||_;55UR#$kFf<9E+~ns?A7e>q?J3b)*_1rR3qe z;5s0Q;S}_Vu)l)~hqGjl^%>=lyMR`G0*=E@#TCJggOk@Od(ddTE{O~6u@6}@+PSvc zW1k1*U__7ijBrxd1z6~29DzP^%^l;sy~gAE#~7#dT94ft{W}qH>I&dmIo4UZ*5f`8 z%0{yc^}$ku`+>?{r^z~xoq`8?s-|3aKh^Hlw~m{sUH3i`!lI1eGPOL)cl$2dx%D35^Y=aH`O9$3ORcHb;CLdnKFmUk43&;4KZ0X^Dz3~VwLYi< z#=)ua#I{&_&mB(h8VI8fS2UJpv)4a8W6!s(Iyx-}PmJ)1=U2|6{UYV7<`8f5;TWz}!L)@FM;)T(rFZ`UxTS zOt2G~i+hDcb?Z|~oGOKJlbz_C+2XNZ0gdLdVn-7!=_Ql=D>tjq7Y+-je*$lXWjWP` z%h4gqxqUIP~cXUVJc zB{=q8fP)!m)k){z;$3VKLM#@B4OY)>a7-mPwDvbT&czLj-6#WF8m1Isk!a!E45!JC zzCrJT;)0v|Xp2@YPzB=zd^O&+Jj`2X`!X!EFC}k=8fK~@mEfA<+LP(T?)12S0_5}y zyjK^ux1HTK%Rhiwt_5&ykfwx_cPYa4UY0ZYHIKDt8gJ#2UW>AUua0t`$!*TLl zqY&yMbLY+Ot8lVJ>f(DFmItZpWsA8gLp1>=!gZAy@?!Irc6wd>6Sf;7)tVIhxXM*c z%z4`3?iM?rgK%sSRlC^vhB1{+o&OLl+FM6 z2IiqZb{1^0tS-ZLLaa;9w0euwqb^;DS+HzJx&LzQTI4i&$74q?Rtp98mZ-!_a6RSm z1#2Vhn{aFy71#Pn)fCcM)1Jl`!p;HQx&HdJbLL%-{mznm(--aUdB(r5<~sizTnsXj zt?2sl8Rxen9_!(y?7GgeQT7;wVi_$P%i2OK`}EO#^$6 zyXi80-)yK4?oH=}2Lj4`<%;q#90!Qnpj32JS7K?y&>RETSH^KOvJFmkIxjun!^xW^ zv7?Lmh*P&`p!4dNw)vcM?HD#`*w)QzDfoEgVGR+K<#oHc8s>>UV=lo>OtvMcZdTN+h z+*#}4+KN79aF6mSf;?O|`&xgUd6PU9j&}rVBEAhb^j^x~b^a?D%Rds1U8ybryZmu_ zcEid8h1n6;gTCvXYae+mXFVTNa(rDyNHqmFqYoF5RBQ{SE$Nu^{zc(0Qp-kA&r{*SGl_VAY7@B6J;2bsaA9?)n?msPbPa zaewxBJ8L57U|Gu75n^Ym_H=FXPbc<4H#nZAguEfN7Q(8j^DaVzWx-jv;LZM#!^u1v zPK___FJKY<1lHJ{93g-{M^R!eeg)a9!l%rgIE2U%BV0vEBcmk2gawY#ddvO>i7_%H4r$Aswe; z<5$$cR&iNy>^(!mk@PB&jz}M8YG#vMg2)jER zD~)e3yb2R#2s`J6(&MLi!J6Jwqt#?@6eWTig)vAkKoNLlyC-#cRs_-`czO2*d zN|gN+LTnxRWZwD+ZYUqTxiR7gHR~g|2q)=kl*@h0Iey(^_dJGIw2&AN4M#<|UOwi`80~Ri0UQljO1F3oQ7{h;6 zp=24lf>62)4gb(E;++%8QP$fCsl3{rG>io@_A)|K*(lcWQ~JTSRsSRAN46Frm0y{E z=(4$IAvCdgedJnq5j0aCGxTGBeLhA=mAK0%JPXUP3!y}ruI{J)(madMLRp%cpYd@& zAM(#dXt4~HInDBuWg?U=kG(8IWO1MSV-F#u>f|}YV_E)_2#u4+w)(JU_2x zoBzdKhwF|wwQp#7UCmUBH*946zW3Y?+R1;s>)Le@TLQHC4L{}eaw=SJq>;}# z?6={%(W$S*0>1MvbSzG5xNvz&-X$bzXUkieqi{S>ZvskxugW7!=Z=MoV6J*wgOd;G8+G&oWWY!@o+q)UV#q6_P=Lc<%-1d zQmAduB3)?JzPMuM-?q*EQOvMSkM#kFzS5lc zwX{qBaPOv_sUB|3fK^K;uZ6F}@vL|jFfzifeN%OST(9lnaIJY(c_(izfsJt1 z42`nSBh&*Cs9!5=>B4S_*fOY4>MfPCYLd6$I7G0uOo(t>KO6FkAyYSWCFfM{c6K-@ zn-<$=d>fw($Id9B(*!u?qIP!VFX~EOQhsx@366tHJ*NNZ7xguIqucrs4Ii3VS#TZX zHsTe8B9U4>LHq%Z$Ch;5XRX{Gw#?vgyRwF7B={f?tl3VXE>b9OqRRq*$HOaU_LEWeFof6$80Txd z5;ud<-~66}1S5Yz;=@rwoV}!F2A<44O5O8TYUi%rELlMMcYa^j(zNM zUc0w5u+Qo=>IA zHG_@P>SXe^&eglLs2+kNmV&apSf}tr`W0--)|4|kNIq+fg5x3_DEm4Kj-|(Y zRCsEzNylL=!&_CK!O3|gSCJCskRej4HlGdGU+&Yzs}0PS?i27FLApc+zH7m~VEOXM zU5(2K1lh_ZUJ^+eKbV>~44&f8;&)KHMO<8vI() z9_=>eqN?0cxM-ORFNJj~n))l@u)+vC0gk6vtMrR-y>u>J1MxRC`u-@)IxX>u05Qa1JG5Yve?=LU6@oE%>b&eS_fd6NS4QH6J#30)c2Z85bTEt^~CQN zxFOQ<4TIiQOnGxs!Abi75BTAD*$R^1PhEs#XW6pG2@DVpOX<6l}_+61S81?kE!Oe%vfLR$Zk$496Z;m+(ibsZry<`UJ?!d@3l9 zFC$ljm*7|iQ+`kIHJq9kod2QK)p_O0;~HIEoN0;4SOCgF>d&>j%=KGPj>1y%{Udjc z8p`^|cUj)9*-JrrVbX1V3RYhEIF4NvYKq0J&>{V5sEC?qaMOkn@rHKtr9%4- z97mw3R^)cIR7Eq-_#IX11HBWt~Pj12gkz7_X0%!c4mO}h_po?-(S3AYOAhN z-=jVS$99s3*eBsQ)A8LbN>!td%G{8%GXsue9}at%58zlvxxSjEMMwv;s#xF3Y-x?G zi(w+4^t_4?bJOd_9axSSd;^8+R`U?Oh^luCM!?FnauwbLCtE#`sWXe-#Xxkvi1G-$vcj(Na1)9 zmq%DRjFZn<-q74oOGOc^TKl;4H)x=Wq8=WMf#Yn!-TL3V2EuS!snPs999QrPYV%vB zk!i%k%I%bpp;KztybNM741EL&LhyZbyWhvEH+#kYvcH!I#L{oq&&{ocVUSPpCTF#3DA z!T0jBqnhh6FTX6d^I%!rK-rqs0oa!Eo6;KyvAU(@mtR9#pm!vH4peGp}Rg-|Cs9c#2!gF#LF@o+bCLsE|-C^ z+Nt4Tt%vRHliGBJy2Ay^_NmZb4=i={=?~jQK15%F5LZX_T>B^- z`&~VI4CvsW$=qy2!pZUMTzD5x_u+V)UXJ&|a%-;6-Ls=Q8}7L9y!%-=eMj*Tf_jwU zt}U>WX|%g{&@XT!{LUKKnb-AgysqOfGU=57Gw)be@%kY2<)e|Nkt+@iGVxMaq=+31 zRJWUHOcQ+un^BfPFhvI4C8JDv$M1i#RoV%g9UcIfr{ZrRI1i`2ACK>kt?AuOW4uam z7Qu1wCBeXVl;*yG2h^ zer2q37!TLyUVg8_sVgT}>wm&=BC0RFyTz(v>3P2twwqimK0-(>dt59k_EMcH?=h?x zIQ2esE<*PTXPt)YE2mt;-f9Wb#eus&tAqQP^5L{vn^WQXqB!bX{DW}!cTo1vupHp( z(%Yf0n#XuyI2tbu!*!M8`vZiSN=^e;#eQP(7}FyvjKeN~6HyL(>xF(S8{cIqLP*st zuQ%@c`-`n(vCJp-SJPHKrr8I_Nut)_n{fBbKV*R3F9~-|e5nklI)rP~CAj+?89K1| zaS8w8&cpFCDQ}GI&_TtIn*zrLT(w>yoV*uPm$r+r_m_aKgNyaF`LxKNh~e}lAR9zo zkn0UmZ7SbXGKY&DlaS;hpntm^VKpDh#^JlXGZDI10qavZj~os)A1gj4AA?hOLcE`U z9PVC;TyH-new%~_{TcLLC0yO(#Nv3+y>V)>Eal{-M%bl>snVC?MZq2ncfU+~;2sm_ z8ew%9uEwu=pce^uZ$od-fRkGaE<^SvhEKtEH*chxDS>(- zwwI4^E{-ydbfi^#k-?+Ywne!uaJ)tY$nAQSG5!IIJ6dZ3Tz@`#w@)H80IB5Depkp? zu`&tuojg|EWvI80_QUmOPO2+yuPUJ2kJ}^QIOgPvY700nqw0y)2{?{fyn%?TNZE0! zN6X&-wwQ09^Z@4SZ8&*n@lqxnXT9ZMnA^Lwv*lMYMQ|KaGS1awy!b5@Wz8I~N@vIi zW%j$U%pgG7+pua-@eZle1U-qwju7m8W@(GJ`*0aO0w+hT-0}Yjr!F|$R(14=4jEX< zH~LU_btiTmLAiTZC#pHopPpZe#A%1CeotIy;PA{aF3SD@A-0dauDSyz{Z*&72UUAy zE|wW^;cD;r5`sKfJ&(EoHt{ z+5X3q^4)f82WSWN@Ziu)+{}C{J^wP5-5^CxD!CR~kHN{;zg(+Q#PL}eHrI4K-c~vu z;i{P`hR+6_k*Y4Kc=zFp2>UEt8&yL*Aq`1W%~@KvLV$b}y%>}$sk|d|pM>MSDL|*e z2JP{7cDZylW7Okw>law{`-;|up-_BOb# zNF|%wz5%DM3*1U}p5{-9j&VYfED}jiVr%*M z{ooe}4plU4E(Vqg<{>y*1;0X2Cus9HW}l*q5FDt2U)-mU%)`u<)HQRSn7afed<{sg z*&HU{!FhFabv5UU;m?@ea7|q@t(fr?~RMhSrkt7-dp1M&#$Ol(P_h zB-3FPk{>G1g9l_e5+Godzz?p2@bvu6e`EObZ@w;Uzr7Z7W?TahE7N_9AL^(0;pbETP`M9OMxUv8gIXRxm$moBhsvviNvM@4C;`urPzp+KLz%9ePFGyXD}nQT zqpIix{~Kk}syaQDC#<1;ab=%BOfJqnYa*ez@vK>=F+n4pn#y7l5;f7>6_ zx&`C3GWdv2)>3PjjxVk(R2y&}-%iK>l`<+Ezo_kXx?-9mm#zpzur|?9X533_KPdhf zxJi^BDo=NM40&HqXnRZ7SIg}RIqqSgU?`O)kE zzM;MMD~H*Z)rV18YPa@O`XKF#D~nr2b1KtS*PhCJYia*qG)Fc;9VBFib+v|Qt*0|6 zu0-{9d;=X{T!|WKUR*hFnt`*REulPLm`l&qFaU0>IzsWs;Qu?q&tEAI?4r|kg|enm zIz5%~-LVxMe_g^74b};$rZ{&H9rgP`lmGY|Hf?0kVLAD&r?<#eZU>nuq_J4L`+|XtL&irEHZX9ZzL21;1F?46W0k zY=yZ{rk@Yx=f2|n-0iK>5&xg7oVEX#1z=OIM!{L*^|}Ior5u=>5Kr9-Wzv^*`Wyxr z-mdjkC^OyxWyZT1sg-<>_EZMS^Wxe7@xOwzLVrNZLQ7*nSR8-lWdQ%?5|jyoIa0JTuj=sB znmWENlr;^}>8K3W$1fJ7iT2G2@u4!`Fdg4c$9I6X<@irUfYWUnlo|7X+Te#uKV5q& zGnx%$U(SUxYQENmP{uz6Wr3GyU8;2%l=(SOeyBMt@$(4qs#5@E(`<(_qn%J@v8|hfE*L8X-`5RE?b3n(xt>d9;D|J*SJO*V;oYejllo@^s#UJByt!JSu;CU$1 ze*@(SuIl*f+J6V-@jq$)Gn5tn9m<0JQ33%&oOnm?DJ^755~%edt>v`3wN{4myfvUa zZ!IYEs}1FcN?!-c{OW1{u-5ueeyDQD1n7mZiH@K$gQi-WX-;LZrPkJ(|KBJN4aYB5 zphJLKh!IdH?x?ks*3MeHKv|yb#JJ-VQay>;i0*7~0QYTA9t8@I;63i^<>9 z@lM(erveNyDm z73VgXRYMRm9>y=`(@<+;M#DFyidrvVHsOp$8yy|4qdRErq&fcLjyx<<`|jF%wC}04 zHkRmG!gw8#s1qh@o~C_<)+{L7ZK{r+4rM;Gb$pK2 zJRLtz>l09Z?rWv{fF)dn1SQ3qjo5U(yb-%&{;I|^E!8va5oQ}+8NosP=mHe2{7#CU>29U)b8-h^_Iynl^NWE^0=QhFRtXjfb+Otbv%{%{t4yr zE*PpMFW3w)Rx2|osXdjxl-5Aasm$OZt>rW?t~{>1=KquC{8a>x3BoUK^lC#{le#)1 zDt$fesqC_bP@b@nj&H2vspL(xr!svD<#S|!t@J1WYt$CX1KOzsQpr1LPi5amYX4Wt z^xbtlmHGA1p2`Q21Efd)Gr$@R(g~Hr=v2zJgsxJKCa`bEcblP7ieBwiJsD&%JfU1?15!a zHsteAmS=TIJsS~_pW@027l5-s8+1IC{sk!G3pFpUjNhU;m3}Lf1$kNX`-~SC*73!a>3#t(A(CFg zkYf3M*U5@2%P-HRmFZkOw^n9T0-hS6IhEehzPPfz0(HEtqQ$^$BBPG!b! z?f*&{Us1;wR~EdoK0XM_hxqlO?5M`2Fr*l0p%0|;fR<2Z7^Zn~W%{<77grXzz2;Q5 zU}q@v>7x06XbvKH6V^*7>Ar?55+XJaG@LF`83zf)FtZ0iI|Klo^lJ35shq@af=e zk=Z()%D)n@M0+Y{hoe1}d*jX8Q`rTtK$&h=Am%?$xEp{4*b8MzUx)HU2ce9A3(8sY zK9n`&|DVltpF;Ve@D(QGC^Q{79R&`2atz!>73_xw96Bbuy z6sq}ODNoP@@ziEoTR@o~|5fT{o@ZaJ{&(( z|LZY1{s5JI8>tg?(;5Zk=dYCK>VqF<*cU(iQ0e)43_nyh`9Kc-$yFcuj`8kO!~HJa|p!!D}+O zx#xA|!D})PUXxK*hzGC9@ZwMf_a_ftlQH;;2%F=m+SyE&uWU%>RP3MgHS884+^Y%