diff --git a/app2/.babelrc b/app2/.babelrc new file mode 100644 index 000000000..b56ad8dc6 --- /dev/null +++ b/app2/.babelrc @@ -0,0 +1,4 @@ +{ + "presets": ["next/babel"], + "plugins": [] +} \ No newline at end of file diff --git a/app2/.eslintrc.json b/app2/.eslintrc.json new file mode 100755 index 000000000..3af52d700 --- /dev/null +++ b/app2/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": ["next/babel"] +} diff --git a/app2/.gitignore b/app2/.gitignore new file mode 100755 index 000000000..737d87210 --- /dev/null +++ b/app2/.gitignore @@ -0,0 +1,35 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo diff --git a/app2/.nvmrc b/app2/.nvmrc new file mode 100644 index 000000000..0ff38047b --- /dev/null +++ b/app2/.nvmrc @@ -0,0 +1 @@ +16.16.0 \ No newline at end of file diff --git a/app2/README.md b/app2/README.md new file mode 100755 index 000000000..c87e0421d --- /dev/null +++ b/app2/README.md @@ -0,0 +1,34 @@ +This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). + +## Getting Started + +First, run the development server: + +```bash +npm run dev +# or +yarn dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file. + +[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`. + +The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! + +## Deploy on Vercel + +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. diff --git a/app2/next-env.d.ts b/app2/next-env.d.ts new file mode 100755 index 000000000..4f11a03dc --- /dev/null +++ b/app2/next-env.d.ts @@ -0,0 +1,5 @@ +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/app2/next.config.js b/app2/next.config.js new file mode 100755 index 000000000..ae887958d --- /dev/null +++ b/app2/next.config.js @@ -0,0 +1,7 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + reactStrictMode: true, + swcMinify: true, +} + +module.exports = nextConfig diff --git a/app2/package-lock.json b/app2/package-lock.json new file mode 100644 index 000000000..4c0b1a706 --- /dev/null +++ b/app2/package-lock.json @@ -0,0 +1,9310 @@ +{ + "name": "app2", + "version": "0.1.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "app2", + "version": "0.1.0", + "dependencies": { + "@emotion/react": "^11.9.3", + "@reduxjs/toolkit": "^1.8.3", + "@types/react-redux": "^7.1.24", + "next": "12.2.2", + "react": "18.2.0", + "react-dom": "18.2.0", + "react-redux": "^8.0.2", + "redux": "^4.2.0", + "redux-flash": "^2.0.2" + }, + "devDependencies": { + "@babel/core": "^7.18.9", + "@babel/preset-env": "^7.18.9", + "@types/node": "18.0.6", + "@types/react": "18.0.15", + "@types/react-dom": "18.0.6", + "eslint": "8.20.0", + "eslint-config-next": "12.2.2", + "typescript": "4.7.4" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.8.tgz", + "integrity": "sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.9.tgz", + "integrity": "sha512-1LIb1eL8APMy91/IMW+31ckrfBM4yCoLaVzoDhZUKSM4cu1L1nIidyxkCgzPAgrC5WEz36IPEr/eSeSF9pIn+g==", + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.18.9", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-module-transforms": "^7.18.9", + "@babel/helpers": "^7.18.9", + "@babel/parser": "^7.18.9", + "@babel/template": "^7.18.6", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.9.tgz", + "integrity": "sha512-wt5Naw6lJrL1/SGkipMiFxJjtyczUWTP38deiP1PO60HsBjDeKk08CGC3S8iVuvf0FmTdgKwU1KIXzSKL1G0Ug==", + "dependencies": { + "@babel/types": "^7.18.9", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", + "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz", + "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==", + "dev": true, + "dependencies": { + "@babel/helper-explode-assignable-expression": "^7.18.6", + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz", + "integrity": "sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg==", + "dependencies": { + "@babel/compat-data": "^7.18.8", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.20.2", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.18.9.tgz", + "integrity": "sha512-WvypNAYaVh23QcjpMR24CwZY2Nz6hqdOcFdPbNpV56hL5H6KiFheO7Xm1aPdlLQ7d5emYZX7VZwPp9x3z+2opw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.9", + "@babel/helper-split-export-declaration": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.18.6.tgz", + "integrity": "sha512-7LcpH1wnQLGrI+4v+nPp+zUvIkF9x0ddv1Hkdue10tg3gmRnLy97DXh4STiOf1qeIInyD69Qv5kKSZzKD8B/7A==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "regexpu-core": "^5.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz", + "integrity": "sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.13.0", + "@babel/helper-module-imports": "^7.12.13", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/traverse": "^7.13.0", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0-0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-explode-assignable-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz", + "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.18.9.tgz", + "integrity": "sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A==", + "dependencies": { + "@babel/template": "^7.18.6", + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz", + "integrity": "sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.9.tgz", + "integrity": "sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.18.6", + "@babel/template": "^7.18.6", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", + "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz", + "integrity": "sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", + "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-wrap-function": "^7.18.9", + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.18.9.tgz", + "integrity": "sha512-dNsWibVI4lNT6HiuOIBr1oyxo40HvIVmbwPUm3XZ7wMh4k2WxrxTqZwSqw/eEmXDS9np0ey5M2bz9tBmO9c+YQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", + "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.9.tgz", + "integrity": "sha512-imytd2gHi3cJPsybLRbmFrF7u5BIEuI2cNheyKi3/iOBC63kNn3q8Crn2xVuESli0aM4KYsyEqKyS7lFL8YVtw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", + "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", + "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.18.9.tgz", + "integrity": "sha512-cG2ru3TRAL6a60tfQflpEfs4ldiPwF6YW3zfJiRgmoFVIaC1vGnBBgatfec+ZUziPHkHSaXAuEck3Cdkf3eRpQ==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.18.9", + "@babel/template": "^7.18.6", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.9.tgz", + "integrity": "sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ==", + "dependencies": { + "@babel/template": "^7.18.6", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.9.tgz", + "integrity": "sha512-9uJveS9eY9DJ0t64YbIBZICtJy8a5QrDEVdiLCG97fVLpDTpGX7t8mMSb6OWw6Lrnjqj4O8zwjELX3dhoMgiBg==", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz", + "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz", + "integrity": "sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@babel/plugin-proposal-optional-chaining": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-proposal-async-generator-functions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.18.6.tgz", + "integrity": "sha512-WAz4R9bvozx4qwf74M+sfqPMKfSqwM0phxPTR6iJIi8robgzXwkEgmeJG1gEKhm6sDqT/U9aV3lfcqybIpev8w==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-remap-async-to-generator": "^7.18.6", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-class-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-class-static-block": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.6.tgz", + "integrity": "sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-proposal-dynamic-import": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", + "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-export-namespace-from": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", + "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-json-strings": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz", + "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz", + "integrity": "sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-numeric-separator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", + "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-object-rest-spread": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.18.9.tgz", + "integrity": "sha512-kDDHQ5rflIeY5xl69CEqGEZ0KY369ehsCIEbTGb4siHG5BE9sga/T0r0OUwyZNLMmZE79E1kbsqAjwFCW4ds6Q==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.18.8", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.18.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-catch-binding": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", + "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-chaining": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz", + "integrity": "sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-methods": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.18.6.tgz", + "integrity": "sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-unicode-property-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", + "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.18.6.tgz", + "integrity": "sha512-/DU3RXad9+bZwrgWJQKbr39gYbJpLJHezqEzRzi/BHRlJ9zsQb4CK2CA/5apllXNomwA1qHwzvHl+AdEmC5krQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", + "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz", + "integrity": "sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz", + "integrity": "sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-remap-async-to-generator": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz", + "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.18.9.tgz", + "integrity": "sha512-5sDIJRV1KtQVEbt/EIBwGy4T01uYIo4KRB3VUqzkhrAIOGx7AoctL9+Ux88btY0zXdDyPJ9mW+bg+v+XEkGmtw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.18.9.tgz", + "integrity": "sha512-EkRQxsxoytpTlKJmSPYrsOMjCILacAjtSVkd4gChEe2kXjFCun3yohhW5I7plXJhCemM0gKsaGMcO8tinvCA5g==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-replace-supers": "^7.18.9", + "@babel/helper-split-export-declaration": "^7.18.6", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-classes/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz", + "integrity": "sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.18.9.tgz", + "integrity": "sha512-p5VCYNddPLkZTq4XymQIaIfZNJwT9YsjkPOhkVEqt6QIpQFZVM9IltqqYpOEkJoN1DPznmxUDyZ5CTZs/ZCuHA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz", + "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", + "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz", + "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==", + "dev": true, + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz", + "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", + "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", + "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz", + "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.18.6.tgz", + "integrity": "sha512-Pra5aXsmTsOnjM3IajS8rTaLCy++nGM4v3YR4esk5PCsyg9z8NA5oQLwxzMUtDBd8F+UmVza3VxoAaWCbzH1rg==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "babel-plugin-dynamic-import-node": "^2.3.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.18.6.tgz", + "integrity": "sha512-Qfv2ZOWikpvmedXQJDSbxNqy7Xr/j2Y8/KfijM0iJyKkBTmWuvCA1yeH1yDM7NJhBW/2aXxeucLj6i80/LAJ/Q==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-simple-access": "^7.18.6", + "babel-plugin-dynamic-import-node": "^2.3.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.18.9.tgz", + "integrity": "sha512-zY/VSIbbqtoRoJKo2cDTewL364jSlZGvn0LKOf9ntbfxOvjfmyrdtEEOAdswOswhZEb8UH3jDkCKHd1sPgsS0A==", + "dev": true, + "dependencies": { + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-module-transforms": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-validator-identifier": "^7.18.6", + "babel-plugin-dynamic-import-node": "^2.3.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz", + "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.18.6.tgz", + "integrity": "sha512-UmEOGF8XgaIqD74bC8g7iV3RYj8lMf0Bw7NJzvnS9qQhM4mg+1WHKotUIdjxgD2RGrgFLZZPCFPFj3P/kVDYhg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz", + "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", + "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.18.8.tgz", + "integrity": "sha512-ivfbE3X2Ss+Fj8nnXvKJS6sjRG4gzwPMsP+taZC+ZzEGjAYlvENixmt1sZ5Ca6tWls+BlKSGKPJ6OOXvXCbkFg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz", + "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz", + "integrity": "sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "regenerator-transform": "^0.15.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz", + "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", + "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.18.9.tgz", + "integrity": "sha512-39Q814wyoOPtIB/qGopNIL9xDChOE1pNU0ZY5dO0owhiVt/5kFm4li+/bBtwc7QotG0u5EPzqhZdjMtmqBqyQA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz", + "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", + "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", + "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.6.tgz", + "integrity": "sha512-XNRwQUXYMP7VLuy54cr/KS/WeL3AZeORhrmeZ7iewgu+X2eBqmpaLI/hzqr9ZxCeUoq0ASK4GUzSM0BDhZkLFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz", + "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.18.9.tgz", + "integrity": "sha512-75pt/q95cMIHWssYtyfjVlvI+QEZQThQbKvR9xH+F/Agtw/s4Wfc2V9Bwd/P39VtixB7oWxGdH4GteTTwYJWMg==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.18.8", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-async-generator-functions": "^7.18.6", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-class-static-block": "^7.18.6", + "@babel/plugin-proposal-dynamic-import": "^7.18.6", + "@babel/plugin-proposal-export-namespace-from": "^7.18.9", + "@babel/plugin-proposal-json-strings": "^7.18.6", + "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", + "@babel/plugin-proposal-numeric-separator": "^7.18.6", + "@babel/plugin-proposal-object-rest-spread": "^7.18.9", + "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", + "@babel/plugin-proposal-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "@babel/plugin-proposal-private-property-in-object": "^7.18.6", + "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.18.6", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-transform-arrow-functions": "^7.18.6", + "@babel/plugin-transform-async-to-generator": "^7.18.6", + "@babel/plugin-transform-block-scoped-functions": "^7.18.6", + "@babel/plugin-transform-block-scoping": "^7.18.9", + "@babel/plugin-transform-classes": "^7.18.9", + "@babel/plugin-transform-computed-properties": "^7.18.9", + "@babel/plugin-transform-destructuring": "^7.18.9", + "@babel/plugin-transform-dotall-regex": "^7.18.6", + "@babel/plugin-transform-duplicate-keys": "^7.18.9", + "@babel/plugin-transform-exponentiation-operator": "^7.18.6", + "@babel/plugin-transform-for-of": "^7.18.8", + "@babel/plugin-transform-function-name": "^7.18.9", + "@babel/plugin-transform-literals": "^7.18.9", + "@babel/plugin-transform-member-expression-literals": "^7.18.6", + "@babel/plugin-transform-modules-amd": "^7.18.6", + "@babel/plugin-transform-modules-commonjs": "^7.18.6", + "@babel/plugin-transform-modules-systemjs": "^7.18.9", + "@babel/plugin-transform-modules-umd": "^7.18.6", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.18.6", + "@babel/plugin-transform-new-target": "^7.18.6", + "@babel/plugin-transform-object-super": "^7.18.6", + "@babel/plugin-transform-parameters": "^7.18.8", + "@babel/plugin-transform-property-literals": "^7.18.6", + "@babel/plugin-transform-regenerator": "^7.18.6", + "@babel/plugin-transform-reserved-words": "^7.18.6", + "@babel/plugin-transform-shorthand-properties": "^7.18.6", + "@babel/plugin-transform-spread": "^7.18.9", + "@babel/plugin-transform-sticky-regex": "^7.18.6", + "@babel/plugin-transform-template-literals": "^7.18.9", + "@babel/plugin-transform-typeof-symbol": "^7.18.9", + "@babel/plugin-transform-unicode-escapes": "^7.18.6", + "@babel/plugin-transform-unicode-regex": "^7.18.6", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.18.9", + "babel-plugin-polyfill-corejs2": "^0.3.1", + "babel-plugin-polyfill-corejs3": "^0.5.2", + "babel-plugin-polyfill-regenerator": "^0.3.1", + "core-js-compat": "^3.22.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", + "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.6.tgz", + "integrity": "sha512-t9wi7/AW6XtKahAe20Yw0/mMljKq0B1r2fPdvaAdV/KPDZewFXdaaa6K7lxmZBZ8FBNpCiAT6iHPmd6QO9bKfQ==", + "dependencies": { + "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime-corejs3": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.18.6.tgz", + "integrity": "sha512-cOu5wH2JFBgMjje+a+fz2JNIWU4GzYpl05oSob3UDvBEh6EuIn+TXFHMmBbhSb+k/4HMzgKCQfEEDArAWNF9Cw==", + "dev": true, + "dependencies": { + "core-js-pure": "^3.20.2", + "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.6.tgz", + "integrity": "sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw==", + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.6", + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.9.tgz", + "integrity": "sha512-LcPAnujXGwBgv3/WHv01pHtb2tihcyW1XuL9wd7jqh1Z8AQkTd+QVjMrMijrln0T7ED3UXLIy36P9Ao7W75rYg==", + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.18.9", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.18.9", + "@babel/types": "^7.18.9", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/types": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.9.tgz", + "integrity": "sha512-WwMLAg2MvJmt/rKEVQBBhIVffMmnilX4oe0sRe7iPOHIGsqpruFHHdrfj4O1CMMtgMtCU4oPafZjDPCRgO57Wg==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@emotion/babel-plugin": { + "version": "11.9.2", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.9.2.tgz", + "integrity": "sha512-Pr/7HGH6H6yKgnVFNEj2MVlreu3ADqftqjqwUvDy/OJzKFgxKeTQ+eeUf20FOTuHVkDON2iNa25rAXVYtWJCjw==", + "dependencies": { + "@babel/helper-module-imports": "^7.12.13", + "@babel/plugin-syntax-jsx": "^7.12.13", + "@babel/runtime": "^7.13.10", + "@emotion/hash": "^0.8.0", + "@emotion/memoize": "^0.7.5", + "@emotion/serialize": "^1.0.2", + "babel-plugin-macros": "^2.6.1", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.0.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@emotion/cache": { + "version": "11.9.3", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.9.3.tgz", + "integrity": "sha512-0dgkI/JKlCXa+lEXviaMtGBL0ynpx4osh7rjOXE71q9bIF8G+XhJgvi+wDu0B0IdCVx37BffiwXlN9I3UuzFvg==", + "dependencies": { + "@emotion/memoize": "^0.7.4", + "@emotion/sheet": "^1.1.1", + "@emotion/utils": "^1.0.0", + "@emotion/weak-memoize": "^0.2.5", + "stylis": "4.0.13" + } + }, + "node_modules/@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" + }, + "node_modules/@emotion/memoize": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.5.tgz", + "integrity": "sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ==" + }, + "node_modules/@emotion/react": { + "version": "11.9.3", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.9.3.tgz", + "integrity": "sha512-g9Q1GcTOlzOEjqwuLF/Zd9LC+4FljjPjDfxSM7KmEakm+hsHXk+bYZ2q+/hTJzr0OUNkujo72pXLQvXj6H+GJQ==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@emotion/babel-plugin": "^11.7.1", + "@emotion/cache": "^11.9.3", + "@emotion/serialize": "^1.0.4", + "@emotion/utils": "^1.1.0", + "@emotion/weak-memoize": "^0.2.5", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.0.4.tgz", + "integrity": "sha512-1JHamSpH8PIfFwAMryO2bNka+y8+KA5yga5Ocf2d7ZEiJjb7xlLW7aknBGZqJLajuLOvJ+72vN+IBSwPlXD1Pg==", + "dependencies": { + "@emotion/hash": "^0.8.0", + "@emotion/memoize": "^0.7.4", + "@emotion/unitless": "^0.7.5", + "@emotion/utils": "^1.0.0", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.1.1.tgz", + "integrity": "sha512-J3YPccVRMiTZxYAY0IOq3kd+hUP8idY8Kz6B/Cyo+JuXq52Ek+zbPbSQUrVQp95aJ+lsAW7DPL1P2Z+U1jGkKA==" + }, + "node_modules/@emotion/unitless": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", + "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" + }, + "node_modules/@emotion/utils": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.1.0.tgz", + "integrity": "sha512-iRLa/Y4Rs5H/f2nimczYmS5kFJEbpiVvgN3XVfZ022IYhuNA1IRSHEizcof88LtCTXtl9S2Cxt32KgaXEu72JQ==" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz", + "integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==" + }, + "node_modules/@eslint/eslintrc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", + "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.3.2", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.14", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", + "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@next/env": { + "version": "12.2.2", + "resolved": "https://registry.npmjs.org/@next/env/-/env-12.2.2.tgz", + "integrity": "sha512-BqDwE4gDl1F608TpnNxZqrCn6g48MBjvmWFEmeX5wEXDXh3IkAOw6ASKUgjT8H4OUePYFqghDFUss5ZhnbOUjw==" + }, + "node_modules/@next/eslint-plugin-next": { + "version": "12.2.2", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-12.2.2.tgz", + "integrity": "sha512-XOi0WzJhGH3Lk51SkSu9eZxF+IY1ZZhWcJTIGBycAbWU877IQa6+6KxMATWCOs7c+bmp6Sd8KywXJaDRxzu0JA==", + "dev": true, + "dependencies": { + "glob": "7.1.7" + } + }, + "node_modules/@next/eslint-plugin-next/node_modules/glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@next/swc-android-arm-eabi": { + "version": "12.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.2.2.tgz", + "integrity": "sha512-VHjuCHeq9qCprUZbsRxxM/VqSW8MmsUtqB5nEpGEgUNnQi/BTm/2aK8tl7R4D0twGKRh6g1AAeFuWtXzk9Z/vQ==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-android-arm64": { + "version": "12.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.2.2.tgz", + "integrity": "sha512-v5EYzXUOSv0r9mO/2PX6mOcF53k8ndlu9yeFHVAWW1Dhw2jaJcvTRcCAwYYN8Q3tDg0nH3NbEltJDLKmcJOuVA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "12.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.2.2.tgz", + "integrity": "sha512-JCoGySHKGt+YBk7xRTFGx1QjrnCcwYxIo3yGepcOq64MoiocTM3yllQWeOAJU2/k9MH0+B5E9WUSme4rOCBbpA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "12.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.2.2.tgz", + "integrity": "sha512-dztDtvfkhUqiqpXvrWVccfGhLe44yQ5tQ7B4tBfnsOR6vxzI9DNPHTlEOgRN9qDqTAcFyPxvg86mn4l8bB9Jcw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-freebsd-x64": { + "version": "12.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-12.2.2.tgz", + "integrity": "sha512-JUnXB+2xfxqsAvhFLPJpU1NeyDsvJrKoOjpV7g3Dxbno2Riu4tDKn3kKF886yleAuD/1qNTUCpqubTvbbT2VoA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm-gnueabihf": { + "version": "12.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.2.2.tgz", + "integrity": "sha512-XeYC/qqPLz58R4pjkb+x8sUUxuGLnx9QruC7/IGkK68yW4G17PHwKI/1njFYVfXTXUukpWjcfBuauWwxp9ke7Q==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "12.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.2.2.tgz", + "integrity": "sha512-d6jT8xgfKYFkzR7J0OHo2D+kFvY/6W8qEo6/hmdrTt6AKAqxs//rbbcdoyn3YQq1x6FVUUd39zzpezZntg9Naw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "12.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.2.2.tgz", + "integrity": "sha512-rIZRFxI9N/502auJT1i7coas0HTHUM+HaXMyJiCpnY8Rimbo0495ir24tzzHo3nQqJwcflcPTwEh/DV17sdv9A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "12.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.2.2.tgz", + "integrity": "sha512-ir1vNadlUDj7eQk15AvfhG5BjVizuCHks9uZwBfUgT5jyeDCeRvaDCo1+Q6+0CLOAnYDR/nqSCvBgzG2UdFh9A==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "12.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.2.2.tgz", + "integrity": "sha512-bte5n2GzLN3O8JdSFYWZzMgEgDHZmRz5wiispiiDssj4ik3l8E7wq/czNi8RmIF+ioj2sYVokUNa/ekLzrESWw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "12.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.2.2.tgz", + "integrity": "sha512-ZUGCmcDmdPVSAlwJ/aD+1F9lYW8vttseiv4n2+VCDv5JloxiX9aY32kYZaJJO7hmTLNrprvXkb4OvNuHdN22Jg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-ia32-msvc": { + "version": "12.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.2.2.tgz", + "integrity": "sha512-v7ykeEDbr9eXiblGSZiEYYkWoig6sRhAbLKHUHQtk8vEWWVEqeXFcxmw6LRrKu5rCN1DY357UlYWToCGPQPCRA==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "12.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.2.2.tgz", + "integrity": "sha512-2D2iinWUL6xx8D9LYVZ5qi7FP6uLAoWymt8m8aaG2Ld/Ka8/k723fJfiklfuAcwOxfufPJI+nRbT5VcgHGzHAQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@reduxjs/toolkit": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.8.3.tgz", + "integrity": "sha512-lU/LDIfORmjBbyDLaqFN2JB9YmAT1BElET9y0ZszwhSBa5Ef3t6o5CrHupw5J1iOXwd+o92QfQZ8OJpwXvsssg==", + "dependencies": { + "immer": "^9.0.7", + "redux": "^4.1.2", + "redux-thunk": "^2.4.1", + "reselect": "^4.1.5" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18", + "react-redux": "^7.2.1 || ^8.0.2" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, + "node_modules/@rushstack/eslint-patch": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.1.4.tgz", + "integrity": "sha512-LwzQKA4vzIct1zNZzBmRKI9QuNpLgTQMEjsQLf3BXuGYb3QPTP4Yjf6mkdX+X1mYttZ808QpOwAzZjv28kq7DA==", + "dev": true + }, + "node_modules/@swc/helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.2.tgz", + "integrity": "sha512-556Az0VX7WR6UdoTn4htt/l3zPQ7bsQWK+HqdG4swV7beUCxo/BqmvbOpUkTIm/9ih86LIf1qsUnywNL3obGHw==", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/hoist-non-react-statics": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "dependencies": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "node_modules/@types/node": { + "version": "18.0.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.6.tgz", + "integrity": "sha512-/xUq6H2aQm261exT6iZTMifUySEt4GR5KX8eYyY+C4MSNPqSh9oNIP7tz2GLKTlFaiBbgZNxffoR3CVRG+cljw==", + "dev": true + }, + "node_modules/@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" + }, + "node_modules/@types/prop-types": { + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + }, + "node_modules/@types/react": { + "version": "18.0.15", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.15.tgz", + "integrity": "sha512-iz3BtLuIYH1uWdsv6wXYdhozhqj20oD4/Hk2DNXIn1kFsmp9x8d9QB6FnPhfkbhd2PgEONt9Q1x/ebkwjfFLow==", + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.0.6", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.6.tgz", + "integrity": "sha512-/5OFZgfIPSwy+YuIBP/FgJnQnsxhZhjjrnxudMddeblOouIodEQ75X14Rr4wGSG/bknL+Omy9iWlLo1u/9GzAA==", + "devOptional": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-redux": { + "version": "7.1.24", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.24.tgz", + "integrity": "sha512-7FkurKcS1k0FHZEtdbbgN8Oc6b+stGSfZYjQGicofJ0j4U0qIn/jaSvnP2pLwZKiai3/17xqqxkkrxTgN8UNbQ==", + "dependencies": { + "@types/hoist-non-react-statics": "^3.3.0", + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0", + "redux": "^4.0.0" + } + }, + "node_modules/@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" + }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", + "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.30.6", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.30.6.tgz", + "integrity": "sha512-gfF9lZjT0p2ZSdxO70Xbw8w9sPPJGfAdjK7WikEjB3fcUI/yr9maUVEdqigBjKincUYNKOmf7QBMiTf719kbrA==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.30.6", + "@typescript-eslint/types": "5.30.6", + "@typescript-eslint/typescript-estree": "5.30.6", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.30.6", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.30.6.tgz", + "integrity": "sha512-Hkq5PhLgtVoW1obkqYH0i4iELctEKixkhWLPTYs55doGUKCASvkjOXOd/pisVeLdO24ZX9D6yymJ/twqpJiG3g==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.30.6", + "@typescript-eslint/visitor-keys": "5.30.6" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.30.6", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.30.6.tgz", + "integrity": "sha512-HdnP8HioL1F7CwVmT4RaaMX57RrfqsOMclZc08wGMiDYJBsLGBM7JwXM4cZJmbWLzIR/pXg1kkrBBVpxTOwfUg==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.30.6", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.6.tgz", + "integrity": "sha512-Z7TgPoeYUm06smfEfYF0RBkpF8csMyVnqQbLYiGgmUSTaSXTP57bt8f0UFXstbGxKIreTwQCujtaH0LY9w9B+A==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.30.6", + "@typescript-eslint/visitor-keys": "5.30.6", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.30.6", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.6.tgz", + "integrity": "sha512-41OiCjdL2mCaSDi2SvYbzFLlqqlm5v1ZW9Ym55wXKL/Rx6OOB1IbuFGo71Fj6Xy90gJDFTlgOS+vbmtGHPTQQA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.30.6", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/array-includes": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz", + "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", + "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.0.tgz", + "integrity": "sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ast-types-flow": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", + "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==", + "dev": true + }, + "node_modules/axe-core": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.4.3.tgz", + "integrity": "sha512-32+ub6kkdhhWick/UjvEwRchgoetXqTK14INLqbGm5U2TzBkBNF3nQtLYm8ovxSkQWArjEQvftCKryjZaATu3w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/axobject-query": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", + "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==", + "dev": true + }, + "node_modules/babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "dev": true, + "dependencies": { + "object.assign": "^4.1.0" + } + }, + "node_modules/babel-plugin-macros": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz", + "integrity": "sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "cosmiconfig": "^6.0.0", + "resolve": "^1.12.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz", + "integrity": "sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.13.11", + "@babel/helper-define-polyfill-provider": "^0.3.1", + "semver": "^6.1.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz", + "integrity": "sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.1", + "core-js-compat": "^3.21.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", + "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.2.tgz", + "integrity": "sha512-MonuOgAtUB46uP5CezYbRaYKBNt2LxP0yX+Pmj4LkcDFGkn9Cbpi83d9sCjwQDErXsIJSzY5oKGDbgOlF/LPAA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001366", + "electron-to-chromium": "^1.4.188", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.4" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001367", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001367.tgz", + "integrity": "sha512-XDgbeOHfifWV3GEES2B8rtsrADx4Jf+juKX2SICJcaUhjYBO3bR96kvEIHa15VU6ohtOhBZuPGGYGbXMRn0NCw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "node_modules/core-js-compat": { + "version": "3.23.5", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.23.5.tgz", + "integrity": "sha512-fHYozIFIxd+91IIbXJgWd/igXIc8Mf9is0fusswjnGIWVG96y2cwyUdlCkGOw6rMLHKAxg7xtCIVaHsyOUnJIg==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.2", + "semver": "7.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat/node_modules/semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/core-js-pure": { + "version": "3.23.5", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.23.5.tgz", + "integrity": "sha512-8t78LdpKSuCq4pJYCYk8hl7XEkAX+BP16yRIwL3AanTksxuEf7CM83vRyctmiEL8NDZ3jpUcv56fk9/zG3aIuw==", + "dev": true, + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz", + "integrity": "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==" + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/define-properties": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "dev": true, + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.199", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.199.tgz", + "integrity": "sha512-WIGME0Cs7oob3mxsJwHbeWkH0tYkIE/sjkJ8ML2BYmuRcjhRl/q5kVDXG7W9LOOKwzPU5M0LBlXRq9rlSgnNlg==" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz", + "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "regexp.prototype.flags": "^1.4.3", + "string.prototype.trimend": "^1.0.5", + "string.prototype.trimstart": "^1.0.5", + "unbox-primitive": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.20.0.tgz", + "integrity": "sha512-d4ixhz5SKCa1D6SCPrivP7yYVi7nyD6A4vs6HIAul9ujBzcEmZVM3/0NN/yu5nKhmO1wjp5xQ46iRfmDGlOviA==", + "dev": true, + "dependencies": { + "@eslint/eslintrc": "^1.3.0", + "@humanwhocodes/config-array": "^0.9.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.2", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-next": { + "version": "12.2.2", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-12.2.2.tgz", + "integrity": "sha512-oJhWBLC4wDYYUFv/5APbjHUFd0QRFCojMdj/QnMoOEktmeTvwnnoA8F8uaXs0fQgsaTK0tbUxBRv9/Y4/rpxOA==", + "dev": true, + "dependencies": { + "@next/eslint-plugin-next": "12.2.2", + "@rushstack/eslint-patch": "^1.1.3", + "@typescript-eslint/parser": "^5.21.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-import-resolver-typescript": "^2.7.1", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-jsx-a11y": "^6.5.1", + "eslint-plugin-react": "^7.29.4", + "eslint-plugin-react-hooks": "^4.5.0" + }, + "peerDependencies": { + "eslint": "^7.23.0 || ^8.0.0", + "typescript": ">=3.3.1" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", + "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "resolve": "^1.20.0" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-typescript": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-2.7.1.tgz", + "integrity": "sha512-00UbgGwV8bSgUv34igBDbTOtKhqoRMy9bFjNehT40bXg6585PNIct8HhXZ0SybqB9rWtXj9crcku8ndDn/gIqQ==", + "dev": true, + "dependencies": { + "debug": "^4.3.4", + "glob": "^7.2.0", + "is-glob": "^4.0.3", + "resolve": "^1.22.0", + "tsconfig-paths": "^3.14.1" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", + "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "find-up": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", + "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.4", + "array.prototype.flat": "^1.2.5", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.7.3", + "has": "^1.0.3", + "is-core-module": "^2.8.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.values": "^1.1.5", + "resolve": "^1.22.0", + "tsconfig-paths": "^3.14.1" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.6.0.tgz", + "integrity": "sha512-kTeLuIzpNhXL2CwLlc8AHI0aFRwWHcg483yepO9VQiHzM9bZwJdzTkzBszbuPrbgGmq2rlX/FaT2fJQsjUSHsw==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.18.3", + "aria-query": "^4.2.2", + "array-includes": "^3.1.5", + "ast-types-flow": "^0.0.7", + "axe-core": "^4.4.2", + "axobject-query": "^2.2.0", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "has": "^1.0.3", + "jsx-ast-utils": "^3.3.1", + "language-tags": "^1.0.5", + "minimatch": "^3.1.2", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.30.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.30.1.tgz", + "integrity": "sha512-NbEvI9jtqO46yJA3wcRF9Mo0lF9T/jhdHqhCHXiXtD+Zcb98812wvokjWpU7Q4QH5edo6dmqrukxVvWWXHlsUg==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.5", + "array.prototype.flatmap": "^1.3.0", + "doctrine": "^2.1.0", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.5", + "object.fromentries": "^2.0.5", + "object.hasown": "^1.1.1", + "object.values": "^1.1.5", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.3", + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", + "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", + "dev": true, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", + "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-plugin-react/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/espree": { + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz", + "integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==", + "dev": true, + "dependencies": { + "acorn": "^8.7.1", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + }, + "node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz", + "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", + "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "13.16.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.16.0.tgz", + "integrity": "sha512-A1lrQfpNF+McdPOnnFqY3kSN0AFTy485bTi1bkLk4mVPODIUEcSfhHgRqA+QdXPksrSTTztYXx37NFV+GpGk3Q==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/immer": { + "version": "9.0.15", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.15.tgz", + "integrity": "sha512-2eB/sswms9AEUSkOm4SbV5Y7Vmt/bKRwByd52jfLkW4OLYeaTP3EEiJ9agqU0O/tq6Dk62Zfj+TJSqfm1rLVGQ==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.2.tgz", + "integrity": "sha512-4ZCADZHRkno244xlNnn4AOG6sRQ7iBZ5BbgZ4vW4y5IZw7cVUD1PPeblm1xx/nfmMxPdt/LHsXZW8z/j58+l9Q==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.5", + "object.assign": "^4.1.2" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/just-curry-it": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/just-curry-it/-/just-curry-it-3.2.1.tgz", + "integrity": "sha512-Q8206k8pTY7krW32cdmPsP+DqqLgWx/hYPSj9/+7SYqSqz7UuwPbfSe07lQtvuuaVyiSJveXk0E5RydOuWwsEg==" + }, + "node_modules/language-subtag-registry": { + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", + "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==", + "dev": true + }, + "node_modules/language-tags": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", + "integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==", + "dev": true, + "dependencies": { + "language-subtag-registry": "~0.3.2" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/next": { + "version": "12.2.2", + "resolved": "https://registry.npmjs.org/next/-/next-12.2.2.tgz", + "integrity": "sha512-zAYFY45aBry/PlKONqtlloRFqU/We3zWYdn2NoGvDZkoYUYQSJC8WMcalS5C19MxbCZLUVCX7D7a6gTGgl2yLg==", + "dependencies": { + "@next/env": "12.2.2", + "@swc/helpers": "0.4.2", + "caniuse-lite": "^1.0.30001332", + "postcss": "8.4.5", + "styled-jsx": "5.0.2", + "use-sync-external-store": "1.1.0" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": ">=12.22.0" + }, + "optionalDependencies": { + "@next/swc-android-arm-eabi": "12.2.2", + "@next/swc-android-arm64": "12.2.2", + "@next/swc-darwin-arm64": "12.2.2", + "@next/swc-darwin-x64": "12.2.2", + "@next/swc-freebsd-x64": "12.2.2", + "@next/swc-linux-arm-gnueabihf": "12.2.2", + "@next/swc-linux-arm64-gnu": "12.2.2", + "@next/swc-linux-arm64-musl": "12.2.2", + "@next/swc-linux-x64-gnu": "12.2.2", + "@next/swc-linux-x64-musl": "12.2.2", + "@next/swc-win32-arm64-msvc": "12.2.2", + "@next/swc-win32-ia32-msvc": "12.2.2", + "@next/swc-win32-x64-msvc": "12.2.2" + }, + "peerDependencies": { + "fibers": ">= 3.1.0", + "node-sass": "^6.0.0 || ^7.0.0", + "react": "^17.0.2 || ^18.0.0-0", + "react-dom": "^17.0.2 || ^18.0.0-0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "fibers": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/node-releases": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz", + "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz", + "integrity": "sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.hasown": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.1.tgz", + "integrity": "sha512-LYLe4tivNQzq4JdaWW6WO3HMZZJWzkkH8fnI6EebWl0VZth2wL2Lovm74ep2/gZzlaTdV62JZHEqHQ2yVn8Q/A==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", + "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.4.5", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz", + "integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==", + "dependencies": { + "nanoid": "^3.1.30", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/react-redux": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.0.2.tgz", + "integrity": "sha512-nBwiscMw3NoP59NFCXFf02f8xdo+vSHT/uZ1ldDwF7XaTpzm+Phk97VT4urYBl5TYAPNVaFm12UHAEyzkpNzRA==", + "dependencies": { + "@babel/runtime": "^7.12.1", + "@types/hoist-non-react-statics": "^3.3.1", + "@types/use-sync-external-store": "^0.0.3", + "hoist-non-react-statics": "^3.3.2", + "react-is": "^18.0.0", + "use-sync-external-store": "^1.0.0" + }, + "peerDependencies": { + "@types/react": "^16.8 || ^17.0 || ^18.0", + "@types/react-dom": "^16.8 || ^17.0 || ^18.0", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0", + "react-native": ">=0.59", + "redux": "^4" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, + "node_modules/react-redux/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + }, + "node_modules/reduce-reducers": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/reduce-reducers/-/reduce-reducers-0.4.3.tgz", + "integrity": "sha512-+CNMnI8QhgVMtAt54uQs3kUxC3Sybpa7Y63HR14uGLgI9/QR5ggHvpxwhGGe3wmx5V91YwqQIblN9k5lspAmGw==" + }, + "node_modules/redux": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.0.tgz", + "integrity": "sha512-oSBmcKKIuIR4ME29/AeNUnl5L+hvBq7OaJWzaptTQJAntaPvxIJqfnjbaEiCzzaIz+XmVILfqAM3Ob0aXLPfjA==", + "dependencies": { + "@babel/runtime": "^7.9.2" + } + }, + "node_modules/redux-actions": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/redux-actions/-/redux-actions-2.6.5.tgz", + "integrity": "sha512-pFhEcWFTYNk7DhQgxMGnbsB1H2glqhQJRQrtPb96kD3hWiZRzXHwwmFPswg6V2MjraXRXWNmuP9P84tvdLAJmw==", + "dependencies": { + "invariant": "^2.2.4", + "just-curry-it": "^3.1.0", + "loose-envify": "^1.4.0", + "reduce-reducers": "^0.4.3", + "to-camel-case": "^1.0.0" + } + }, + "node_modules/redux-flash": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/redux-flash/-/redux-flash-2.0.2.tgz", + "integrity": "sha512-tX8Yxf13uy2IVvQm5VpiGabirGySZhM9DZGzDsmU818px5bpmbUsxqCnUy/NtTmUEJnFuU+vL6IYejkbwHr/Dw==", + "dependencies": { + "prop-types": "^15.6.1", + "redux-actions": "^2.6.5", + "uuid": "^3.1.0" + }, + "peerDependencies": { + "redux": "^4.0.0 || ^3.0.0" + } + }, + "node_modules/redux-thunk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.1.tgz", + "integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==", + "peerDependencies": { + "redux": "^4" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", + "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + }, + "node_modules/regenerator-transform": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz", + "integrity": "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/regexpu-core": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.1.0.tgz", + "integrity": "sha512-bb6hk+xWd2PEOkj5It46A16zFMs2mv86Iwpdu94la4S3sJ7C973h2dHpYKwIBGaWSO7cIRJ+UX0IeMaWcO4qwA==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.0.1", + "regjsgen": "^0.6.0", + "regjsparser": "^0.8.2", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", + "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==", + "dev": true + }, + "node_modules/regjsparser": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", + "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", + "dev": true, + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/reselect": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.6.tgz", + "integrity": "sha512-ZovIuXqto7elwnxyXbBtCPo9YFEr3uJqj2rRbcOOog1bmu2Ag85M4hixSwFWyaBMKXNgvPaJ9OSu9SkBPIeJHQ==" + }, + "node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz", + "integrity": "sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1", + "get-intrinsic": "^1.1.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.4.1", + "side-channel": "^1.0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", + "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", + "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/styled-jsx": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.2.tgz", + "integrity": "sha512-LqPQrbBh3egD57NBcHET4qcgshPks+yblyhPlH2GY8oaDgKs8SK4C3dBh3oSJjgzJ3G5t1SYEZGHkP+QEpX9EQ==", + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/stylis": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.0.13.tgz", + "integrity": "sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag==" + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/to-camel-case": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-camel-case/-/to-camel-case-1.0.0.tgz", + "integrity": "sha512-nD8pQi5H34kyu1QDMFjzEIYqk0xa9Alt6ZfrdEMuHCFOfTLhDG5pgTu/aAM9Wt9lXILwlXmWP43b8sav0GNE8Q==", + "dependencies": { + "to-space-case": "^1.0.0" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-no-case": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/to-no-case/-/to-no-case-1.0.2.tgz", + "integrity": "sha512-Z3g735FxuZY8rodxV4gH7LxClE4H0hTIyHNIHdk+vpQxjLm0cwnKXq/OFVZ76SOQmto7txVcwSCwkU5kqp+FKg==" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/to-space-case": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-space-case/-/to-space-case-1.0.0.tgz", + "integrity": "sha512-rLdvwXZ39VOn1IxGL3V6ZstoTbwLRckQmn/U8ZDLuWwIXNpuZDhQ3AiRUlhTbOXFVE9C+dR51wM0CBDhk31VcA==", + "dependencies": { + "to-no-case": "^1.0.0" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", + "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", + "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", + "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz", + "integrity": "sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist-lint": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.1.0.tgz", + "integrity": "sha512-SEnieB2FPKEVne66NpXPd1Np4R1lTNKfjuy3XdIoPQKYBAFdzbzSZlSn1KJZUiihQLQC5Znot4SBz1EOTBwQAQ==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + } + }, + "dependencies": { + "@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "requires": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "requires": { + "@babel/highlight": "^7.18.6" + } + }, + "@babel/compat-data": { + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.8.tgz", + "integrity": "sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ==" + }, + "@babel/core": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.9.tgz", + "integrity": "sha512-1LIb1eL8APMy91/IMW+31ckrfBM4yCoLaVzoDhZUKSM4cu1L1nIidyxkCgzPAgrC5WEz36IPEr/eSeSF9pIn+g==", + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.18.9", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-module-transforms": "^7.18.9", + "@babel/helpers": "^7.18.9", + "@babel/parser": "^7.18.9", + "@babel/template": "^7.18.6", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "dependencies": { + "json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "@babel/generator": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.9.tgz", + "integrity": "sha512-wt5Naw6lJrL1/SGkipMiFxJjtyczUWTP38deiP1PO60HsBjDeKk08CGC3S8iVuvf0FmTdgKwU1KIXzSKL1G0Ug==", + "requires": { + "@babel/types": "^7.18.9", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", + "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz", + "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==", + "dev": true, + "requires": { + "@babel/helper-explode-assignable-expression": "^7.18.6", + "@babel/types": "^7.18.9" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz", + "integrity": "sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg==", + "requires": { + "@babel/compat-data": "^7.18.8", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.20.2", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.18.9.tgz", + "integrity": "sha512-WvypNAYaVh23QcjpMR24CwZY2Nz6hqdOcFdPbNpV56hL5H6KiFheO7Xm1aPdlLQ7d5emYZX7VZwPp9x3z+2opw==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.9", + "@babel/helper-split-export-declaration": "^7.18.6" + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.18.6.tgz", + "integrity": "sha512-7LcpH1wnQLGrI+4v+nPp+zUvIkF9x0ddv1Hkdue10tg3gmRnLy97DXh4STiOf1qeIInyD69Qv5kKSZzKD8B/7A==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "regexpu-core": "^5.1.0" + } + }, + "@babel/helper-define-polyfill-provider": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz", + "integrity": "sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==", + "dev": true, + "requires": { + "@babel/helper-compilation-targets": "^7.13.0", + "@babel/helper-module-imports": "^7.12.13", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/traverse": "^7.13.0", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/helper-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==" + }, + "@babel/helper-explode-assignable-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz", + "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-function-name": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.18.9.tgz", + "integrity": "sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A==", + "requires": { + "@babel/template": "^7.18.6", + "@babel/types": "^7.18.9" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz", + "integrity": "sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==", + "dev": true, + "requires": { + "@babel/types": "^7.18.9" + } + }, + "@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-module-transforms": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.9.tgz", + "integrity": "sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g==", + "requires": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.18.6", + "@babel/template": "^7.18.6", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", + "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz", + "integrity": "sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w==" + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", + "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-wrap-function": "^7.18.9", + "@babel/types": "^7.18.9" + } + }, + "@babel/helper-replace-supers": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.18.9.tgz", + "integrity": "sha512-dNsWibVI4lNT6HiuOIBr1oyxo40HvIVmbwPUm3XZ7wMh4k2WxrxTqZwSqw/eEmXDS9np0ey5M2bz9tBmO9c+YQ==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9" + } + }, + "@babel/helper-simple-access": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", + "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.9.tgz", + "integrity": "sha512-imytd2gHi3cJPsybLRbmFrF7u5BIEuI2cNheyKi3/iOBC63kNn3q8Crn2xVuESli0aM4KYsyEqKyS7lFL8YVtw==", + "dev": true, + "requires": { + "@babel/types": "^7.18.9" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", + "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==" + }, + "@babel/helper-validator-option": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", + "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==" + }, + "@babel/helper-wrap-function": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.18.9.tgz", + "integrity": "sha512-cG2ru3TRAL6a60tfQflpEfs4ldiPwF6YW3zfJiRgmoFVIaC1vGnBBgatfec+ZUziPHkHSaXAuEck3Cdkf3eRpQ==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.18.9", + "@babel/template": "^7.18.6", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9" + } + }, + "@babel/helpers": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.9.tgz", + "integrity": "sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ==", + "requires": { + "@babel/template": "^7.18.6", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9" + } + }, + "@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "requires": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/parser": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.9.tgz", + "integrity": "sha512-9uJveS9eY9DJ0t64YbIBZICtJy8a5QrDEVdiLCG97fVLpDTpGX7t8mMSb6OWw6Lrnjqj4O8zwjELX3dhoMgiBg==" + }, + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz", + "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz", + "integrity": "sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@babel/plugin-proposal-optional-chaining": "^7.18.9" + } + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.18.6.tgz", + "integrity": "sha512-WAz4R9bvozx4qwf74M+sfqPMKfSqwM0phxPTR6iJIi8robgzXwkEgmeJG1gEKhm6sDqT/U9aV3lfcqybIpev8w==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-remap-async-to-generator": "^7.18.6", + "@babel/plugin-syntax-async-generators": "^7.8.4" + } + }, + "@babel/plugin-proposal-class-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-proposal-class-static-block": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.6.tgz", + "integrity": "sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + } + }, + "@babel/plugin-proposal-dynamic-import": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", + "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + } + }, + "@babel/plugin-proposal-export-namespace-from": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", + "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + } + }, + "@babel/plugin-proposal-json-strings": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz", + "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-json-strings": "^7.8.3" + } + }, + "@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz", + "integrity": "sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + } + }, + "@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + } + }, + "@babel/plugin-proposal-numeric-separator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", + "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.18.9.tgz", + "integrity": "sha512-kDDHQ5rflIeY5xl69CEqGEZ0KY369ehsCIEbTGb4siHG5BE9sga/T0r0OUwyZNLMmZE79E1kbsqAjwFCW4ds6Q==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.18.8", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.18.8" + } + }, + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", + "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + } + }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz", + "integrity": "sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + } + }, + "@babel/plugin-proposal-private-methods": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-proposal-private-property-in-object": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.18.6.tgz", + "integrity": "sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + } + }, + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", + "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-syntax-import-assertions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.18.6.tgz", + "integrity": "sha512-/DU3RXad9+bZwrgWJQKbr39gYbJpLJHezqEzRzi/BHRlJ9zsQb4CK2CA/5apllXNomwA1qHwzvHl+AdEmC5krQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-jsx": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", + "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz", + "integrity": "sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz", + "integrity": "sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-remap-async-to-generator": "^7.18.6" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz", + "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.18.9.tgz", + "integrity": "sha512-5sDIJRV1KtQVEbt/EIBwGy4T01uYIo4KRB3VUqzkhrAIOGx7AoctL9+Ux88btY0zXdDyPJ9mW+bg+v+XEkGmtw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.18.9.tgz", + "integrity": "sha512-EkRQxsxoytpTlKJmSPYrsOMjCILacAjtSVkd4gChEe2kXjFCun3yohhW5I7plXJhCemM0gKsaGMcO8tinvCA5g==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-replace-supers": "^7.18.9", + "@babel/helper-split-export-declaration": "^7.18.6", + "globals": "^11.1.0" + }, + "dependencies": { + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + } + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz", + "integrity": "sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.18.9.tgz", + "integrity": "sha512-p5VCYNddPLkZTq4XymQIaIfZNJwT9YsjkPOhkVEqt6QIpQFZVM9IltqqYpOEkJoN1DPznmxUDyZ5CTZs/ZCuHA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz", + "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", + "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz", + "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==", + "dev": true, + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz", + "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", + "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", + "dev": true, + "requires": { + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", + "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz", + "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.18.6.tgz", + "integrity": "sha512-Pra5aXsmTsOnjM3IajS8rTaLCy++nGM4v3YR4esk5PCsyg9z8NA5oQLwxzMUtDBd8F+UmVza3VxoAaWCbzH1rg==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.18.6.tgz", + "integrity": "sha512-Qfv2ZOWikpvmedXQJDSbxNqy7Xr/j2Y8/KfijM0iJyKkBTmWuvCA1yeH1yDM7NJhBW/2aXxeucLj6i80/LAJ/Q==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-simple-access": "^7.18.6", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.18.9.tgz", + "integrity": "sha512-zY/VSIbbqtoRoJKo2cDTewL364jSlZGvn0LKOf9ntbfxOvjfmyrdtEEOAdswOswhZEb8UH3jDkCKHd1sPgsS0A==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-module-transforms": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-validator-identifier": "^7.18.6", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz", + "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.18.6.tgz", + "integrity": "sha512-UmEOGF8XgaIqD74bC8g7iV3RYj8lMf0Bw7NJzvnS9qQhM4mg+1WHKotUIdjxgD2RGrgFLZZPCFPFj3P/kVDYhg==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz", + "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", + "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.6" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.18.8.tgz", + "integrity": "sha512-ivfbE3X2Ss+Fj8nnXvKJS6sjRG4gzwPMsP+taZC+ZzEGjAYlvENixmt1sZ5Ca6tWls+BlKSGKPJ6OOXvXCbkFg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz", + "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz", + "integrity": "sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "regenerator-transform": "^0.15.0" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz", + "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", + "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.18.9.tgz", + "integrity": "sha512-39Q814wyoOPtIB/qGopNIL9xDChOE1pNU0ZY5dO0owhiVt/5kFm4li+/bBtwc7QotG0u5EPzqhZdjMtmqBqyQA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz", + "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", + "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", + "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-unicode-escapes": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.6.tgz", + "integrity": "sha512-XNRwQUXYMP7VLuy54cr/KS/WeL3AZeORhrmeZ7iewgu+X2eBqmpaLI/hzqr9ZxCeUoq0ASK4GUzSM0BDhZkLFw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz", + "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/preset-env": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.18.9.tgz", + "integrity": "sha512-75pt/q95cMIHWssYtyfjVlvI+QEZQThQbKvR9xH+F/Agtw/s4Wfc2V9Bwd/P39VtixB7oWxGdH4GteTTwYJWMg==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.18.8", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-async-generator-functions": "^7.18.6", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-class-static-block": "^7.18.6", + "@babel/plugin-proposal-dynamic-import": "^7.18.6", + "@babel/plugin-proposal-export-namespace-from": "^7.18.9", + "@babel/plugin-proposal-json-strings": "^7.18.6", + "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", + "@babel/plugin-proposal-numeric-separator": "^7.18.6", + "@babel/plugin-proposal-object-rest-spread": "^7.18.9", + "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", + "@babel/plugin-proposal-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "@babel/plugin-proposal-private-property-in-object": "^7.18.6", + "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.18.6", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-transform-arrow-functions": "^7.18.6", + "@babel/plugin-transform-async-to-generator": "^7.18.6", + "@babel/plugin-transform-block-scoped-functions": "^7.18.6", + "@babel/plugin-transform-block-scoping": "^7.18.9", + "@babel/plugin-transform-classes": "^7.18.9", + "@babel/plugin-transform-computed-properties": "^7.18.9", + "@babel/plugin-transform-destructuring": "^7.18.9", + "@babel/plugin-transform-dotall-regex": "^7.18.6", + "@babel/plugin-transform-duplicate-keys": "^7.18.9", + "@babel/plugin-transform-exponentiation-operator": "^7.18.6", + "@babel/plugin-transform-for-of": "^7.18.8", + "@babel/plugin-transform-function-name": "^7.18.9", + "@babel/plugin-transform-literals": "^7.18.9", + "@babel/plugin-transform-member-expression-literals": "^7.18.6", + "@babel/plugin-transform-modules-amd": "^7.18.6", + "@babel/plugin-transform-modules-commonjs": "^7.18.6", + "@babel/plugin-transform-modules-systemjs": "^7.18.9", + "@babel/plugin-transform-modules-umd": "^7.18.6", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.18.6", + "@babel/plugin-transform-new-target": "^7.18.6", + "@babel/plugin-transform-object-super": "^7.18.6", + "@babel/plugin-transform-parameters": "^7.18.8", + "@babel/plugin-transform-property-literals": "^7.18.6", + "@babel/plugin-transform-regenerator": "^7.18.6", + "@babel/plugin-transform-reserved-words": "^7.18.6", + "@babel/plugin-transform-shorthand-properties": "^7.18.6", + "@babel/plugin-transform-spread": "^7.18.9", + "@babel/plugin-transform-sticky-regex": "^7.18.6", + "@babel/plugin-transform-template-literals": "^7.18.9", + "@babel/plugin-transform-typeof-symbol": "^7.18.9", + "@babel/plugin-transform-unicode-escapes": "^7.18.6", + "@babel/plugin-transform-unicode-regex": "^7.18.6", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.18.9", + "babel-plugin-polyfill-corejs2": "^0.3.1", + "babel-plugin-polyfill-corejs3": "^0.5.2", + "babel-plugin-polyfill-regenerator": "^0.3.1", + "core-js-compat": "^3.22.1", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/preset-modules": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", + "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + } + }, + "@babel/runtime": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.6.tgz", + "integrity": "sha512-t9wi7/AW6XtKahAe20Yw0/mMljKq0B1r2fPdvaAdV/KPDZewFXdaaa6K7lxmZBZ8FBNpCiAT6iHPmd6QO9bKfQ==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/runtime-corejs3": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.18.6.tgz", + "integrity": "sha512-cOu5wH2JFBgMjje+a+fz2JNIWU4GzYpl05oSob3UDvBEh6EuIn+TXFHMmBbhSb+k/4HMzgKCQfEEDArAWNF9Cw==", + "dev": true, + "requires": { + "core-js-pure": "^3.20.2", + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/template": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.6.tgz", + "integrity": "sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw==", + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.6", + "@babel/types": "^7.18.6" + } + }, + "@babel/traverse": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.9.tgz", + "integrity": "sha512-LcPAnujXGwBgv3/WHv01pHtb2tihcyW1XuL9wd7jqh1Z8AQkTd+QVjMrMijrln0T7ED3UXLIy36P9Ao7W75rYg==", + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.18.9", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.18.9", + "@babel/types": "^7.18.9", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "dependencies": { + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + } + } + }, + "@babel/types": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.9.tgz", + "integrity": "sha512-WwMLAg2MvJmt/rKEVQBBhIVffMmnilX4oe0sRe7iPOHIGsqpruFHHdrfj4O1CMMtgMtCU4oPafZjDPCRgO57Wg==", + "requires": { + "@babel/helper-validator-identifier": "^7.18.6", + "to-fast-properties": "^2.0.0" + } + }, + "@emotion/babel-plugin": { + "version": "11.9.2", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.9.2.tgz", + "integrity": "sha512-Pr/7HGH6H6yKgnVFNEj2MVlreu3ADqftqjqwUvDy/OJzKFgxKeTQ+eeUf20FOTuHVkDON2iNa25rAXVYtWJCjw==", + "requires": { + "@babel/helper-module-imports": "^7.12.13", + "@babel/plugin-syntax-jsx": "^7.12.13", + "@babel/runtime": "^7.13.10", + "@emotion/hash": "^0.8.0", + "@emotion/memoize": "^0.7.5", + "@emotion/serialize": "^1.0.2", + "babel-plugin-macros": "^2.6.1", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.0.13" + } + }, + "@emotion/cache": { + "version": "11.9.3", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.9.3.tgz", + "integrity": "sha512-0dgkI/JKlCXa+lEXviaMtGBL0ynpx4osh7rjOXE71q9bIF8G+XhJgvi+wDu0B0IdCVx37BffiwXlN9I3UuzFvg==", + "requires": { + "@emotion/memoize": "^0.7.4", + "@emotion/sheet": "^1.1.1", + "@emotion/utils": "^1.0.0", + "@emotion/weak-memoize": "^0.2.5", + "stylis": "4.0.13" + } + }, + "@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" + }, + "@emotion/memoize": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.5.tgz", + "integrity": "sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ==" + }, + "@emotion/react": { + "version": "11.9.3", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.9.3.tgz", + "integrity": "sha512-g9Q1GcTOlzOEjqwuLF/Zd9LC+4FljjPjDfxSM7KmEakm+hsHXk+bYZ2q+/hTJzr0OUNkujo72pXLQvXj6H+GJQ==", + "requires": { + "@babel/runtime": "^7.13.10", + "@emotion/babel-plugin": "^11.7.1", + "@emotion/cache": "^11.9.3", + "@emotion/serialize": "^1.0.4", + "@emotion/utils": "^1.1.0", + "@emotion/weak-memoize": "^0.2.5", + "hoist-non-react-statics": "^3.3.1" + } + }, + "@emotion/serialize": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.0.4.tgz", + "integrity": "sha512-1JHamSpH8PIfFwAMryO2bNka+y8+KA5yga5Ocf2d7ZEiJjb7xlLW7aknBGZqJLajuLOvJ+72vN+IBSwPlXD1Pg==", + "requires": { + "@emotion/hash": "^0.8.0", + "@emotion/memoize": "^0.7.4", + "@emotion/unitless": "^0.7.5", + "@emotion/utils": "^1.0.0", + "csstype": "^3.0.2" + } + }, + "@emotion/sheet": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.1.1.tgz", + "integrity": "sha512-J3YPccVRMiTZxYAY0IOq3kd+hUP8idY8Kz6B/Cyo+JuXq52Ek+zbPbSQUrVQp95aJ+lsAW7DPL1P2Z+U1jGkKA==" + }, + "@emotion/unitless": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", + "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" + }, + "@emotion/utils": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.1.0.tgz", + "integrity": "sha512-iRLa/Y4Rs5H/f2nimczYmS5kFJEbpiVvgN3XVfZ022IYhuNA1IRSHEizcof88LtCTXtl9S2Cxt32KgaXEu72JQ==" + }, + "@emotion/weak-memoize": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz", + "integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==" + }, + "@eslint/eslintrc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", + "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.3.2", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + } + }, + "@humanwhocodes/config-array": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + } + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "requires": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==" + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + }, + "@jridgewell/trace-mapping": { + "version": "0.3.14", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", + "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@next/env": { + "version": "12.2.2", + "resolved": "https://registry.npmjs.org/@next/env/-/env-12.2.2.tgz", + "integrity": "sha512-BqDwE4gDl1F608TpnNxZqrCn6g48MBjvmWFEmeX5wEXDXh3IkAOw6ASKUgjT8H4OUePYFqghDFUss5ZhnbOUjw==" + }, + "@next/eslint-plugin-next": { + "version": "12.2.2", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-12.2.2.tgz", + "integrity": "sha512-XOi0WzJhGH3Lk51SkSu9eZxF+IY1ZZhWcJTIGBycAbWU877IQa6+6KxMATWCOs7c+bmp6Sd8KywXJaDRxzu0JA==", + "dev": true, + "requires": { + "glob": "7.1.7" + }, + "dependencies": { + "glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "@next/swc-android-arm-eabi": { + "version": "12.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.2.2.tgz", + "integrity": "sha512-VHjuCHeq9qCprUZbsRxxM/VqSW8MmsUtqB5nEpGEgUNnQi/BTm/2aK8tl7R4D0twGKRh6g1AAeFuWtXzk9Z/vQ==", + "optional": true + }, + "@next/swc-android-arm64": { + "version": "12.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.2.2.tgz", + "integrity": "sha512-v5EYzXUOSv0r9mO/2PX6mOcF53k8ndlu9yeFHVAWW1Dhw2jaJcvTRcCAwYYN8Q3tDg0nH3NbEltJDLKmcJOuVA==", + "optional": true + }, + "@next/swc-darwin-arm64": { + "version": "12.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.2.2.tgz", + "integrity": "sha512-JCoGySHKGt+YBk7xRTFGx1QjrnCcwYxIo3yGepcOq64MoiocTM3yllQWeOAJU2/k9MH0+B5E9WUSme4rOCBbpA==", + "optional": true + }, + "@next/swc-darwin-x64": { + "version": "12.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.2.2.tgz", + "integrity": "sha512-dztDtvfkhUqiqpXvrWVccfGhLe44yQ5tQ7B4tBfnsOR6vxzI9DNPHTlEOgRN9qDqTAcFyPxvg86mn4l8bB9Jcw==", + "optional": true + }, + "@next/swc-freebsd-x64": { + "version": "12.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-12.2.2.tgz", + "integrity": "sha512-JUnXB+2xfxqsAvhFLPJpU1NeyDsvJrKoOjpV7g3Dxbno2Riu4tDKn3kKF886yleAuD/1qNTUCpqubTvbbT2VoA==", + "optional": true + }, + "@next/swc-linux-arm-gnueabihf": { + "version": "12.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.2.2.tgz", + "integrity": "sha512-XeYC/qqPLz58R4pjkb+x8sUUxuGLnx9QruC7/IGkK68yW4G17PHwKI/1njFYVfXTXUukpWjcfBuauWwxp9ke7Q==", + "optional": true + }, + "@next/swc-linux-arm64-gnu": { + "version": "12.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.2.2.tgz", + "integrity": "sha512-d6jT8xgfKYFkzR7J0OHo2D+kFvY/6W8qEo6/hmdrTt6AKAqxs//rbbcdoyn3YQq1x6FVUUd39zzpezZntg9Naw==", + "optional": true + }, + "@next/swc-linux-arm64-musl": { + "version": "12.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.2.2.tgz", + "integrity": "sha512-rIZRFxI9N/502auJT1i7coas0HTHUM+HaXMyJiCpnY8Rimbo0495ir24tzzHo3nQqJwcflcPTwEh/DV17sdv9A==", + "optional": true + }, + "@next/swc-linux-x64-gnu": { + "version": "12.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.2.2.tgz", + "integrity": "sha512-ir1vNadlUDj7eQk15AvfhG5BjVizuCHks9uZwBfUgT5jyeDCeRvaDCo1+Q6+0CLOAnYDR/nqSCvBgzG2UdFh9A==", + "optional": true + }, + "@next/swc-linux-x64-musl": { + "version": "12.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.2.2.tgz", + "integrity": "sha512-bte5n2GzLN3O8JdSFYWZzMgEgDHZmRz5wiispiiDssj4ik3l8E7wq/czNi8RmIF+ioj2sYVokUNa/ekLzrESWw==", + "optional": true + }, + "@next/swc-win32-arm64-msvc": { + "version": "12.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.2.2.tgz", + "integrity": "sha512-ZUGCmcDmdPVSAlwJ/aD+1F9lYW8vttseiv4n2+VCDv5JloxiX9aY32kYZaJJO7hmTLNrprvXkb4OvNuHdN22Jg==", + "optional": true + }, + "@next/swc-win32-ia32-msvc": { + "version": "12.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.2.2.tgz", + "integrity": "sha512-v7ykeEDbr9eXiblGSZiEYYkWoig6sRhAbLKHUHQtk8vEWWVEqeXFcxmw6LRrKu5rCN1DY357UlYWToCGPQPCRA==", + "optional": true + }, + "@next/swc-win32-x64-msvc": { + "version": "12.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.2.2.tgz", + "integrity": "sha512-2D2iinWUL6xx8D9LYVZ5qi7FP6uLAoWymt8m8aaG2Ld/Ka8/k723fJfiklfuAcwOxfufPJI+nRbT5VcgHGzHAQ==", + "optional": true + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@reduxjs/toolkit": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.8.3.tgz", + "integrity": "sha512-lU/LDIfORmjBbyDLaqFN2JB9YmAT1BElET9y0ZszwhSBa5Ef3t6o5CrHupw5J1iOXwd+o92QfQZ8OJpwXvsssg==", + "requires": { + "immer": "^9.0.7", + "redux": "^4.1.2", + "redux-thunk": "^2.4.1", + "reselect": "^4.1.5" + } + }, + "@rushstack/eslint-patch": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.1.4.tgz", + "integrity": "sha512-LwzQKA4vzIct1zNZzBmRKI9QuNpLgTQMEjsQLf3BXuGYb3QPTP4Yjf6mkdX+X1mYttZ808QpOwAzZjv28kq7DA==", + "dev": true + }, + "@swc/helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.2.tgz", + "integrity": "sha512-556Az0VX7WR6UdoTn4htt/l3zPQ7bsQWK+HqdG4swV7beUCxo/BqmvbOpUkTIm/9ih86LIf1qsUnywNL3obGHw==", + "requires": { + "tslib": "^2.4.0" + } + }, + "@types/hoist-non-react-statics": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "requires": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "@types/node": { + "version": "18.0.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.6.tgz", + "integrity": "sha512-/xUq6H2aQm261exT6iZTMifUySEt4GR5KX8eYyY+C4MSNPqSh9oNIP7tz2GLKTlFaiBbgZNxffoR3CVRG+cljw==", + "dev": true + }, + "@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" + }, + "@types/prop-types": { + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + }, + "@types/react": { + "version": "18.0.15", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.15.tgz", + "integrity": "sha512-iz3BtLuIYH1uWdsv6wXYdhozhqj20oD4/Hk2DNXIn1kFsmp9x8d9QB6FnPhfkbhd2PgEONt9Q1x/ebkwjfFLow==", + "requires": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "@types/react-dom": { + "version": "18.0.6", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.6.tgz", + "integrity": "sha512-/5OFZgfIPSwy+YuIBP/FgJnQnsxhZhjjrnxudMddeblOouIodEQ75X14Rr4wGSG/bknL+Omy9iWlLo1u/9GzAA==", + "devOptional": true, + "requires": { + "@types/react": "*" + } + }, + "@types/react-redux": { + "version": "7.1.24", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.24.tgz", + "integrity": "sha512-7FkurKcS1k0FHZEtdbbgN8Oc6b+stGSfZYjQGicofJ0j4U0qIn/jaSvnP2pLwZKiai3/17xqqxkkrxTgN8UNbQ==", + "requires": { + "@types/hoist-non-react-statics": "^3.3.0", + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0", + "redux": "^4.0.0" + } + }, + "@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" + }, + "@types/use-sync-external-store": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", + "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" + }, + "@typescript-eslint/parser": { + "version": "5.30.6", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.30.6.tgz", + "integrity": "sha512-gfF9lZjT0p2ZSdxO70Xbw8w9sPPJGfAdjK7WikEjB3fcUI/yr9maUVEdqigBjKincUYNKOmf7QBMiTf719kbrA==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.30.6", + "@typescript-eslint/types": "5.30.6", + "@typescript-eslint/typescript-estree": "5.30.6", + "debug": "^4.3.4" + } + }, + "@typescript-eslint/scope-manager": { + "version": "5.30.6", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.30.6.tgz", + "integrity": "sha512-Hkq5PhLgtVoW1obkqYH0i4iELctEKixkhWLPTYs55doGUKCASvkjOXOd/pisVeLdO24ZX9D6yymJ/twqpJiG3g==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.30.6", + "@typescript-eslint/visitor-keys": "5.30.6" + } + }, + "@typescript-eslint/types": { + "version": "5.30.6", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.30.6.tgz", + "integrity": "sha512-HdnP8HioL1F7CwVmT4RaaMX57RrfqsOMclZc08wGMiDYJBsLGBM7JwXM4cZJmbWLzIR/pXg1kkrBBVpxTOwfUg==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "5.30.6", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.6.tgz", + "integrity": "sha512-Z7TgPoeYUm06smfEfYF0RBkpF8csMyVnqQbLYiGgmUSTaSXTP57bt8f0UFXstbGxKIreTwQCujtaH0LY9w9B+A==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.30.6", + "@typescript-eslint/visitor-keys": "5.30.6", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.30.6", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.6.tgz", + "integrity": "sha512-41OiCjdL2mCaSDi2SvYbzFLlqqlm5v1ZW9Ym55wXKL/Rx6OOB1IbuFGo71Fj6Xy90gJDFTlgOS+vbmtGHPTQQA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.30.6", + "eslint-visitor-keys": "^3.3.0" + } + }, + "acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "requires": {} + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "dev": true, + "requires": { + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" + } + }, + "array-includes": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz", + "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.7" + } + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "array.prototype.flat": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", + "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" + } + }, + "array.prototype.flatmap": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.0.tgz", + "integrity": "sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" + } + }, + "ast-types-flow": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", + "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==", + "dev": true + }, + "axe-core": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.4.3.tgz", + "integrity": "sha512-32+ub6kkdhhWick/UjvEwRchgoetXqTK14INLqbGm5U2TzBkBNF3nQtLYm8ovxSkQWArjEQvftCKryjZaATu3w==", + "dev": true + }, + "axobject-query": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", + "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==", + "dev": true + }, + "babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "dev": true, + "requires": { + "object.assign": "^4.1.0" + } + }, + "babel-plugin-macros": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz", + "integrity": "sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==", + "requires": { + "@babel/runtime": "^7.7.2", + "cosmiconfig": "^6.0.0", + "resolve": "^1.12.0" + } + }, + "babel-plugin-polyfill-corejs2": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz", + "integrity": "sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.13.11", + "@babel/helper-define-polyfill-provider": "^0.3.1", + "semver": "^6.1.1" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "babel-plugin-polyfill-corejs3": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz", + "integrity": "sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==", + "dev": true, + "requires": { + "@babel/helper-define-polyfill-provider": "^0.3.1", + "core-js-compat": "^3.21.0" + } + }, + "babel-plugin-polyfill-regenerator": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", + "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", + "dev": true, + "requires": { + "@babel/helper-define-polyfill-provider": "^0.3.1" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browserslist": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.2.tgz", + "integrity": "sha512-MonuOgAtUB46uP5CezYbRaYKBNt2LxP0yX+Pmj4LkcDFGkn9Cbpi83d9sCjwQDErXsIJSzY5oKGDbgOlF/LPAA==", + "requires": { + "caniuse-lite": "^1.0.30001366", + "electron-to-chromium": "^1.4.188", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.4" + } + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" + }, + "caniuse-lite": { + "version": "1.0.30001367", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001367.tgz", + "integrity": "sha512-XDgbeOHfifWV3GEES2B8rtsrADx4Jf+juKX2SICJcaUhjYBO3bR96kvEIHa15VU6ohtOhBZuPGGYGbXMRn0NCw==" + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "core-js-compat": { + "version": "3.23.5", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.23.5.tgz", + "integrity": "sha512-fHYozIFIxd+91IIbXJgWd/igXIc8Mf9is0fusswjnGIWVG96y2cwyUdlCkGOw6rMLHKAxg7xtCIVaHsyOUnJIg==", + "dev": true, + "requires": { + "browserslist": "^4.21.2", + "semver": "7.0.0" + }, + "dependencies": { + "semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true + } + } + }, + "core-js-pure": { + "version": "3.23.5", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.23.5.tgz", + "integrity": "sha512-8t78LdpKSuCq4pJYCYk8hl7XEkAX+BP16yRIwL3AanTksxuEf7CM83vRyctmiEL8NDZ3jpUcv56fk9/zG3aIuw==", + "dev": true + }, + "cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "csstype": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz", + "integrity": "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==" + }, + "damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "define-properties": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "dev": true, + "requires": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "electron-to-chromium": { + "version": "1.4.199", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.199.tgz", + "integrity": "sha512-WIGME0Cs7oob3mxsJwHbeWkH0tYkIE/sjkJ8ML2BYmuRcjhRl/q5kVDXG7W9LOOKwzPU5M0LBlXRq9rlSgnNlg==" + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz", + "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "regexp.prototype.flags": "^1.4.3", + "string.prototype.trimend": "^1.0.5", + "string.prototype.trimstart": "^1.0.5", + "unbox-primitive": "^1.0.2" + } + }, + "es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" + }, + "eslint": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.20.0.tgz", + "integrity": "sha512-d4ixhz5SKCa1D6SCPrivP7yYVi7nyD6A4vs6HIAul9ujBzcEmZVM3/0NN/yu5nKhmO1wjp5xQ46iRfmDGlOviA==", + "dev": true, + "requires": { + "@eslint/eslintrc": "^1.3.0", + "@humanwhocodes/config-array": "^0.9.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.2", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + } + }, + "eslint-config-next": { + "version": "12.2.2", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-12.2.2.tgz", + "integrity": "sha512-oJhWBLC4wDYYUFv/5APbjHUFd0QRFCojMdj/QnMoOEktmeTvwnnoA8F8uaXs0fQgsaTK0tbUxBRv9/Y4/rpxOA==", + "dev": true, + "requires": { + "@next/eslint-plugin-next": "12.2.2", + "@rushstack/eslint-patch": "^1.1.3", + "@typescript-eslint/parser": "^5.21.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-import-resolver-typescript": "^2.7.1", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-jsx-a11y": "^6.5.1", + "eslint-plugin-react": "^7.29.4", + "eslint-plugin-react-hooks": "^4.5.0" + } + }, + "eslint-import-resolver-node": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", + "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "dev": true, + "requires": { + "debug": "^3.2.7", + "resolve": "^1.20.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "eslint-import-resolver-typescript": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-2.7.1.tgz", + "integrity": "sha512-00UbgGwV8bSgUv34igBDbTOtKhqoRMy9bFjNehT40bXg6585PNIct8HhXZ0SybqB9rWtXj9crcku8ndDn/gIqQ==", + "dev": true, + "requires": { + "debug": "^4.3.4", + "glob": "^7.2.0", + "is-glob": "^4.0.3", + "resolve": "^1.22.0", + "tsconfig-paths": "^3.14.1" + } + }, + "eslint-module-utils": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", + "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", + "dev": true, + "requires": { + "debug": "^3.2.7", + "find-up": "^2.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "eslint-plugin-import": { + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", + "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", + "dev": true, + "requires": { + "array-includes": "^3.1.4", + "array.prototype.flat": "^1.2.5", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.7.3", + "has": "^1.0.3", + "is-core-module": "^2.8.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.values": "^1.1.5", + "resolve": "^1.22.0", + "tsconfig-paths": "^3.14.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "eslint-plugin-jsx-a11y": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.6.0.tgz", + "integrity": "sha512-kTeLuIzpNhXL2CwLlc8AHI0aFRwWHcg483yepO9VQiHzM9bZwJdzTkzBszbuPrbgGmq2rlX/FaT2fJQsjUSHsw==", + "dev": true, + "requires": { + "@babel/runtime": "^7.18.3", + "aria-query": "^4.2.2", + "array-includes": "^3.1.5", + "ast-types-flow": "^0.0.7", + "axe-core": "^4.4.2", + "axobject-query": "^2.2.0", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "has": "^1.0.3", + "jsx-ast-utils": "^3.3.1", + "language-tags": "^1.0.5", + "minimatch": "^3.1.2", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "eslint-plugin-react": { + "version": "7.30.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.30.1.tgz", + "integrity": "sha512-NbEvI9jtqO46yJA3wcRF9Mo0lF9T/jhdHqhCHXiXtD+Zcb98812wvokjWpU7Q4QH5edo6dmqrukxVvWWXHlsUg==", + "dev": true, + "requires": { + "array-includes": "^3.1.5", + "array.prototype.flatmap": "^1.3.0", + "doctrine": "^2.1.0", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.5", + "object.fromentries": "^2.0.5", + "object.hasown": "^1.1.1", + "object.values": "^1.1.5", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.3", + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.7" + }, + "dependencies": { + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "resolve": { + "version": "2.0.0-next.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", + "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", + "dev": true, + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "eslint-plugin-react-hooks": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", + "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", + "dev": true, + "requires": {} + }, + "eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true + }, + "espree": { + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz", + "integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==", + "dev": true, + "requires": { + "acorn": "^8.7.1", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + } + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz", + "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + } + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" + }, + "get-intrinsic": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", + "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + } + }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "globals": { + "version": "13.16.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.16.0.tgz", + "integrity": "sha512-A1lrQfpNF+McdPOnnFqY3kSN0AFTy485bTi1bkLk4mVPODIUEcSfhHgRqA+QdXPksrSTTztYXx37NFV+GpGk3Q==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.1" + } + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "requires": { + "react-is": "^16.7.0" + } + }, + "ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true + }, + "immer": { + "version": "9.0.15", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.15.tgz", + "integrity": "sha512-2eB/sswms9AEUSkOm4SbV5Y7Vmt/bKRwByd52jfLkW4OLYeaTP3EEiJ9agqU0O/tq6Dk62Zfj+TJSqfm1rLVGQ==" + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "requires": { + "loose-envify": "^1.0.0" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "requires": { + "has-bigints": "^1.0.1" + } + }, + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "dev": true + }, + "is-core-module": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", + "requires": { + "has": "^1.0.3" + } + }, + "is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "jsx-ast-utils": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.2.tgz", + "integrity": "sha512-4ZCADZHRkno244xlNnn4AOG6sRQ7iBZ5BbgZ4vW4y5IZw7cVUD1PPeblm1xx/nfmMxPdt/LHsXZW8z/j58+l9Q==", + "dev": true, + "requires": { + "array-includes": "^3.1.5", + "object.assign": "^4.1.2" + } + }, + "just-curry-it": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/just-curry-it/-/just-curry-it-3.2.1.tgz", + "integrity": "sha512-Q8206k8pTY7krW32cdmPsP+DqqLgWx/hYPSj9/+7SYqSqz7UuwPbfSe07lQtvuuaVyiSJveXk0E5RydOuWwsEg==" + }, + "language-subtag-registry": { + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", + "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==", + "dev": true + }, + "language-tags": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", + "integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==", + "dev": true, + "requires": { + "language-subtag-registry": "~0.3.2" + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==" + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "next": { + "version": "12.2.2", + "resolved": "https://registry.npmjs.org/next/-/next-12.2.2.tgz", + "integrity": "sha512-zAYFY45aBry/PlKONqtlloRFqU/We3zWYdn2NoGvDZkoYUYQSJC8WMcalS5C19MxbCZLUVCX7D7a6gTGgl2yLg==", + "requires": { + "@next/env": "12.2.2", + "@next/swc-android-arm-eabi": "12.2.2", + "@next/swc-android-arm64": "12.2.2", + "@next/swc-darwin-arm64": "12.2.2", + "@next/swc-darwin-x64": "12.2.2", + "@next/swc-freebsd-x64": "12.2.2", + "@next/swc-linux-arm-gnueabihf": "12.2.2", + "@next/swc-linux-arm64-gnu": "12.2.2", + "@next/swc-linux-arm64-musl": "12.2.2", + "@next/swc-linux-x64-gnu": "12.2.2", + "@next/swc-linux-x64-musl": "12.2.2", + "@next/swc-win32-arm64-msvc": "12.2.2", + "@next/swc-win32-ia32-msvc": "12.2.2", + "@next/swc-win32-x64-msvc": "12.2.2", + "@swc/helpers": "0.4.2", + "caniuse-lite": "^1.0.30001332", + "postcss": "8.4.5", + "styled-jsx": "5.0.2", + "use-sync-external-store": "1.1.0" + } + }, + "node-releases": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" + }, + "object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "object.entries": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz", + "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + } + }, + "object.fromentries": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz", + "integrity": "sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + } + }, + "object.hasown": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.1.tgz", + "integrity": "sha512-LYLe4tivNQzq4JdaWW6WO3HMZZJWzkkH8fnI6EebWl0VZth2wL2Lovm74ep2/gZzlaTdV62JZHEqHQ2yVn8Q/A==", + "dev": true, + "requires": { + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" + } + }, + "object.values": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", + "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", + "dev": true + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "postcss": { + "version": "8.4.5", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz", + "integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==", + "requires": { + "nanoid": "^3.1.30", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.1" + } + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "requires": { + "loose-envify": "^1.1.0" + } + }, + "react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "requires": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + } + }, + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "react-redux": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.0.2.tgz", + "integrity": "sha512-nBwiscMw3NoP59NFCXFf02f8xdo+vSHT/uZ1ldDwF7XaTpzm+Phk97VT4urYBl5TYAPNVaFm12UHAEyzkpNzRA==", + "requires": { + "@babel/runtime": "^7.12.1", + "@types/hoist-non-react-statics": "^3.3.1", + "@types/use-sync-external-store": "^0.0.3", + "hoist-non-react-statics": "^3.3.2", + "react-is": "^18.0.0", + "use-sync-external-store": "^1.0.0" + }, + "dependencies": { + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + } + } + }, + "reduce-reducers": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/reduce-reducers/-/reduce-reducers-0.4.3.tgz", + "integrity": "sha512-+CNMnI8QhgVMtAt54uQs3kUxC3Sybpa7Y63HR14uGLgI9/QR5ggHvpxwhGGe3wmx5V91YwqQIblN9k5lspAmGw==" + }, + "redux": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.0.tgz", + "integrity": "sha512-oSBmcKKIuIR4ME29/AeNUnl5L+hvBq7OaJWzaptTQJAntaPvxIJqfnjbaEiCzzaIz+XmVILfqAM3Ob0aXLPfjA==", + "requires": { + "@babel/runtime": "^7.9.2" + } + }, + "redux-actions": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/redux-actions/-/redux-actions-2.6.5.tgz", + "integrity": "sha512-pFhEcWFTYNk7DhQgxMGnbsB1H2glqhQJRQrtPb96kD3hWiZRzXHwwmFPswg6V2MjraXRXWNmuP9P84tvdLAJmw==", + "requires": { + "invariant": "^2.2.4", + "just-curry-it": "^3.1.0", + "loose-envify": "^1.4.0", + "reduce-reducers": "^0.4.3", + "to-camel-case": "^1.0.0" + } + }, + "redux-flash": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/redux-flash/-/redux-flash-2.0.2.tgz", + "integrity": "sha512-tX8Yxf13uy2IVvQm5VpiGabirGySZhM9DZGzDsmU818px5bpmbUsxqCnUy/NtTmUEJnFuU+vL6IYejkbwHr/Dw==", + "requires": { + "prop-types": "^15.6.1", + "redux-actions": "^2.6.5", + "uuid": "^3.1.0" + } + }, + "redux-thunk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.1.tgz", + "integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==", + "requires": {} + }, + "regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "regenerate-unicode-properties": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", + "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", + "dev": true, + "requires": { + "regenerate": "^1.4.2" + } + }, + "regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + }, + "regenerator-transform": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz", + "integrity": "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==", + "dev": true, + "requires": { + "@babel/runtime": "^7.8.4" + } + }, + "regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + } + }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, + "regexpu-core": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.1.0.tgz", + "integrity": "sha512-bb6hk+xWd2PEOkj5It46A16zFMs2mv86Iwpdu94la4S3sJ7C973h2dHpYKwIBGaWSO7cIRJ+UX0IeMaWcO4qwA==", + "dev": true, + "requires": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.0.1", + "regjsgen": "^0.6.0", + "regjsparser": "^0.8.2", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.0.0" + } + }, + "regjsgen": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", + "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==", + "dev": true + }, + "regjsparser": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", + "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true + } + } + }, + "reselect": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.6.tgz", + "integrity": "sha512-ZovIuXqto7elwnxyXbBtCPo9YFEr3uJqj2rRbcOOog1bmu2Ag85M4hixSwFWyaBMKXNgvPaJ9OSu9SkBPIeJHQ==" + }, + "resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "requires": { + "loose-envify": "^1.1.0" + } + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==" + }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" + }, + "string.prototype.matchall": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz", + "integrity": "sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1", + "get-intrinsic": "^1.1.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.4.1", + "side-channel": "^1.0.4" + } + }, + "string.prototype.trimend": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", + "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" + } + }, + "string.prototype.trimstart": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", + "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "styled-jsx": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.2.tgz", + "integrity": "sha512-LqPQrbBh3egD57NBcHET4qcgshPks+yblyhPlH2GY8oaDgKs8SK4C3dBh3oSJjgzJ3G5t1SYEZGHkP+QEpX9EQ==", + "requires": {} + }, + "stylis": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.0.13.tgz", + "integrity": "sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "to-camel-case": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-camel-case/-/to-camel-case-1.0.0.tgz", + "integrity": "sha512-nD8pQi5H34kyu1QDMFjzEIYqk0xa9Alt6ZfrdEMuHCFOfTLhDG5pgTu/aAM9Wt9lXILwlXmWP43b8sav0GNE8Q==", + "requires": { + "to-space-case": "^1.0.0" + } + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" + }, + "to-no-case": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/to-no-case/-/to-no-case-1.0.2.tgz", + "integrity": "sha512-Z3g735FxuZY8rodxV4gH7LxClE4H0hTIyHNIHdk+vpQxjLm0cwnKXq/OFVZ76SOQmto7txVcwSCwkU5kqp+FKg==" + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "to-space-case": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-space-case/-/to-space-case-1.0.0.tgz", + "integrity": "sha512-rLdvwXZ39VOn1IxGL3V6ZstoTbwLRckQmn/U8ZDLuWwIXNpuZDhQ3AiRUlhTbOXFVE9C+dR51wM0CBDhk31VcA==", + "requires": { + "to-no-case": "^1.0.0" + } + }, + "tsconfig-paths": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", + "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", + "dev": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, + "typescript": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "dev": true + }, + "unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + } + }, + "unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "dev": true + }, + "unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "requires": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", + "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", + "dev": true + }, + "unicode-property-aliases-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", + "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==", + "dev": true + }, + "update-browserslist-db": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz", + "integrity": "sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q==", + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "use-sync-external-store": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.1.0.tgz", + "integrity": "sha512-SEnieB2FPKEVne66NpXPd1Np4R1lTNKfjuy3XdIoPQKYBAFdzbzSZlSn1KJZUiihQLQC5Znot4SBz1EOTBwQAQ==", + "requires": {} + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" + } + } +} diff --git a/app2/package.json b/app2/package.json new file mode 100644 index 000000000..4cb4fa0d9 --- /dev/null +++ b/app2/package.json @@ -0,0 +1,33 @@ +{ + "name": "app2", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "PORT=4000 next dev", + "build": "next build", + "start": "next start", + "lint": "next lint" + }, + "dependencies": { + "@emotion/react": "^11.9.3", + "@reduxjs/toolkit": "^1.8.3", + "@types/react-redux": "^7.1.24", + "next": "12.2.2", + "react": "18.2.0", + "react-dom": "18.2.0", + "react-redux": "^8.0.2", + "redux": "^4.2.0", + "redux-flash": "^2.0.2" + }, + "devDependencies": { + "@babel/core": "^7.18.9", + "@babel/preset-env": "^7.18.9", + "@types/node": "18.0.6", + "@types/react": "18.0.15", + "@types/react-dom": "18.0.6", + "eslint": "8.20.0", + "eslint-config-next": "12.2.2", + "typescript": "4.7.4" + }, + "types": "./types/*" +} diff --git a/app2/public/favicon.ico b/app2/public/favicon.ico new file mode 100755 index 000000000..718d6fea4 Binary files /dev/null and b/app2/public/favicon.ico differ diff --git a/app2/public/vercel.svg b/app2/public/vercel.svg new file mode 100755 index 000000000..fbf0e25a6 --- /dev/null +++ b/app2/public/vercel.svg @@ -0,0 +1,4 @@ + + + \ No newline at end of file diff --git a/app2/src/api/api.js b/app2/src/api/api.js new file mode 100644 index 000000000..a464fc186 --- /dev/null +++ b/app2/src/api/api.js @@ -0,0 +1,723 @@ +import jwtDecode from 'jwt-decode'; +import { parseFromTimeZone, convertToTimeZone } from 'date-fns-timezone'; +import { format } from 'date-fns'; + +export const UserRoleEnum = Object.freeze({ + GOVERNMENT_ADMIN: 'government_admin', + CAMPAIGN_ADMIN: 'campaign_admin', + CAMPAIGN_STAFF: 'campaign_staff', +}); + +export const ContributionTypeEnum = Object.freeze({ + CONTRIBUTION: 'contribution', + OTHER: 'other', +}); + +export const ContributionTypeFieldEnum = Object.freeze({ + CONTRIBUTION: 'Contribution', + OTHER: 'Other Receipt', +}); + +export const DataToContributionTypeFieldMap = new Map([ + [ContributionTypeEnum.CONTRIBUTION, ContributionTypeFieldEnum.CONTRIBUTION], + [ContributionTypeEnum.OTHER, ContributionTypeFieldEnum.OTHER], +]); + +export const ContributionTypeFieldToDataMap = new Map([ + [ContributionTypeFieldEnum.CONTRIBUTION, ContributionTypeEnum.CONTRIBUTION], + [ContributionTypeFieldEnum.OTHER, ContributionTypeEnum.OTHER], +]); + +export const ContributionSubTypeEnum = Object.freeze({ + CASH: 'cash', + INKIND_CONTRIBUTION: 'inkind_contribution', + INKIND_PAID_SUPERVISION: 'inkind_paid_supervision', + INKIND_FORGIVEN_ACCOUNT: 'inkind_forgiven_account', + INKIND_FORGIVEN_PERSONAL: 'inkind_forgiven_personal', + ITEM_SOLD_FAIR_MARKET: 'item_sold_fair_market', + ITEM_RETURNED_CHECK: 'item_returned_check', + ITEM_MISC: 'item_misc', + ITEM_REFUND: 'item_refund', +}); + +export const ContributionSubTypeFieldEnum = Object.freeze({ + ITEM_SOLD_FAIR_MARKET: 'Items Sold at Fair Market Value', + LOST_RETURNED_CHECK: 'Lost or Returned Check', + MISC_OTHER_RECEIPT: 'Miscellaneous Other Receipt', + REFUND_REBATES: 'Refunds and Rebates', + INKIND_CONTRIBUTION: 'In-Kind Contribution', + INKIND_FORGIVEN_ACCOUNT: 'In-Kind Forgiven Accounts Payable', + INKIND_FORGIVEN_PERSONAL: 'In-Kind /Forgiven Personal Expenditure', + CASH_CONTRIBUTION: 'Cash Contribution', +}); + +export const InKindDescriptionTypeEnum = Object.freeze({ + WAGES: 'wages', + BROADCAST: 'broadcast_advertising', + FUNDRAISING: 'fundraising_event_expenses', + GENERAL_OPERATING: 'general_operating_expenses', + PRINTING: 'printing', + MANAGEMENT: 'management', + NEWSPAPER: 'print_advertising', + OTHER_AD: 'other_advertising', + PETITION: 'petition_circulators', + POSTAGE: 'postage', + PREP_AD: 'preparation_of_advertising', + POLLING: 'surveys_and_polls', + TRAVEL: 'travel_expenses', + UTILITIES: 'utilities', +}); + +export const DataToContributionSubTypeFieldMap = new Map([ + [ + ContributionSubTypeEnum.CASH, + ContributionSubTypeFieldEnum.CASH_CONTRIBUTION, + ], + [ + ContributionSubTypeEnum.INKIND_CONTRIBUTION, + ContributionSubTypeFieldEnum.INKIND_CONTRIBUTION, + ], + [ + ContributionSubTypeEnum.INKIND_FORGIVEN_ACCOUNT, + ContributionSubTypeFieldEnum.INKIND_FORGIVEN_ACCOUNT, + ], + [ + ContributionSubTypeEnum.INKIND_FORGIVEN_PERSONAL, + ContributionSubTypeFieldEnum.INKIND_FORGIVEN_PERSONAL, + ], + [ + ContributionSubTypeEnum.ITEM_SOLD_FAIR_MARKET, + ContributionSubTypeFieldEnum.ITEM_SOLD_FAIR_MARKET, + ], + [ + ContributionSubTypeEnum.ITEM_RETURNED_CHECK, + ContributionSubTypeFieldEnum.LOST_RETURNED_CHECK, + ], + [ + ContributionSubTypeEnum.ITEM_MISC, + ContributionSubTypeFieldEnum.MISC_OTHER_RECEIPT, + ], + [ + ContributionSubTypeEnum.ITEM_REFUND, + ContributionSubTypeFieldEnum.REFUND_REBATES, + ], +]); + +export const ContributionSubTypeFieldToDataMap = new Map([ + [ + ContributionSubTypeFieldEnum.CASH_CONTRIBUTION, + ContributionSubTypeEnum.CASH, + ], + [ + ContributionSubTypeFieldEnum.INKIND_CONTRIBUTION, + ContributionSubTypeEnum.INKIND_CONTRIBUTION, + ], + [ + ContributionSubTypeFieldEnum.INKIND_FORGIVEN_ACCOUNT, + ContributionSubTypeEnum.INKIND_FORGIVEN_ACCOUNT, + ], + [ + ContributionSubTypeFieldEnum.INKIND_FORGIVEN_PERSONAL, + ContributionSubTypeEnum.INKIND_FORGIVEN_PERSONAL, + ], + [ + ContributionSubTypeFieldEnum.ITEM_SOLD_FAIR_MARKET, + ContributionSubTypeEnum.ITEM_SOLD_FAIR_MARKET, + ], + [ + ContributionSubTypeFieldEnum.LOST_RETURNED_CHECK, + ContributionSubTypeEnum.ITEM_RETURNED_CHECK, + ], + [ + ContributionSubTypeFieldEnum.MISC_OTHER_RECEIPT, + ContributionSubTypeEnum.ITEM_MISC, + ], + [ + ContributionSubTypeFieldEnum.REFUND_REBATES, + ContributionSubTypeEnum.ITEM_REFUND, + ], +]); + +export const ContributorTypeEnum = Object.freeze({ + INDIVIDUAL: 'individual', + BUSINESS: 'business', + FAMILY: 'family', + LABOR: 'labor', + POLITICAL_COMMITTEE: 'political_committee', + POLITICAL_PARTY: 'political_party', + UNREGISTERED: 'unregistered', + OTHER: 'other', +}); + +export const ContributorTypeFieldEnum = Object.freeze({ + BUSINESS_ENTITY: 'Business Entity', + LABOR_ORGANIZATION: 'Labor Organization', + POLITICAL_COMMITTEE: 'Political Committee', + POLITICAL_PARTY_COMMITEE: 'Political Party Committee', + UNREGISTERED_COMMITTEE: 'Unregistered Committee', + INDIVIDUAL: 'Individual', + CANDIDATE_IMMEDIATE_FAMILY: 'Candidate’s Immediate Family', + OTHER: 'Other', +}); + +export const DataToContributorTypeFieldMap = new Map([ + [ContributorTypeEnum.INDIVIDUAL, ContributorTypeFieldEnum.INDIVIDUAL], + [ContributorTypeEnum.BUSINESS, ContributorTypeFieldEnum.BUSINESS_ENTITY], + [ + ContributorTypeEnum.FAMILY, + ContributorTypeFieldEnum.CANDIDATE_IMMEDIATE_FAMILY, + ], + [ContributorTypeEnum.LABOR, ContributorTypeFieldEnum.LABOR_ORGANIZATION], + [ + ContributorTypeEnum.POLITICAL_COMMITTEE, + ContributorTypeFieldEnum.POLITICAL_COMMITTEE, + ], + [ + ContributorTypeEnum.POLITICAL_PARTY, + ContributorTypeFieldEnum.POLITICAL_PARTY_COMMITEE, + ], + [ + ContributorTypeEnum.UNREGISTERED, + ContributorTypeFieldEnum.UNREGISTERED_COMMITTEE, + ], + [ContributorTypeEnum.OTHER, ContributorTypeFieldEnum.OTHER], +]); + +export const ContributorTypeFieldToDataMap = new Map([ + [ContributorTypeFieldEnum.INDIVIDUAL, ContributorTypeEnum.INDIVIDUAL], + [ContributorTypeFieldEnum.BUSINESS_ENTITY, ContributorTypeEnum.BUSINESS], + [ + ContributorTypeFieldEnum.CANDIDATE_IMMEDIATE_FAMILY, + ContributorTypeEnum.FAMILY, + ], + [ContributorTypeFieldEnum.LABOR_ORGANIZATION, ContributorTypeEnum.LABOR], + [ + ContributorTypeFieldEnum.POLITICAL_COMMITTEE, + ContributorTypeEnum.POLITICAL_COMMITTEE, + ], + [ + ContributorTypeFieldEnum.POLITICAL_PARTY_COMMITEE, + ContributorTypeEnum.POLITICAL_PARTY, + ], + [ + ContributorTypeFieldEnum.UNREGISTERED_COMMITTEE, + ContributorTypeEnum.UNREGISTERED, + ], + [ContributorTypeFieldEnum.OTHER, ContributorTypeEnum.OTHER], +]); + +export const OaeTypeEnum = Object.freeze({ + SEED_MONEY: 'seed', + MATCHABLE: 'matchable', + PUBLIC_MATCHING_CONTRIBUTION: 'public_matching_contribution', + QUALIFYING: 'qualifying', + ALLOWABLE: 'allowable', + INKIND: 'inkind', + OTHER: 'other', +}); + +export const OaeTypeFieldEnum = Object.freeze({ + SEED_MONEY: 'Seed Money', + MATCHABLE: 'Matchable', + PUBLIC_MATCHING_CONTRIBUTION: 'Public Matching Contribution', + QUALIFYING: 'Qualifying', + ALLOWABLE: 'Allowable', + INKIND: 'In-Kind', + OTHER: 'Other', +}); + +export const DataToOaeTypeTypeFieldMap = new Map([ + [OaeTypeEnum.SEED_MONEY, OaeTypeFieldEnum.SEED_MONEY], + [OaeTypeEnum.MATCHABLE, OaeTypeFieldEnum.MATCHABLE], + [ + OaeTypeEnum.PUBLIC_MATCHING_CONTRIBUTION, + OaeTypeFieldEnum.PUBLIC_MATCHING_CONTRIBUTION, + ], + [OaeTypeEnum.QUALIFYING, OaeTypeFieldEnum.QUALIFYING], + [OaeTypeEnum.ALLOWABLE, OaeTypeFieldEnum.ALLOWABLE], + [OaeTypeEnum.INKIND, OaeTypeFieldEnum.INKIND], + [OaeTypeEnum.OTHER, OaeTypeFieldEnum.OTHER], +]); + +export const OaeTypeFieldToDataMap = new Map([ + [OaeTypeFieldEnum.SEED_MONEY, OaeTypeEnum.SEED_MONEY], + [OaeTypeFieldEnum.MATCHABLE, OaeTypeEnum.MATCHABLE], + [ + OaeTypeFieldEnum.PUBLIC_MATCHING_CONTRIBUTION, + OaeTypeEnum.PUBLIC_MATCHING_CONTRIBUTION, + ], + [OaeTypeFieldEnum.QUALIFYING, OaeTypeEnum.QUALIFYING], + [OaeTypeFieldEnum.ALLOWABLE, OaeTypeEnum.ALLOWABLE], + [OaeTypeFieldEnum.INKIND, OaeTypeEnum.INKIND], +]); + +export const PhoneTypeEnum = Object.freeze({ + MOBILE: 'Mobile', + WORK: 'Work', + HOME: 'Home', +}); + +export const PhoneTypeFieldEnum = Object.freeze({ + MOBILE_PHONE: 'Mobile Phone', + WORK_PHONE: 'Work Phone', + HOME_PHONE: 'Home Phone', +}); + +export const PaymentMethodEnum = Object.freeze({ + CASH: 'cash', + CHECK: 'check', + MONEY_ORDER: 'money_order', + CREDIT_CARD_ONLINE: 'credit_card_online', + CREDIT_CARD_PAPER: 'credit_card_paper', + ETF: 'electronic_funds_transfer', + DEBIT: 'debit', +}); + +export const DataToPhoneTypeFieldMap = new Map([ + [PhoneTypeEnum.MOBILE, PhoneTypeFieldEnum.MOBILE_PHONE], + [PhoneTypeEnum.WORK, PhoneTypeFieldEnum.WORK_PHONE], + [PhoneTypeEnum.HOME, PhoneTypeFieldEnum.HOME_PHONE], +]); + +export const PhoneTypeFieldToDataMap = new Map([ + [PhoneTypeFieldEnum.MOBILE_PHONE, PhoneTypeEnum.MOBILE], + [PhoneTypeFieldEnum.HOME_PHONE, PhoneTypeEnum.HOME_PHONE], + [PhoneTypeFieldEnum.WORK_PHONE, PhoneTypeEnum.WORK], +]); + +export const ContributionStatusEnum = Object.freeze({ + ARCHIVED: 'Archived', + DRAFT: 'Draft', + SUBMITTED: 'Submitted', + PROCESSED: 'Processed', + AWAITING: 'Awaiting', +}); + +export const ExpenditureTypeEnum = Object.freeze({ + EXPENDITURE: 'expenditure', + OTHER: 'other', + OTHER_DISBURSEMENT: 'other_disbursement', +}); + +export const ExpenditureSubTypeEnum = Object.freeze({ + ACCOUNTS_PAYABLE: 'accounts_payable', + CASH_EXPENDITURE: 'cash_expenditure', + PERSONAL_EXPENDITURE: 'personal_expenditure', + ACCOUNTS_PAYABLE_RESCINDED: 'accounts_payable_rescinded', + CASH_BALANCE_ADJUSTMENT: 'cash_balance_adjustment', + MISCELLANEOUS_OTHER_DISBURSEMENT: 'miscellaneous_other_disbursement', + REFUND_OF_CONTRIBUTION: 'refund_of_expenditure', +}); + +export const PayeeTypeEnum = Object.freeze({ + INDIVIDUAL: 'individual', + BUSINESS: 'business', + FAMILY: 'family', + LABOR: 'labor', + POLITICAL_COMMITTEE: 'political_committee', + POLITICAL_PARTY: 'political_party', + UNREGISTERED: 'unregistered', + OTHER: 'other', +}); + +export const ExpenditureStatusEnum = Object.freeze({ + ARCHIVED: 'archived', + DRAFT: 'draft', + SUBMITTED: 'submitted', + OUT_OF_COMPLIANCE: 'out_of_compliance', + IN_COMPLIANCE: 'in_compliance', +}); + +export const PurposeTypeEnum = Object.freeze({ + WAGES: 'wages', + CASH: 'cash_contribution', + REIMBURSEMENT: 'personal_reimbursement', + BROADCAST: 'broadcast_advertising', + FUNDRAISING: 'fundraising_event_expenses', + GENERAL_OPERATING: 'general_operating_expenses', + PRIMTING: 'printing', + MANAGEMENT: 'management', + NEWSPAPER: 'print_advertising', + OTHER_AD: 'other_advertising', + PETITION: 'petition_circulators', + POSTAGE: 'postage', + PREP_AD: 'preparation_of_advertising', + POLLING: 'surveys_and_polls', + TRAVEL: 'travel_expenses', + UTILITIES: 'utilities', +}); + +export function post(url, data) { + const headers = { + 'Content-Type': 'application/json', + Accept: 'application/json', + }; + + if (data.format === 'csv') { + headers.Accept = 'text/csv'; + } + + if (process.env.NODE_ENV === 'test' && !!process.env.TOKEN) { + headers.Cookie = `token=${process.env.TOKEN}`; + } + return fetch(url, { + method: 'POST', + headers, + body: JSON.stringify(data), + credentials: 'include', + }); +} + +export function deleteRequest(url) { + const headers = { + 'Content-Type': 'application/json', + Accept: 'application/json', + }; + if (process.env.NODE_ENV === 'test' && !!process.env.TOKEN) { + headers.Cookie = `token=${process.env.TOKEN}`; + } + return fetch(url, { + method: 'DELETE', + headers, + credentials: 'include', + }); +} + +export function get(url) { + const headers = { + 'Content-Type': 'application/json', + Accept: 'application/json', + }; + if (process.env.NODE_ENV === 'test' && !!process.env.TOKEN) { + headers.Cookie = `token=${process.env.TOKEN}`; + } + return fetch(url, { + method: 'GET', + headers, + credentials: 'include', + }); +} + +export function put(url, data) { + const headers = { + 'Content-Type': 'application/json', + Accept: 'application/json', + }; + if (process.env.NODE_ENV === 'test' && !!process.env.TOKEN) { + headers.Cookie = `token=${process.env.TOKEN}`; + } + return fetch(url, { + method: 'PUT', + headers, + body: JSON.stringify(data), + credentials: 'include', + }); +} + +export function decodeToken(token) { + return jwtDecode(token); +} + +export function baseUrl(isDataVisualizationRequest = false) { + if (process.env.NODE_ENV === 'test') { + return 'http://localhost:3000'; + } + + if (window && window.location.hostname.includes('qa')) { + return 'https://api-qa.openelectionsportland.org'; + } + + if (process.env.NODE_ENV === 'development' && !isDataVisualizationRequest) { + return 'http://localhost:3000'; + } + + return 'https://api.openelectionsportland.org'; +} + +// returns the jwt session token +export function login(email, password) { + return post(`${baseUrl()}/users/login`, { email, password }); +} + +// returns the jwt session token +export function me() { + return get(`${baseUrl()}/me`).then(response => response.json()); +} + +export function dateToPickerFormat(date) { + return date !== null && date !== '' + ? format( + parseFromTimeZone(date, { + timeZone: 'America/Los_Angeles', + }), + 'yyyy-MM-dd' + ) + : ''; +} + +export function dateToMicroTime(formatedDate) { + return new Date( + convertToTimeZone(formatedDate, { + timeZone: 'America/Los_Angeles', + }) + ).getTime(); +} + +export function inviteUsertoGovernment( + email, + firstName, + lastName, + governmentId +) { + return post(`${baseUrl()}/users/invite`, { + email, + firstName, + lastName, + governmentId, + role: UserRoleEnum.GOVERNMENT_ADMIN, + }); +} + +export function inviteUsertoCampaign( + email, + firstName, + lastName, + campaignId, + role +) { + return post(`${baseUrl()}/users/invite`, { + email, + firstName, + lastName, + campaignId, + role, + }); +} + +export function resendInvite(userId) { + return post(`${baseUrl()}/users/resend-invite`, { userId }); +} + +export function removePermission(permissionId) { + return deleteRequest(`${baseUrl()}/permissions/${permissionId}`); +} + +export function redeemInvite(invitationCode, password, firstName, lastName) { + const data = { + invitationCode, + password, + firstName, + lastName, + }; + + return post(`${baseUrl()}/users/redeem-invite`, data); +} + +export function getCampaignUsers(campaignId) { + return post(`${baseUrl()}/users`, { campaignId }).then(response => + response.json() + ); +} + +export function getGovernmentUsers(governmentId) { + return post(`${baseUrl()}/users`, { governmentId }).then(response => + response.json() + ); +} + +// path: '/users/send-password-reset-email', +// method: 'post', +export function sendPasswordResetEmail(email) { + return post(`${baseUrl()}/users/send-password-reset-email`, { email }); +} + +// path: '/users/reset-password', +// method: 'post', +export function resetPassword(invitationCode, password) { + return post(`${baseUrl()}/users/reset-password`, { + invitationCode, + password, + }); +} + +// path: '/users/password', +// method: 'put', +export function updatePassword(currentPassword, newPassword) { + return put(`${baseUrl()}/users/password`, { currentPassword, newPassword }); +} + +// path: '/activities', +// method: 'post', +export function getCampaignActivities(activitiesAttrs) { + return post(`${baseUrl()}/activities`, activitiesAttrs).then(response => + response.json() + ); +} + +export function getGovernmentActivities(activitiesAttrs) { + return post(`${baseUrl()}/activities`, activitiesAttrs).then(response => + response.json() + ); +} + +export function getContributionActivities(activitiesAttrs) { + return post(`${baseUrl()}/activities`, activitiesAttrs).then(response => + response.json() + ); +} + +export function getExpenditureActivities(activitiesAttrs) { + return post(`${baseUrl()}/activities`, activitiesAttrs).then(response => + response.json() + ); +} + +// path: '/campaigns', +// method: 'post', +export function getCampaignsForGovernment(governmentId) { + return post(`${baseUrl()}/campaigns`, { governmentId }).then(response => + response.json() + ); +} + +// path: '/campaigns/new', +// method: 'post', +export function createCampaignForGovernment(campaignAttrs) { + return post(`${baseUrl()}/campaigns/new`, campaignAttrs); +} + +// path: '/campaigns/update', +// method: 'post', +export function updateCampaignNameForGovernment(campaignAttrs) { + return post(`${baseUrl()}/campaigns/update`, campaignAttrs).then(response => + response.json() + ); +} + +// path: '/contributions/:id' +// method: 'put', +export function updateContribution(contributionAttrs) { + return put( + `${baseUrl()}/contributions/${contributionAttrs.id}`, + contributionAttrs + ); +} + +// path: '/contributions/new', +// method: 'post', +export function createContribution(contributionAttrs) { + return post(`${baseUrl()}/contributions/new`, contributionAttrs); +} + +// path: '/contributions', +// method: 'post', +export function getContributions(contributionSearchAttrs) { + return post(`${baseUrl()}/contributions`, contributionSearchAttrs); +} + +// path: '/contributions/:id/comments', +// method: 'post', +export function postContributionComment(contributionId, comment, attachment) { + const formData = new FormData(); + if (attachment) { + formData.append('attachment', attachment); + } + formData.append('comment', comment); + return fetch(`${baseUrl()}/contributions/${contributionId}/comments`, { + method: 'POST', + body: formData, + credentials: 'include', + }); +} + +// path: '/contributions/{id}', +// method: 'post', +export function getContributionById(id) { + return get(`${baseUrl()}/contributions/${id}`); +} + +// path: '/contributions/{id}', +// method: 'delete', +export function archiveContribution(id) { + return deleteRequest(`${baseUrl()}/contributions/${id}`); +} + +// path: '/expenditures/new', +// method: 'post', +export function createExpenditure(expenditureAttrs) { + return post(`${baseUrl()}/expenditures/new`, expenditureAttrs); +} + +// path: '/expenditures/:id/comments', +// method: 'post', +export function postExpenditureComment(expenditureId, comment, attachment) { + const formData = new FormData(); + if (attachment) { + formData.append('attachment', attachment); + } + formData.append('comment', comment); + return fetch(`${baseUrl()}/expenditures/${expenditureId}/comments`, { + method: 'POST', + body: formData, + credentials: 'include', + }); +} + +// path: '/expenditures', +// method: 'post', +export function getExpenditures(expenditureSearchAttrs) { + return post(`${baseUrl()}/expenditures`, expenditureSearchAttrs); +} + +// path: '/expenditures/:id', +// method: 'get', +export function getExpenditureById(id) { + return get(`${baseUrl()}/expenditures/${id}`); +} + +// path: '/expenditures/:id' +// method: 'put', +export function updateExpenditure(expenditureAttrs) { + return put( + `${baseUrl()}/expenditures/${expenditureAttrs.id}`, + expenditureAttrs + ); +} + +// path: '/summary' +// method: 'post', +// summaryArttrs = {governmentId: integer OR campaignId: integer} +export function getStatusSummary(summaryAttrs) { + return post(`${baseUrl()}/summary`, summaryAttrs); +} + +// path '/matches/:id' +// method: 'get' +export function getMatchesByContributionId(id) { + return get(`${baseUrl()}/matches/${id}`); +} + +/* +path '/matches' +method: 'post' +@attrs { +contributionId: number, +matchId: string, +matchStrength: enum[exact, strong, weak, none] + } + */ +export function updateMatchForContribution(attrs) { + return post(`${baseUrl()}/matches`, attrs); +} + +export function getContributionGeoData() { + return get(`${baseUrl(true)}/contributionsgeo`).then(response => + response.json() + ); +} + +export function getExternalContributionGeoData() { + return get(`${baseUrl()}/external-contributionsgeo`).then(response => + response.json() + ); +} diff --git a/app2/src/api/api.test.js b/app2/src/api/api.test.js new file mode 100644 index 000000000..c53b32ee5 --- /dev/null +++ b/app2/src/api/api.test.js @@ -0,0 +1,562 @@ +import * as api from './api'; + +let govAdminToken; +let campaignAdminToken; +let campaignStaffToken; +let governmentId; +let campaignId; +let campaignStaffId; +let campaignAdminId; + +describe('API', () => { + beforeAll(async () => { + let tokenResponse = await api.login( + 'govadmin@openelectionsportland.org', + 'password' + ); + govAdminToken = tokenResponse.headers + .get('set-cookie') + .match(/=([a-zA-Z0-9].+); Path/)[1]; + let decodedToken = api.decodeToken(govAdminToken); + governmentId = decodedToken.permissions[0].governmentId; + + tokenResponse = await api.login( + 'campaignadmin@openelectionsportland.org', + 'password' + ); + + campaignAdminToken = tokenResponse.headers + .get('set-cookie') + .match(/=([a-zA-Z0-9].+); Path/)[1]; + decodedToken = api.decodeToken(campaignAdminToken); + campaignId = decodedToken.permissions[0].campaignId; + campaignAdminId = decodedToken.id; + + tokenResponse = await api.login( + 'campaignstaff@openelectionsportland.org', + 'password' + ); + campaignStaffToken = tokenResponse.headers + .get('set-cookie') + .match(/=([a-zA-Z0-9].+); Path/)[1]; + decodedToken = api.decodeToken(campaignStaffToken); + campaignStaffId = decodedToken.id; + }); + + beforeEach(() => { + delete process.env.TOKEN; + }); + + it('decodeToken', () => { + const decoded = api.decodeToken( + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MzEwOSwiZXhwIjoxNTU4NTQ2OTE5OTk5LCJmaXJzdE5hbWUiOiJHb3Zlcm5tZW50IiwibGFzdE5hbWUiOiJBZG1pbiIsImVtYWlsIjoiZ292YWRtaW5Ab3BlbmVsZWN0aW9uc3BvcnRsYW5kLm9yZyIsInBlcm1pc3Npb25zIjpbeyJyb2xlIjoiZ292ZXJubWVudF9hZG1pbiIsInR5cGUiOiJnb3Zlcm5tZW50IiwiaWQiOjI0MTF9XSwiaWF0IjoxNTU4Mjg3NzE5fQ.qdSVIWO8yJ0ZR73MUGfyW1TQDOrhfcaOBEOTvEK_dUs' + ); + expect(decoded.email).toEqual('govadmin@openelectionsportland.org'); + expect(decoded.firstName).toEqual('Government'); + expect(decoded.lastName).toEqual('Admin'); + expect(decoded.permissions.length).toEqual(1); + expect(decoded.permissions[0].role).toEqual('government_admin'); + expect(decoded.permissions[0].type).toEqual('government'); + }); + + it('login govadmin success', async () => { + const response = await api.login( + 'govadmin@openelectionsportland.org', + 'password' + ); + govAdminToken = response.headers + .get('set-cookie') + .match(/=([a-zA-Z0-9].+); Path/)[1]; + expect(govAdminToken).toBeDefined(); + }); + + it('login campaignadmin success', async () => { + const response = await api.login( + 'campaignadmin@openelectionsportland.org', + 'password' + ); + campaignAdminToken = response.headers + .get('set-cookie') + .match(/=([a-zA-Z0-9].+); Path/)[1]; + expect(campaignAdminToken).toBeDefined(); + }); + + it('login campaignstaff success1', async () => { + const response = await api.login( + 'campaignstaff@openelectionsportland.org', + 'password' + ); + campaignStaffToken = response.headers + .get('set-cookie') + .match(/=([a-zA-Z0-9].+); Path/)[1]; + expect(campaignStaffToken).toBeDefined(); + }); + + it('login fail', async () => { + const response = await api.login( + 'govadmin@openelectionsportland.org', + 'password1' + ); + expect(response.status).toEqual(401); + }); + + it('me', async () => { + process.env.TOKEN = govAdminToken; + const response = await api.me(); + expect(response.email).toEqual('govadmin@openelectionsportland.org'); + expect(response.firstName).toEqual('Government'); + expect(response.lastName).toEqual('Admin'); + expect(response.permissions.length).toEqual(1); + expect(response.permissions[0].role).toEqual('government_admin'); + expect(response.permissions[0].type).toEqual('government'); + governmentId = response.permissions[0].id; + process.env.TOKEN = null; + }); + + it('inviteUsertoGovernment', async () => { + process.env.TOKEN = govAdminToken; + const response = await api.inviteUsertoGovernment( + 'govadmin1@openelectionsportland.org', + 'Government2', + 'Admin2', + governmentId + ); + expect(response.status).toEqual(201); + process.env.TOKEN = null; + }); + + it('inviteUsertoCampaign as govAdmin', async () => { + process.env.TOKEN = govAdminToken; + const response = await api.inviteUsertoCampaign( + 'campaignadmin1@openelectionsportland.org', + 'Government2', + 'Admin2', + campaignId, + api.UserRoleEnum.CAMPAIGN_STAFF + ); + expect(response.status).toEqual(201); + process.env.TOKEN = null; + }); + + it('inviteUsertoCampaign as campaignAdmin', async () => { + process.env.TOKEN = campaignAdminToken; + const response = await api.inviteUsertoCampaign( + 'campaignadmin2@openelectionsportland.org', + 'Government2', + 'Admin2', + campaignId, + api.UserRoleEnum.CAMPAIGN_ADMIN + ); + expect(response.status).toEqual(201); + process.env.TOKEN = null; + }); + + it('redeemInvite', async () => { + const response = await api.redeemInvite('inviteme', 'password'); + expect(response.status).toEqual(204); + }); + + it('getCampaignUsers', async () => { + process.env.TOKEN = campaignAdminToken; + const response = await api.getCampaignUsers(campaignId); + expect(response.length > 1).toBeTruthy(); + process.env.TOKEN = null; + }); + + it('getGovernmentUsers', async () => { + process.env.TOKEN = govAdminToken; + const response = await api.getGovernmentUsers(governmentId); + expect(response.length > 1).toBeTruthy(); + }); + + it('sendPasswordResetEmail', async () => { + const response = await api.sendPasswordResetEmail( + 'campaignstaff@openelectionsportland.org' + ); + expect(response.status).toEqual(204); + }); + + it('resetPassword', async () => { + const response = await api.resetPassword('resetme', 'newpassword'); + + expect(response.status).toEqual(204); + }); + + it('updatePassword', async () => { + process.env.TOKEN = govAdminToken; + const response = await api.updatePassword('password', 'newpassword'); + expect(response.status).toEqual(204); + }); + + it('createCampaignForGovernment', async () => { + process.env.TOKEN = govAdminToken; + const response = await api.createCampaignForGovernment({ + governmentId, + name: 'Test for Mayor', + officeSought: 'Mayor', + }); + expect(response.status).toEqual(201); + }); + + it('getCampaignsForGovernment', async () => { + process.env.TOKEN = govAdminToken; + const response = await api.getCampaignsForGovernment(governmentId); + expect(response.length > 1).toBeTruthy(); + }); + + it('getGovernmentActivities', async () => { + process.env.TOKEN = govAdminToken; + const response = await api.getGovernmentActivities({ governmentId }); + expect(response.data.length > 1).toBeTruthy(); + }); + + it('getCampaignActivities', async () => { + process.env.TOKEN = campaignAdminToken; + const response = await api.getCampaignActivities({ campaignId }); + expect(response.data.length > 1).toBeTruthy(); + }); + + it('createContribution', async () => { + process.env.TOKEN = campaignStaffToken; + const response = await api.createContribution({ + address1: '123 ABC ST', + amount: 250, + campaignId, + city: 'Portland', + currentUserId: campaignStaffId, + date: 1562436237619, + firstName: 'John', + middleInitial: '', + lastName: 'Doe', + governmentId, + type: api.ContributionTypeEnum.CONTRIBUTION, + subType: api.ContributionSubTypeEnum.CASH, + paymentMethod: api.PaymentMethodEnum.CASH, + state: 'OR', + status: api.ContributionStatusEnum.DRAFT, + zip: '97214', + contributorType: api.ContributorTypeEnum.INDIVIDUAL, + }); + expect(response.status).toEqual(201); + }); + + it('getContributionActivities', async () => { + process.env.TOKEN = campaignAdminToken; + let contribution = await api.createContribution({ + address1: '123 ABC ST', + amount: 250, + campaignId, + city: 'Portland', + currentUserId: campaignStaffId, + date: 1562436237700, + firstName: 'John', + middleInitial: '', + lastName: 'Doe', + governmentId, + type: api.ContributionTypeEnum.CONTRIBUTION, + subType: api.ContributionSubTypeEnum.CASH, + paymentMethod: api.PaymentMethodEnum.CASH, + state: 'OR', + status: api.ContributionStatusEnum.DRAFT, + zip: '97214', + contributorType: api.ContributorTypeEnum.INDIVIDUAL, + }); + contribution = await contribution.json(); + + const response = await api.getContributionActivities({ + contributionId: contribution.id, + }); + expect(response.data.length >= 1).toBeTruthy(); + }); + + it('updateContribution', async () => { + process.env.TOKEN = campaignStaffToken; + + let response = await api.createContribution({ + address1: '123 ABC ST', + amount: 250, + campaignId, + city: 'Portland', + currentUserId: campaignAdminId, + date: 1562436237619, + firstName: 'John', + middleInitial: '', + lastName: 'Doe', + governmentId, + type: api.ContributionTypeEnum.CONTRIBUTION, + subType: api.ContributionSubTypeEnum.CASH, + paymentMethod: api.PaymentMethodEnum.CASH, + state: 'OR', + status: api.ContributionStatusEnum.DRAFT, + zip: '97214', + contributorType: api.ContributorTypeEnum.INDIVIDUAL, + }); + const contribution = await response.json(); + + response = await api.updateContribution({ + id: contribution.id, + firstName: 'Ian', + currentUserId: campaignStaffId, + }); + expect(response.status).toEqual(204); + }); + + it('getContributions', async () => { + process.env.TOKEN = campaignStaffToken; + const response = await api.getContributions({ + governmentId, + campaignId, + currentUserId: campaignAdminId, + }); + expect(response.status).toEqual(200); + }); + + it('getContributionById', async () => { + process.env.TOKEN = campaignStaffToken; + const contribution = await api.createContribution({ + address1: '123 ABC ST', + amount: 250, + campaignId, + city: 'Portland', + currentUserId: campaignStaffId, + date: 1562436237619, + firstName: 'John', + middleInitial: '', + lastName: 'Doe', + governmentId, + type: api.ContributionTypeEnum.CONTRIBUTION, + subType: api.ContributionSubTypeEnum.CASH, + paymentMethod: api.PaymentMethodEnum.CASH, + state: 'OR', + status: api.ContributionStatusEnum.DRAFT, + zip: '97214', + contributorType: api.ContributorTypeEnum.INDIVIDUAL, + }); + const { id } = await contribution.json(); + const response = await api.getContributionById(id); + expect(response.status).toEqual(200); + }); + + it('removePermission', async () => { + process.env.TOKEN = campaignAdminToken; + const tokenResponse = await api.login( + 'campaignstaff+removeme@openelectionsportland.org', + 'password' + ); + + const token = tokenResponse.headers + .get('set-cookie') + .match(/=([a-zA-Z0-9].+); Path/)[1]; + + const user = api.decodeToken(token); + + const permissionId = user.permissions[0].id; + const response = await api.removePermission(permissionId); + expect(response.status).toEqual(200); + }); + + it('archiveContribution', async () => { + process.env.TOKEN = campaignStaffToken; + let contribution = await api.createContribution({ + address1: '123 ABC ST', + amount: 250, + campaignId, + city: 'Portland', + currentUserId: campaignStaffId, + date: 1562436237700, + firstName: 'John', + middleInitial: '', + lastName: 'Doe', + governmentId, + type: api.ContributionTypeEnum.CONTRIBUTION, + subType: api.ContributionSubTypeEnum.CASH, + paymentMethod: api.PaymentMethodEnum.CASH, + state: 'OR', + status: api.ContributionStatusEnum.DRAFT, + zip: '97214', + contributorType: api.ContributorTypeEnum.INDIVIDUAL, + }); + contribution = await contribution.json(); + + let response = await api.archiveContribution(contribution.id); + expect(response.status).toEqual(200); + response = await api.getContributionById(contribution.id); + contribution = await response.json(); + expect(contribution.status).toEqual(api.ContributionStatusEnum.ARCHIVED); + }); + + it('createExpenditure', async () => { + process.env.TOKEN = campaignStaffToken; + const response = await api.createExpenditure({ + address1: '123 ABC ST', + amount: 250, + campaignId, + city: 'Portland', + currentUserId: campaignStaffId, + date: 1562436237700, + governmentId, + type: api.ExpenditureTypeEnum.EXPENDITURE, + subType: api.ExpenditureSubTypeEnum.CASH_EXPENDITURE, + state: 'OR', + status: api.ExpenditureStatusEnum.DRAFT, + zip: '97214', + payeeType: api.PayeeTypeEnum.INDIVIDUAL, + name: 'Test Expenditure', + description: 'This is a test', + }); + expect(response.status).toEqual(201); + }); + + it('getExpenditures', async () => { + process.env.TOKEN = campaignStaffToken; + const response = await api.getExpenditures({ + governmentId, + campaignId, + currentUserId: campaignStaffId, + }); + expect(response.status).toEqual(200); + }); + + it('updateExpenditure', async () => { + process.env.TOKEN = campaignStaffToken; + + let response = await api.createExpenditure({ + address1: '123 ABC ST', + amount: 250, + campaignId, + city: 'Portland', + currentUserId: campaignStaffId, + date: 1562436237700, + governmentId, + type: api.ExpenditureTypeEnum.EXPENDITURE, + subType: api.ExpenditureSubTypeEnum.CASH_EXPENDITURE, + state: 'OR', + status: api.ExpenditureStatusEnum.DRAFT, + zip: '97214', + payeeType: api.PayeeTypeEnum.INDIVIDUAL, + name: 'Test Expenditure', + description: 'This is an update test', + }); + const expenditure = await response.json(); + + response = await api.updateExpenditure({ + id: expenditure.id, + amount: 500, + currentUserId: campaignStaffId, + }); + expect(response.status).toEqual(204); + }); + + it('getExpenditureActivities', async () => { + process.env.TOKEN = campaignStaffToken; + + let response = await api.createExpenditure({ + address1: '123 ABC ST', + amount: 250, + campaignId, + city: 'Portland', + currentUserId: campaignStaffId, + date: 1562436237700, + governmentId, + type: api.ExpenditureTypeEnum.EXPENDITURE, + subType: api.ExpenditureSubTypeEnum.CASH_EXPENDITURE, + state: 'OR', + status: api.ExpenditureStatusEnum.DRAFT, + zip: '97214', + payeeType: api.PayeeTypeEnum.INDIVIDUAL, + name: 'Test Expenditure', + description: 'This is an update test', + }); + const expenditure = await response.json(); + + response = await api.getExpenditureActivities({ + expenditureId: expenditure.id, + }); + expect(response.data.length >= 1).toBeTruthy(); + }); + + xit('postExpenditureComment', async () => { + process.env.TOKEN = campaignStaffToken; + + let response = await api.createExpenditure({ + address1: '123 ABC ST', + amount: 250, + campaignId, + city: 'Portland', + currentUserId: campaignStaffId, + date: 1562436237700, + governmentId, + type: api.ExpenditureTypeEnum.EXPENDITURE, + subType: api.ExpenditureSubTypeEnum.CASH_EXPENDITURE, + state: 'OR', + status: api.ExpenditureStatusEnum.DRAFT, + zip: '97214', + payeeType: api.PayeeTypeEnum.INDIVIDUAL, + name: 'Test Expenditure', + description: 'This is an update test', + }); + const expenditure = await response.json(); + + response = await api.postExpenditureComment( + expenditure.id, + 'This is a comment' + ); + expect(response.status).toEqual(204); + }); + + it('getExpenditure', async () => { + process.env.TOKEN = campaignStaffToken; + + let response = await api.createExpenditure({ + address1: '123 ABC ST', + amount: 250, + campaignId, + city: 'Portland', + currentUserId: campaignStaffId, + date: 1562436237700, + governmentId, + type: api.ExpenditureTypeEnum.EXPENDITURE, + subType: api.ExpenditureSubTypeEnum.CASH_EXPENDITURE, + state: 'OR', + status: api.ExpenditureStatusEnum.DRAFT, + zip: '97214', + payeeType: api.PayeeTypeEnum.INDIVIDUAL, + name: 'Test Expenditure', + description: 'This is an update test', + }); + const expenditure = await response.json(); + + response = await api.getExpenditureById(expenditure.id); + expect(response.status).toEqual(200); + }); + + xit('postContributionComment', async () => { + process.env.TOKEN = campaignStaffToken; + let contribution = await api.createContribution({ + address1: '123 ABC ST', + amount: 250, + campaignId, + city: 'Portland', + currentUserId: campaignStaffId, + date: 1562436237700, + firstName: 'John', + middleInitial: '', + lastName: 'Doe', + governmentId, + type: api.ContributionTypeEnum.CONTRIBUTION, + subType: api.ContributionSubTypeEnum.CASH, + paymentMethod: api.PaymentMethodEnum.CASH, + state: 'OR', + status: api.ContributionStatusEnum.DRAFT, + zip: '97214', + contributorType: api.ContributorTypeEnum.INDIVIDUAL, + }); + contribution = await contribution.json(); + + const response = await api.postContributionComment( + contribution.id, + 'This is a comment' + ); + expect(response.status).toEqual(204); + }); +}); diff --git a/app2/src/api/index.js b/app2/src/api/index.js new file mode 100644 index 000000000..b1c13e734 --- /dev/null +++ b/app2/src/api/index.js @@ -0,0 +1 @@ +export * from './api'; diff --git a/app2/src/api/schema.js b/app2/src/api/schema.js new file mode 100644 index 000000000..b919820ed --- /dev/null +++ b/app2/src/api/schema.js @@ -0,0 +1,21 @@ +import { schema } from 'normalizr'; + +export const user = new schema.Entity('users'); + +export const government = new schema.Entity('governments'); + +export const campaign = new schema.Entity('campaigns'); + +export const permission = new schema.Entity('permissions', { + user, + government, + campaign, +}); + +export const activity = new schema.Entity('activities'); + +export const contribution = new schema.Entity('contributions'); + +export const expenditure = new schema.Entity('expenditures'); + +export const match = new schema.Entity('matches'); diff --git a/app2/src/pages/_app.tsx b/app2/src/pages/_app.tsx new file mode 100755 index 000000000..c4f722d60 --- /dev/null +++ b/app2/src/pages/_app.tsx @@ -0,0 +1,21 @@ +import { Provider, useStore } from 'react-redux' +import type { AppProps } from 'next/app' +import {useState, useEffect} from 'react' + +function MyApp({ Component, pageProps }: AppProps) { + const [isLoading, setLoading] = useState(true) + const store = useStore(pageProps.initialReduxState) + + useEffect(() => { + loadAuth().then(() => { + setLoading(false) + }); + }, []) + return ( + + + + ) +} + +export default MyApp diff --git a/app2/src/pages/index.tsx b/app2/src/pages/index.tsx new file mode 100755 index 000000000..86b5b3b5b --- /dev/null +++ b/app2/src/pages/index.tsx @@ -0,0 +1,72 @@ +import type { NextPage } from 'next' +import Head from 'next/head' +import Image from 'next/image' +import styles from '../styles/Home.module.css' + +const Home: NextPage = () => { + return ( +
+ + Create Next App + + + + +
+

+ Welcome to Next.js! +

+ +

+ Get started by editing{' '} + pages/index.tsx +

+ +
+ +

Documentation →

+

Find in-depth information about Next.js features and API.

+
+ + +

Learn →

+

Learn about Next.js in an interactive course with quizzes!

+
+ + +

Examples →

+

Discover and deploy boilerplate example Next.js projects.

+
+ + +

Deploy →

+

+ Instantly deploy your Next.js site to a public URL with Vercel. +

+
+
+
+ + +
+ ) +} + +export default Home diff --git a/app2/src/pages/sign-in.tsx b/app2/src/pages/sign-in.tsx new file mode 100644 index 000000000..3388de234 --- /dev/null +++ b/app2/src/pages/sign-in.tsx @@ -0,0 +1,7 @@ +export default function SignIn() { + return ( +
+

sign in

+
+ ) +} \ No newline at end of file diff --git a/app2/src/state/ducks/activities.js b/app2/src/state/ducks/activities.js new file mode 100644 index 000000000..188c538f8 --- /dev/null +++ b/app2/src/state/ducks/activities.js @@ -0,0 +1,226 @@ +/* eslint-disable no-unused-vars */ +import { normalize } from 'normalizr'; +import { isEmpty } from 'lodash'; +import createReducer from '../utils/createReducer'; +import createActionTypes from '../utils/createActionTypes'; +import action from '../utils/action'; +import { RESET_STATE, resetState } from './common'; + +export const STATE_KEY = 'activities'; +export const ADD_ACTIVITY_ENTITIES = 'ADD_ACTIVITY_ENTITIES'; +export const addActivityEntities = entities => { + return { + type: ADD_ACTIVITY_ENTITIES, + payload: entities, + }; +}; + +// Action Types +export const actionTypes = { + GET_CAMPAIGN_ACTIVITIES: createActionTypes( + STATE_KEY, + 'GET_CAMPAIGN_ACTIVITIES' + ), + GET_GOVERNMENT_ACTIVITIES: createActionTypes( + STATE_KEY, + 'GET_GOVERNMENT_ACTIVITIES' + ), + GET_CONTRIBUTION_ACTIVITIES: createActionTypes( + STATE_KEY, + 'GET_CONTRIBUTION_ACTIVITIES' + ), + GET_EXPENDITURE_ACTIVITIES: createActionTypes( + STATE_KEY, + 'GET_EXPENDITURE_ACTIVITIES' + ), +}; + +// Initial State +export const initialState = { + list: null, + listOrder: [], + listOptions: { + page: 0, + perPage: 25, + total: 0, + }, + isLoading: false, + error: null, +}; + +export const resetActvityState = resetState; +// Reducer +export default createReducer(initialState, { + [RESET_STATE]: () => { + return { ...initialState }; + }, + [ADD_ACTIVITY_ENTITIES]: (state, action) => { + return { + ...state, + list: { ...action.payload.entities.activities }, + listOrder: action.payload.result, + listOptions: { + page: action.payload.page || initialState.listOptions.page, + perPage: action.payload.perPage || initialState.listOptions.perPage, + total: action.payload.total, + }, + }; + }, + [actionTypes.GET_CAMPAIGN_ACTIVITIES.REQUEST]: state => { + return { ...state, isLoading: true }; + }, + [actionTypes.GET_CAMPAIGN_ACTIVITIES.SUCCESS]: state => { + return { ...state, isLoading: false }; + }, + [actionTypes.GET_CAMPAIGN_ACTIVITIES.FAILURE]: (state, action) => { + return { ...state, isLoading: false, error: action.error }; + }, + [actionTypes.GET_GOVERNMENT_ACTIVITIES.REQUEST]: state => { + return { ...state, isLoading: true }; + }, + [actionTypes.GET_GOVERNMENT_ACTIVITIES.SUCCESS]: state => { + return { ...state, isLoading: false }; + }, + [actionTypes.GET_GOVERNMENT_ACTIVITIES.FAILURE]: (state, action) => { + return { ...state, isLoading: false, error: action.error }; + }, + [actionTypes.GET_CONTRIBUTION_ACTIVITIES.REQUEST]: state => { + return { ...state, isLoading: true }; + }, + [actionTypes.GET_CONTRIBUTION_ACTIVITIES.SUCCESS]: state => { + return { ...state, isLoading: false }; + }, + [actionTypes.GET_CONTRIBUTION_ACTIVITIES.FAILURE]: (state, action) => { + return { ...state, isLoading: false, error: action.error }; + }, + [actionTypes.GET_EXPENDITURE_ACTIVITIES.REQUEST]: state => { + return { ...state, isLoading: true }; + }, + [actionTypes.GET_EXPENDITURE_ACTIVITIES.SUCCESS]: state => { + return { ...state, isLoading: false }; + }, + [actionTypes.GET_EXPENDITURE_ACTIVITIES.FAILURE]: (state, action) => { + return { ...state, isLoading: false, error: action.error }; + }, +}); + +// Action Creators +export const actionCreators = { + getCampaignActivities: { + request: () => action(actionTypes.GET_CAMPAIGN_ACTIVITIES.REQUEST), + success: () => action(actionTypes.GET_CAMPAIGN_ACTIVITIES.SUCCESS), + failure: error => + action(actionTypes.GET_CAMPAIGN_ACTIVITIES.FAILURE, { error }), + }, + getGovernmentActivities: { + request: () => action(actionTypes.GET_GOVERNMENT_ACTIVITIES.REQUEST), + success: () => action(actionTypes.GET_GOVERNMENT_ACTIVITIES.SUCCESS), + failure: error => + action(actionTypes.GET_GOVERNMENT_ACTIVITIES.FAILURE, { error }), + }, + getContributionActivities: { + request: () => action(actionTypes.GET_CONTRIBUTION_ACTIVITIES.REQUEST), + success: () => action(actionTypes.GET_CONTRIBUTION_ACTIVITIES.SUCCESS), + failure: error => + action(actionTypes.GET_CONTRIBUTION_ACTIVITIES.FAILURE, { error }), + }, + getExpenditureActivities: { + request: () => action(actionTypes.GET_EXPENDITURE_ACTIVITIES.REQUEST), + success: () => action(actionTypes.GET_EXPENDITURE_ACTIVITIES.SUCCESS), + failure: error => + action(actionTypes.GET_EXPENDITURE_ACTIVITIES.FAILURE, { error }), + }, +}; + +// Side Effects, e.g. thunks +export function getCampaignActivities(campaignId) { + return async (dispatch, getState, { api, schema }) => { + dispatch(actionCreators.getCampaignActivities.request()); + try { + const response = await api.getCampaignActivities(campaignId); + const data = normalize(response.data, [schema.activity]); + const { page, perPage, total } = response; + dispatch(addActivityEntities({ ...data, page, perPage, total })); + dispatch(actionCreators.getCampaignActivities.success()); + } catch (error) { + dispatch(actionCreators.getCampaignActivities.failure(error)); + } + }; +} + +export function getGovernmentActivities(governmentId) { + return async (dispatch, getState, { api, schema }) => { + dispatch(actionCreators.getGovernmentActivities.request()); + try { + const response = await api.getGovernmentActivities(governmentId); + const data = normalize(response.data, [schema.activity]); + const { page, perPage, total } = response; + dispatch(addActivityEntities({ ...data, page, perPage, total })); + dispatch(actionCreators.getGovernmentActivities.success()); + } catch (error) { + dispatch(actionCreators.getGovernmentActivities.failure(error)); + } + }; +} + +export function getContributionActivities(contributionAttrs) { + return async (dispatch, getState, { api, schema }) => { + dispatch(actionCreators.getContributionActivities.request()); + try { + const response = await api.getContributionActivities(contributionAttrs); + const data = normalize(response.data, [schema.activity]); + const { page, perPage, total } = response; + dispatch(addActivityEntities({ ...data, page, perPage, total })); + dispatch(actionCreators.getContributionActivities.success()); + } catch (error) { + dispatch(actionCreators.getContributionActivities.failure(error)); + } + }; +} + +export function getExpenditureActivities(activitiesAttrs) { + return async (dispatch, getState, { api, schema }) => { + dispatch(actionCreators.getExpenditureActivities.request()); + try { + const response = await api.getExpenditureActivities(activitiesAttrs); + const data = normalize(response.data, [schema.activity]); + const { page, perPage, total } = response; + dispatch(addActivityEntities({ ...data, page, perPage, total })); + dispatch(actionCreators.getExpenditureActivities.success()); + } catch (error) { + dispatch(actionCreators.getExpenditureActivities.failure(error)); + } + }; +} + +export function getActivitiesByIdType(activitiesAttrs) { + const { + expenditureId, + contributionId, + governmentId, + campaignId, + } = activitiesAttrs; + return async (dispatch, getState, { api, schema }) => { + if (expenditureId) dispatch(getExpenditureActivities(activitiesAttrs)); + if (contributionId) dispatch(getContributionActivities(activitiesAttrs)); + if (governmentId) dispatch(getGovernmentActivities(activitiesAttrs)); + if (campaignId) dispatch(getCampaignActivities(activitiesAttrs)); + }; +} + +export const getActivities = state => { + if (isEmpty(state.activities.list) || isEmpty(state.activities.listOrder)) { + return []; + } + return state.activities.listOrder.map(id => state.activities.list[id]); +}; + +export const getActivtiesCount = state => { + return isEmpty(state.activities.list) + ? 0 + : Object.keys(state.activities.list).length; +}; + +export const getTotalCount = state => { + return state.activities.listOptions.total; +}; diff --git a/app2/src/state/ducks/activities.test.js b/app2/src/state/ducks/activities.test.js new file mode 100644 index 000000000..2fef4a1d5 --- /dev/null +++ b/app2/src/state/ducks/activities.test.js @@ -0,0 +1,204 @@ +/* eslint-disable no-unused-vars */ +import configureMockStore from 'redux-mock-store'; +import thunk from 'redux-thunk'; +import * as activities from './activities'; +import * as api from '../../api'; +import * as schema from '../../api/schema'; + +const { actionTypes, actionCreators } = activities; + +const middlewares = [thunk.withExtraArgument({ api, schema })]; +const mockStore = configureMockStore(middlewares); + +const govAdmin = { + email: 'govadmin@openelectionsportland.org', + password: 'password', +}; + +const invite = { + code: 'inviteme', + email: 'campaignStaff+1@openelectionsportland.org', + password: 'password', +}; + +const reset = { + code: 'resetme', + password: 'newpassword', +}; + +describe('Reducer', () => { + const reducer = activities.default; + it('initial state', () => { + expect(reducer(undefined, {})).toEqual({ + list: null, + listOrder: [], + isLoading: false, + error: null, + listOptions: { + page: 0, + perPage: 25, + total: 0, + }, + }); + }); + + it('adds activity entities', () => { + expect( + reducer(undefined, { + type: activities.ADD_ACTIVITY_ENTITIES, + payload: { + result: [], + page: 0, + perPage: 25, + total: 1, + entities: { + activities: { + '1': {}, + }, + }, + }, + }) + ).toEqual({ + list: { + '1': {}, + }, + listOptions: { + page: 0, + perPage: 25, + total: 1, + }, + listOrder: [], + isLoading: false, + error: null, + }); + }); +}); + +describe('Action Creators', () => { + it('get campaign activities request', () => { + const expectedAction = { + type: actionTypes.GET_CAMPAIGN_ACTIVITIES.REQUEST, + }; + expect(actionCreators.getCampaignActivities.request()).toEqual( + expectedAction + ); + }); + it('get campaign activities success', () => { + const expectedAction = { + type: actionTypes.GET_CAMPAIGN_ACTIVITIES.SUCCESS, + }; + expect(actionCreators.getCampaignActivities.success()).toEqual( + expectedAction + ); + }); + it('get campaign activities failure', () => { + const expectedAction = { + type: actionTypes.GET_CAMPAIGN_ACTIVITIES.FAILURE, + }; + expect(actionCreators.getCampaignActivities.failure()).toEqual( + expectedAction + ); + }); +}); + +let govAdminToken; +let campaignAdminToken; +let campaignStaffToken; +let governmentId; +let campaignId; +describe('Side Effects', () => { + beforeAll(async () => { + let tokenResponse = await api.login( + 'govadmin@openelectionsportland.org', + 'password' + ); + govAdminToken = tokenResponse.headers + .get('set-cookie') + .match(/=([a-zA-Z0-9].+); Path/)[1]; + let decodedToken = api.decodeToken(govAdminToken); + governmentId = decodedToken.permissions[0].governmentId; + + tokenResponse = await api.login( + 'campaignadmin@openelectionsportland.org', + 'password' + ); + campaignAdminToken = tokenResponse.headers + .get('set-cookie') + .match(/=([a-zA-Z0-9].+); Path/)[1]; + decodedToken = api.decodeToken(campaignAdminToken); + campaignId = decodedToken.permissions[0].campaignId; + + tokenResponse = await api.login( + 'campaignstaff@openelectionsportland.org', + 'password' + ); + campaignStaffToken = tokenResponse.headers + .get('set-cookie') + .match(/=([a-zA-Z0-9].+); Path/)[1]; + }); + + beforeEach(() => { + delete process.env.TOKEN; + }); + + it('gets campaign activities', async () => { + const expectedActions = [ + { type: actionTypes.GET_CAMPAIGN_ACTIVITIES.REQUEST }, + { type: activities.ADD_ACTIVITY_ENTITIES }, + { type: actionTypes.GET_CAMPAIGN_ACTIVITIES.SUCCESS }, + ]; + const store = mockStore({}); + + process.env.TOKEN = campaignAdminToken; + return store + .dispatch( + activities.getCampaignActivities({ campaignId, page: 0, perPage: 25 }) + ) + .then(() => { + const actions = store.getActions(); + expect(actions[0].type).toEqual(expectedActions[0].type); + expect(actions[1].type).toEqual(expectedActions[1].type); + expect(actions[2].type).toEqual(expectedActions[2].type); + }); + }); + + it('gets CONTRIBUTION activities', async () => { + const expectedActions = [ + { type: actionTypes.GET_CONTRIBUTION_ACTIVITIES.REQUEST }, + { type: activities.ADD_ACTIVITY_ENTITIES }, + { type: actionTypes.GET_CONTRIBUTION_ACTIVITIES.SUCCESS }, + ]; + const store = mockStore({}); + + process.env.TOKEN = campaignAdminToken; + + return store + .dispatch(activities.getContributionActivities({ contributionId: 1 })) + .then(() => { + const actions = store.getActions(); + expect(actions[0].type).toEqual(expectedActions[0].type); + expect(actions[1].type).toEqual(expectedActions[1].type); + expect(actions[2].type).toEqual(expectedActions[2].type); + }); + }); + + it('gets EXPENDITURE activities', async () => { + const expectedActions = [ + { type: actionTypes.GET_EXPENDITURE_ACTIVITIES.REQUEST }, + { type: activities.ADD_ACTIVITY_ENTITIES }, + { type: actionTypes.GET_EXPENDITURE_ACTIVITIES.SUCCESS }, + ]; + const store = mockStore({}); + + process.env.TOKEN = campaignAdminToken; + + return store + .dispatch(activities.getExpenditureActivities({ expenditureid: 1 })) + .then(() => { + const actions = store.getActions(); + expect(actions[0].type).toEqual(expectedActions[0].type); + expect(actions[1].type).toEqual(expectedActions[1].type); + expect(actions[2].type).toEqual(expectedActions[2].type); + }); + }); +}); diff --git a/app2/src/state/ducks/auth.js b/app2/src/state/ducks/auth.js new file mode 100644 index 000000000..0cffe5693 --- /dev/null +++ b/app2/src/state/ducks/auth.js @@ -0,0 +1,458 @@ +/* eslint-disable no-unused-vars */ +import { push } from 'connected-react-router'; +import { flashMessage } from 'redux-flash'; +import createReducer from '../utils/createReducer'; +import createActionTypes, { + createCustomActionTypes, +} from '../utils/createActionTypes'; +import action from '../utils/action'; +import * as governments from './governments'; +import { getStatusSummaryAction } from './summary'; +import { resetContributionState } from './contributions'; +import { resetExpenditureState } from './expenditures'; +import { resetUserState } from './users'; +import { resetPermissionState } from './permissions'; +import { resetActvityState } from './activities'; +import { + resetCampaignState, + actionCreators as campaignsActionCreators, +} from './campaigns'; + +// Export State Key +export const STATE_KEY = 'auth'; + +// Action Types +export const actionTypes = { + ME: createActionTypes(STATE_KEY, 'ME'), + LOGIN: createActionTypes(STATE_KEY, 'LOGIN'), + REDEEM_INVITE: createActionTypes(STATE_KEY, 'REDEEM_INVITE'), + RESET_PASSWORD: createActionTypes(STATE_KEY, 'RESET_PASSWORD'), + SEND_PASSWORD_RESET_EMAIL: createActionTypes( + STATE_KEY, + 'SEND_PASSWORD_RESET_EMAIL' + ), + UPDATE_PASSWORD: createActionTypes(STATE_KEY, 'UPDATE_PASSWORD'), + SET_ASSUME: createCustomActionTypes(STATE_KEY, 'SET_ASSUME', ['UPDATE']), +}; + +// Initial State +export const initialState = { + me: null, + assume: false, + isLoading: false, + error: null, +}; + +// Reducer +export default createReducer(initialState, { + [actionTypes.ME.REQUEST]: (state, action) => { + return { ...state, isLoading: true }; + }, + [actionTypes.ME.SUCCESS]: (state, action) => { + return { ...state, isLoading: false, me: action.me }; + }, + [actionTypes.ME.FAILURE]: (state, action) => { + return { ...state, isLoading: false, error: action.error }; + }, + [actionTypes.LOGIN.REQUEST]: (state, action) => { + return { ...state, isLoading: true, error: null }; + }, + [actionTypes.LOGIN.SUCCESS]: (state, action) => { + return { ...state, isLoading: false, error: null, me: action.me }; + }, + [actionTypes.LOGIN.FAILURE]: (state, action) => { + return { ...state, isLoading: false, error: action.error }; + }, + [actionTypes.REDEEM_INVITE.REQUEST]: (state, action) => { + return { ...state, isLoading: true }; + }, + [actionTypes.REDEEM_INVITE.SUCCESS]: (state, action) => { + return { ...state, isLoading: false }; + }, + [actionTypes.REDEEM_INVITE.FAILURE]: (state, action) => { + return { ...state, isLoading: false, error: action.error }; + }, + [actionTypes.RESET_PASSWORD.REQUEST]: (state, action) => { + return { ...state, isLoading: true }; + }, + [actionTypes.RESET_PASSWORD.SUCCESS]: (state, action) => { + return { ...state, isLoading: false }; + }, + [actionTypes.RESET_PASSWORD.FAILURE]: (state, action) => { + return { ...state, isLoading: false, error: action.error }; + }, + [actionTypes.SEND_PASSWORD_RESET_EMAIL.REQUEST]: (state, action) => { + return { ...state, isLoading: true }; + }, + [actionTypes.SEND_PASSWORD_RESET_EMAIL.SUCCESS]: (state, action) => { + return { ...state, isLoading: false }; + }, + [actionTypes.SEND_PASSWORD_RESET_EMAIL.FAILURE]: (state, action) => { + return { ...state, isLoading: false, error: action.error }; + }, + [actionTypes.UPDATE_PASSWORD.REQUEST]: (state, action) => { + return { ...state, isLoading: true }; + }, + [actionTypes.UPDATE_PASSWORD.SUCCESS]: (state, action) => { + return { ...state, isLoading: false, error: null }; + }, + [actionTypes.UPDATE_PASSWORD.FAILURE]: (state, action) => { + return { ...state, isLoading: false, error: action.error }; + }, + [actionTypes.SET_ASSUME.UPDATE]: (state, action) => { + return { ...state, assume: action.assume }; + }, +}); + +// Action Creators +export const actionCreators = { + me: { + request: () => action(actionTypes.ME.REQUEST), + success: me => action(actionTypes.ME.SUCCESS, { me }), + failure: error => action(actionTypes.ME.FAILURE, { error }), + }, + login: { + request: () => action(actionTypes.LOGIN.REQUEST), + success: me => action(actionTypes.LOGIN.SUCCESS, { me }), + failure: error => action(actionTypes.LOGIN.FAILURE, { error }), + }, + redeemInvite: { + request: () => action(actionTypes.REDEEM_INVITE.REQUEST), + success: () => action(actionTypes.REDEEM_INVITE.SUCCESS), + failure: error => action(actionTypes.REDEEM_INVITE.FAILURE, { error }), + }, + resetPassword: { + request: () => action(actionTypes.RESET_PASSWORD.REQUEST), + success: () => action(actionTypes.RESET_PASSWORD.SUCCESS), + failure: error => action(actionTypes.RESET_PASSWORD.FAILURE, { error }), + }, + sendPasswordResetEmail: { + request: () => action(actionTypes.SEND_PASSWORD_RESET_EMAIL.REQUEST), + success: () => action(actionTypes.SEND_PASSWORD_RESET_EMAIL.SUCCESS), + failure: error => + action(actionTypes.SEND_PASSWORD_RESET_EMAIL.FAILURE, { error }), + }, + updatePassword: { + request: () => action(actionTypes.UPDATE_PASSWORD.REQUEST), + success: () => action(actionTypes.UPDATE_PASSWORD.SUCCESS), + failure: error => action(actionTypes.UPDATE_PASSWORD.FAILURE, { error }), + }, + setAssume: assume => action(actionTypes.SET_ASSUME.UPDATE, { assume }), +}; + +export const getMeRole = (state, role = 'campaign_admin') => { + if (state.auth.me && state.auth.me.permissions) { + return !!state.auth.me.permissions.find(permission => { + return permission.role === role; + }); + } + return false; +}; + +export function setAssume() { + return (dispatch, getState) => { + if (getMeRole(getState(), 'government_admin')) { + dispatch(actionCreators.setAssume(true)); + } + }; +} +export function unSetAssume() { + return dispatch => { + dispatch(actionCreators.setAssume(false)); + }; +} + +// Side Effects, e.g. thunks +export function redeemInvite(invitationCode, password, firstName, lastName) { + return async (dispatch, getState, { api }) => { + dispatch(actionCreators.redeemInvite.request()); + try { + const { status } = await api.redeemInvite( + invitationCode, + password, + firstName, + lastName + ); + if (status === 204) { + dispatch(actionCreators.redeemInvite.success()); + dispatch( + flashMessage('Signup Success', { props: { variant: 'success' } }) + ); + dispatch(push('/sign-in')); + } else { + dispatch(actionCreators.redeemInvite.failure()); + dispatch(flashMessage('Signup Error', { props: { variant: 'error' } })); + } + } catch (error) { + dispatch(actionCreators.redeemInvite.failure(error)); + dispatch( + flashMessage(`Signup Error - ${error}`, { props: { variant: 'error' } }) + ); + } + }; +} + +export function resetPassword(invitationCode, password) { + return async (dispatch, getState, { api }) => { + dispatch(actionCreators.resetPassword.request()); + try { + const { status } = await api.resetPassword(invitationCode, password); + if (status === 204) { + dispatch(actionCreators.resetPassword.success()); + return true; + } + dispatch(actionCreators.resetPassword.failure()); + return false; + } catch (error) { + dispatch(actionCreators.resetPassword.failure(error)); + return false; + } + }; +} + +export function sendPasswordResetEmail(email) { + return async (dispatch, getState, { api }) => { + dispatch(actionCreators.sendPasswordResetEmail.request()); + try { + const { status } = await api.sendPasswordResetEmail(email); + if (status === 204) { + dispatch(actionCreators.sendPasswordResetEmail.success()); + return true; + } + dispatch(actionCreators.sendPasswordResetEmail.failure()); + return false; + } catch (error) { + dispatch(actionCreators.sendPasswordResetEmail.failure(error)); + return false; + } + }; +} + +export function logout() { + return dispatch => { + dispatch(actionCreators.me.success(null)); + dispatch(unSetAssume()); + dispatch(resetContributionState()); + dispatch(resetExpenditureState()); + dispatch(resetUserState()); + dispatch(resetCampaignState()); + dispatch(resetPermissionState()); + dispatch(resetActvityState()); + if (!window.location.hostname.includes('localhost')) { + document.cookie = + 'token=; domain=.openelectionsportland.org; expires=Thu, 01 Jan 1970 00:00:00 GMT'; + } else { + document.cookie = 'token=; expires=Thu, 01 Jan 1970 00:00:00 GMT'; + } + + dispatch(push('/sign-in')); + }; +} + +export function me() { + return async (dispatch, getState, { api }) => { + if ( + process.env.NODE_ENV !== 'development' && + !document.cookie.includes('token') && + !process.env.TOKEN + ) { + return; + } + dispatch(actionCreators.me.request()); + try { + const me = await api.me(); + if (me.message && me.message === 'Token expired or incorrect') { + dispatch(logout); + } + if (me && me.permissions) { + const campaignPermission = me.permissions.filter(permission => { + return (permission.type = 'campaign'); + }); + if (campaignPermission.length) { + dispatch( + campaignsActionCreators.setCampaign.success( + me.permissions[0].campaignId + ) + ); + if (me.permissions[0].campaignId) { + dispatch( + getStatusSummaryAction({ + campaignId: me.permissions[0].campaignId, + }) + ); + } + } + + const govPermission = me.permissions.filter(permission => { + return (permission.type = 'government'); + }); + if (govPermission.length) { + dispatch( + governments.actionCreators.setGovernment.success( + me.permissions[0].governmentId + ) + ); + if (me.permissions[0].governmentId) { + dispatch( + getStatusSummaryAction({ + governmentId: me.permissions[0].governmentId, + }) + ); + } + } + } + dispatch(actionCreators.me.success(me)); + } catch (error) { + dispatch(actionCreators.me.failure(error)); + } + }; +} +export function login(email, password) { + return async (dispatch, getState, { api }) => { + // dispatch(actionCreators.login.failure(true)); + dispatch(actionCreators.login.request()); + try { + await api.login(email, password).then(response => { + if (response.status === 204) { + dispatch(actionCreators.login.success()); + dispatch(me()); + dispatch( + flashMessage('Signin Success', { props: { variant: 'success' } }) + ); + dispatch(push('/dashboard')); + } else { + dispatch(actionCreators.login.failure(true)); + dispatch( + flashMessage('Signin Error', { props: { variant: 'error' } }) + ); + } + }); + } catch (error) { + dispatch(actionCreators.login.failure(error)); + dispatch( + flashMessage(`Signin Error - ${error}`, { props: { variant: 'error' } }) + ); + } + }; +} + +export function updatePassword(password, newPassword) { + return async (dispatch, getState, { api }) => { + dispatch(actionCreators.updatePassword.request()); + try { + const { status } = await api.updatePassword(password, newPassword); + if (status === 204) { + dispatch(actionCreators.updatePassword.success()); + dispatch( + flashMessage('Password updated', { props: { variant: 'success' } }) + ); + dispatch(logout()); + } else { + dispatch( + actionCreators.updatePassword.failure( + 'Update password request failed' + ) + ); + dispatch( + flashMessage('Password update failed', { + props: { variant: 'error' }, + }) + ); + } + } catch (error) { + dispatch(actionCreators.updatePassword.failure(error)); + dispatch( + flashMessage(`Password update failed - ${error}`, { + props: { variant: 'error' }, + }) + ); + } + }; +} + +export function redirectToLogin() { + return async (dispatch, getState, { api }) => { + dispatch(push('/sign-in')); + }; +} + +// TODO Dispatch this function from thunks to redirect on stale auth cookies +export function checkForUnauthorizedResponse(response) { + return dispatch => { + if (response.status === 401 || response.status === 422) { + dispatch(logout()); + } + }; +} + +// Selectors +export const rootState = state => state || {}; + +export const isLoggedIn = state => { + return state.auth.me !== null; +}; + +export const isAdmin = state => { + return state.auth.me !== null + ? state.auth.me.permissions[0].role === 'government_admin' || + state.auth.me.permissions[0].role === 'campaign_admin' + : false; +}; + +export const isGovAdminAuthenticated = state => { + return getMeRole(state, 'government_admin'); +}; +export const isAssumed = state => { + return !!state.auth.assume; +}; +export const isGovAdmin = state => { + return state.auth.assume && + (state.router.location.pathname.includes('/contributions/') || + state.router.location.pathname.includes('/expenses/')) + ? false + : getMeRole(state, 'government_admin'); +}; +export const isCampAdmin = state => { + return state.auth.assume && + (state.router.location.pathname.includes('/contributions/') || + state.router.location.pathname.includes('/expenses/')) + ? true + : getMeRole(state, 'campaign_admin'); +}; +export const isCampStaff = state => { + return getMeRole(state, 'campaign_staff'); +}; + +export const getGovOrCampIdAttributes = state => { + if (state.auth.me && state.auth.me.permissions) { + const { governmentId = 1, campaignId } = state.auth.me.permissions[0]; + return { governmentId, campaignId }; + } +}; + +export const getCurrentUserId = state => { + if (state.auth.me) { + return state.auth.me.id; + } + return null; +}; + +// Assumes only one campaign. Add setter and adjust default to [0] permission +export const getCurrentCampaignId = state => { + if (state.auth.me && state.auth.me.permissions) { + if (state.auth.me.permissions[0] && state.auth.me.permissions[0].campaignId) + return state.auth.me.permissions[0].campaignId; + } + return null; +}; + +export const getCurrentCampaignName = state => { + if (state.auth.me && state.auth.me.permissions) { + if ( + state.auth.me.permissions[0] && + state.auth.me.permissions[0].campaignName + ) + return state.auth.me.permissions[0].campaignName; + } + return 'Campaign'; +}; diff --git a/app2/src/state/ducks/auth.test.js b/app2/src/state/ducks/auth.test.js new file mode 100644 index 000000000..bf97b564e --- /dev/null +++ b/app2/src/state/ducks/auth.test.js @@ -0,0 +1,646 @@ +/* eslint-disable no-unused-vars */ +import configureMockStore from 'redux-mock-store'; +import thunk from 'redux-thunk'; +import * as auth from './auth'; +import * as campaigns from './campaigns'; +import * as summary from './summary'; +import * as governments from './governments'; +import * as api from '../../api'; +import * as schema from '../../api/schema'; + +const { actionTypes, actionCreators } = auth; + +const middlewares = [thunk.withExtraArgument({ api, schema })]; +const mockStore = configureMockStore(middlewares); + +const govAdmin = { + email: 'govadmin@openelectionsportland.org', + password: 'password', +}; + +const invite = { + code: 'inviteme', + email: 'campaignStaff+1@openelectionsportland.org', + password: 'password', +}; + +const reset = { + code: 'resetme', + password: 'newpassword', +}; + +describe('Reducer', () => { + const reducer = auth.default; + it('initial state', () => { + expect(reducer(undefined, {})).toEqual({ + assume: false, + me: null, + isLoading: false, + error: null, + }); + }); + + it('login', () => { + expect( + reducer(undefined, { + type: actionTypes.LOGIN.REQUEST, + }) + ).toEqual({ + assume: false, + me: null, + isLoading: true, + error: null, + }); + + expect( + reducer(undefined, { + type: actionTypes.LOGIN.SUCCESS, + me: {}, + }) + ).toEqual({ + assume: false, + me: {}, + isLoading: false, + error: null, + }); + + expect( + reducer(undefined, { + type: actionTypes.LOGIN.FAILURE, + error: '', + }) + ).toEqual({ + assume: false, + me: null, + isLoading: false, + error: '', + }); + }); + + // it("logout", () => { + // expect( + // reducer(undefined, { + // type: actionTypes.LOGIN.SUCCESS, + // me: null + // }) + // ).toEqual({ + // me: null, + // isLoading: false, + // error: null + // }); + // }); + + it('me', () => { + expect( + reducer(undefined, { + type: actionTypes.ME.REQUEST, + }) + ).toEqual({ + assume: false, + me: null, + isLoading: true, + error: null, + }); + + expect( + reducer(undefined, { + type: actionTypes.ME.SUCCESS, + me: {}, + }) + ).toEqual({ + assume: false, + me: {}, + isLoading: false, + error: null, + }); + + expect( + reducer(undefined, { + type: actionTypes.ME.FAILURE, + error: '', + }) + ).toEqual({ + assume: false, + me: null, + isLoading: false, + error: '', + }); + }); + + it('redeem invite', () => { + expect( + reducer(undefined, { + type: actionTypes.REDEEM_INVITE.REQUEST, + }) + ).toEqual({ + assume: false, + me: null, + isLoading: true, + error: null, + }); + + expect( + reducer(undefined, { + type: actionTypes.REDEEM_INVITE.SUCCESS, + }) + ).toEqual({ + assume: false, + me: null, + isLoading: false, + error: null, + }); + + expect( + reducer(undefined, { + type: actionTypes.REDEEM_INVITE.FAILURE, + error: '', + }) + ).toEqual({ + assume: false, + me: null, + isLoading: false, + error: '', + }); + }); + + it('reset password', () => { + expect( + reducer(undefined, { + type: actionTypes.RESET_PASSWORD.REQUEST, + }) + ).toEqual({ + assume: false, + me: null, + isLoading: true, + error: null, + }); + + expect( + reducer(undefined, { + type: actionTypes.RESET_PASSWORD.SUCCESS, + }) + ).toEqual({ + assume: false, + me: null, + isLoading: false, + error: null, + }); + + expect( + reducer(undefined, { + type: actionTypes.RESET_PASSWORD.FAILURE, + error: '', + }) + ).toEqual({ + assume: false, + me: null, + isLoading: false, + error: '', + }); + }); + + it('send password reset email', () => { + expect( + reducer(undefined, { + type: actionTypes.SEND_PASSWORD_RESET_EMAIL.REQUEST, + }) + ).toEqual({ + assume: false, + me: null, + isLoading: true, + error: null, + }); + + expect( + reducer(undefined, { + type: actionTypes.SEND_PASSWORD_RESET_EMAIL.SUCCESS, + }) + ).toEqual({ + assume: false, + me: null, + isLoading: false, + error: null, + }); + + expect( + reducer(undefined, { + type: actionTypes.SEND_PASSWORD_RESET_EMAIL.FAILURE, + error: '', + }) + ).toEqual({ + assume: false, + me: null, + isLoading: false, + error: '', + }); + }); + + it('update password', () => { + expect( + reducer(undefined, { + type: actionTypes.UPDATE_PASSWORD.REQUEST, + }) + ).toEqual({ + assume: false, + me: null, + isLoading: true, + error: null, + }); + + expect( + reducer(undefined, { + type: actionTypes.UPDATE_PASSWORD.SUCCESS, + }) + ).toEqual({ + assume: false, + me: null, + isLoading: false, + error: null, + }); + + expect( + reducer(undefined, { + type: actionTypes.UPDATE_PASSWORD.FAILURE, + error: '', + }) + ).toEqual({ + assume: false, + me: null, + isLoading: false, + error: '', + }); + }); +}); + +describe('Action Creators', () => { + it('me request', () => { + const expectedAction = { + type: actionTypes.ME.REQUEST, + }; + expect(actionCreators.me.request()).toEqual(expectedAction); + }); + + it('me success', () => { + const me = {}; + const expectedAction = { + type: actionTypes.ME.SUCCESS, + me: {}, + }; + expect(actionCreators.me.success(me)).toEqual(expectedAction); + }); + + it('me failure', () => { + const error = ''; + const expectedAction = { + type: actionTypes.ME.FAILURE, + error: '', + }; + expect(actionCreators.me.failure(error)).toEqual(expectedAction); + }); + + it('login request', () => { + const expectedAction = { + type: actionTypes.LOGIN.REQUEST, + }; + expect(actionCreators.login.request()).toEqual(expectedAction); + }); + + it('login success', () => { + const me = {}; + const expectedAction = { + type: actionTypes.LOGIN.SUCCESS, + me: {}, + }; + expect(actionCreators.login.success(me)).toEqual(expectedAction); + }); + + it('login failure', () => { + const error = ''; + const expectedAction = { + type: actionTypes.LOGIN.FAILURE, + error: '', + }; + expect(actionCreators.login.failure(error)).toEqual(expectedAction); + }); + + it('redeem invite request', () => { + const expectedAction = { + type: actionTypes.REDEEM_INVITE.REQUEST, + }; + expect(actionCreators.redeemInvite.request()).toEqual(expectedAction); + }); + + it('redeem invite success', () => { + const expectedAction = { + type: actionTypes.REDEEM_INVITE.SUCCESS, + }; + expect(actionCreators.redeemInvite.success()).toEqual(expectedAction); + }); + + it('redeem invite failure', () => { + const error = ''; + const expectedAction = { + type: actionTypes.REDEEM_INVITE.FAILURE, + error: '', + }; + expect(actionCreators.redeemInvite.failure(error)).toEqual(expectedAction); + }); + + it('reset password request', () => { + const expectedAction = { + type: actionTypes.RESET_PASSWORD.REQUEST, + }; + expect(actionCreators.resetPassword.request()).toEqual(expectedAction); + }); + + it('reset password success', () => { + const expectedAction = { + type: actionTypes.RESET_PASSWORD.SUCCESS, + }; + expect(actionCreators.resetPassword.success()).toEqual(expectedAction); + }); + + it('reset password failure', () => { + const error = ''; + const expectedAction = { + type: actionTypes.RESET_PASSWORD.FAILURE, + error: '', + }; + expect(actionCreators.resetPassword.failure(error)).toEqual(expectedAction); + }); + + it('send password reset email request', () => { + const expectedAction = { + type: actionTypes.SEND_PASSWORD_RESET_EMAIL.REQUEST, + }; + expect(actionCreators.sendPasswordResetEmail.request()).toEqual( + expectedAction + ); + }); + + it('send password reset email success', () => { + const expectedAction = { + type: actionTypes.SEND_PASSWORD_RESET_EMAIL.SUCCESS, + }; + expect(actionCreators.sendPasswordResetEmail.success()).toEqual( + expectedAction + ); + }); + + it('send password reset email failure', () => { + const error = ''; + const expectedAction = { + type: actionTypes.SEND_PASSWORD_RESET_EMAIL.FAILURE, + error: '', + }; + expect(actionCreators.sendPasswordResetEmail.failure(error)).toEqual( + expectedAction + ); + }); + + it('update password request', () => { + const expectedAction = { + type: actionTypes.UPDATE_PASSWORD.REQUEST, + }; + expect(actionCreators.updatePassword.request()).toEqual(expectedAction); + }); + + it('update password success', () => { + const expectedAction = { + type: actionTypes.UPDATE_PASSWORD.SUCCESS, + }; + expect(actionCreators.updatePassword.success()).toEqual(expectedAction); + }); + + it('update password failure', () => { + const error = ''; + const expectedAction = { + type: actionTypes.UPDATE_PASSWORD.FAILURE, + error: '', + }; + expect(actionCreators.updatePassword.failure(error)).toEqual( + expectedAction + ); + }); +}); + +describe('Side Effects', () => { + beforeEach(() => { + delete process.env.TOKEN; + }); + + it('me', async () => { + const expectedActions = [ + { type: actionTypes.ME.REQUEST }, + { type: campaigns.actionTypes.SET_CAMPAIGN.SUCCESS, campaignId: 1 }, + { type: governments.actionTypes.SET_GOVERNMENT.SUCCESS, governmentId: 1 }, + { type: summary.actionTypes.GET_SUMMARY.REQUEST }, + { type: actionTypes.ME.SUCCESS }, + ]; + const store = mockStore({}); + + const tokenResponse = await api.login( + 'govadmin@openelectionsportland.org', + 'password' + ); + process.env.TOKEN = tokenResponse.headers + .get('set-cookie') + .match(/=([a-zA-Z0-9].+); Path/)[1]; + + return store.dispatch(auth.me()).then(() => { + const actions = store.getActions(); + expect(actions[0]).toEqual(expectedActions[0]); + expect(actions[1].type).toEqual(expectedActions[1].type); + expect(actions[2].type).toEqual(expectedActions[2].type); + expect(actions[3].type).toEqual(expectedActions[3].type); + expect(actions[4].me).toMatchObject({ + id: expect.any(Number), + email: expect.any(String), + }); + }); + }); + + it('me no token', () => { + const expectedActions = []; + const store = mockStore({}); + + return store.dispatch(auth.me()).then(() => { + const actions = store.getActions(); + expect(actions).toHaveLength(0); + }); + }); + + it('login', () => { + const expectedActions = [ + { type: actionTypes.LOGIN.REQUEST }, + { type: actionTypes.LOGIN.SUCCESS }, + ]; + const store = mockStore({}); + + return store + .dispatch(auth.login(govAdmin.email, govAdmin.password)) + .then(() => { + const actions = store.getActions(); + expect(actions[0]).toEqual(expectedActions[0]); + expect(actions[1].type).toEqual(expectedActions[1].type); + }); + }); + + it('logout', () => { + const expectedActions = [{ type: actionTypes.ME.SUCCESS, me: null }]; + const store = mockStore({}); + store.dispatch(auth.logout()); + const actions = store.getActions(); + expect(actions[0]).toEqual(expectedActions[0]); + }); + + it('login failure', () => { + const expectedActions = [ + { type: actionTypes.LOGIN.REQUEST }, + { type: actionTypes.LOGIN.FAILURE }, + ]; + const store = mockStore({}); + + return store + .dispatch(auth.login(govAdmin.email, 'wrongpassword')) + .then(() => { + const actions = store.getActions(); + expect(actions[0]).toEqual(expectedActions[0]); + expect(actions[1].type).toEqual(expectedActions[1].type); + }); + }); + + it('redeem invite', () => { + const expectedActions = [ + { type: actionTypes.REDEEM_INVITE.REQUEST }, + { type: actionTypes.REDEEM_INVITE.SUCCESS }, + ]; + const store = mockStore({}); + + return store + .dispatch(auth.redeemInvite(invite.code, invite.password)) + .then(() => { + const actions = store.getActions(); + expect(actions[0]).toEqual(expectedActions[0]); + expect(actions[1]).toEqual(expectedActions[1]); + }); + }); + + it('redeem invite failure', () => { + const expectedActions = [ + { type: actionTypes.REDEEM_INVITE.REQUEST }, + { type: actionTypes.REDEEM_INVITE.FAILURE }, + ]; + const store = mockStore({}); + + return store + .dispatch(auth.redeemInvite('wrongcode', invite.password)) + .then(() => { + const actions = store.getActions(); + expect(actions[0]).toEqual(expectedActions[0]); + expect(actions[1]).toEqual(expectedActions[1]); + }); + }); + + it('reset password', () => { + const expectedActions = [ + { type: actionTypes.RESET_PASSWORD.REQUEST }, + { type: actionTypes.RESET_PASSWORD.SUCCESS }, + ]; + const store = mockStore({}); + + return store + .dispatch(auth.resetPassword(reset.code, reset.password)) + .then(() => { + expect(store.getActions()).toEqual(expectedActions); + }); + }); + + it('reset password failure', () => { + const expectedActions = [ + { type: actionTypes.RESET_PASSWORD.REQUEST }, + { type: actionTypes.RESET_PASSWORD.FAILURE }, + ]; + const store = mockStore({}); + + return store + .dispatch(auth.resetPassword('wrongcode', reset.password)) + .then(() => { + expect(store.getActions()).toEqual(expectedActions); + }); + }); + + it('send password reset email', () => { + const expectedActions = [ + { type: actionTypes.SEND_PASSWORD_RESET_EMAIL.REQUEST }, + { type: actionTypes.SEND_PASSWORD_RESET_EMAIL.SUCCESS }, + ]; + const store = mockStore({}); + + return store + .dispatch( + auth.sendPasswordResetEmail('campaignstaff@openelectionsportland.org') + ) + .then(() => { + expect(store.getActions()).toEqual(expectedActions); + }); + }); + + it('send password reset email failure', () => { + const expectedActions = [ + { type: actionTypes.SEND_PASSWORD_RESET_EMAIL.REQUEST }, + { type: actionTypes.SEND_PASSWORD_RESET_EMAIL.FAILURE }, + ]; + const store = mockStore({}); + + return store + .dispatch( + auth.sendPasswordResetEmail( + 'wrong_campaignstaff@@openelectionsportland.org' + ) + ) + .then(() => { + expect(store.getActions()).toEqual(expectedActions); + }); + }); + + it('update password', async () => { + const expectedActions = [ + { type: actionTypes.UPDATE_PASSWORD.REQUEST }, + { type: actionTypes.UPDATE_PASSWORD.SUCCESS }, + ]; + const store = mockStore({}); + + const tokenResponse = await api.login( + 'govadmin@openelectionsportland.org', + 'password' + ); + process.env.TOKEN = tokenResponse.headers + .get('set-cookie') + .match(/=([a-zA-Z0-9].+); Path/)[1]; + + return store + .dispatch(auth.updatePassword('password', 'newpassword')) + .then(() => { + const actions = store.getActions(); + expect(actions[0]).toEqual(expectedActions[0]); + expect(actions[1]).toEqual(expectedActions[1]); + }); + }); + + it('update password failure', () => { + const expectedActions = [ + { type: actionTypes.UPDATE_PASSWORD.REQUEST }, + { type: actionTypes.UPDATE_PASSWORD.FAILURE }, + ]; + const store = mockStore({}); + + return store + .dispatch(auth.updatePassword('password', 'newpassword')) + .then(() => { + const actions = store.getActions(); + expect(actions[0]).toEqual(expectedActions[0]); + expect(actions[1].type).toEqual(expectedActions[1].type); + }); + }); +}); diff --git a/app2/src/state/ducks/campaigns.js b/app2/src/state/ducks/campaigns.js new file mode 100644 index 000000000..2dbdcc5ef --- /dev/null +++ b/app2/src/state/ducks/campaigns.js @@ -0,0 +1,216 @@ +/* eslint-disable no-unused-vars */ +import { createSelector } from 'reselect'; +import { normalize } from 'normalizr'; +import { flashMessage } from 'redux-flash'; +import createReducer from '../utils/createReducer'; +import createActionTypes from '../utils/createActionTypes'; +import action from '../utils/action'; +import { addEntities, ADD_ENTITIES, resetState, RESET_STATE } from './common'; +import { inviteUser } from './users'; +import { getCurrentCampaignId } from './auth'; + +export const STATE_KEY = 'campaigns'; + +// Action Types +export const actionTypes = { + CREATE_CAMPAIGN: createActionTypes(STATE_KEY, 'CREATE_CAMPAIGN'), + SET_CAMPAIGN: createActionTypes(STATE_KEY, 'SET_CAMPAIGN'), + GET_CAMPAIGNS: createActionTypes(STATE_KEY, 'GET_CAMPAIGNS'), + UPDATE_CAMPAIGN_NAME: createActionTypes(STATE_KEY, 'UPDATE_CAMPAIGN_NAME'), +}; + +// Initial State +export const initialState = { + isLoading: false, + error: null, + currentCampaignId: null, + list: {}, +}; + +export const resetCampaignState = resetState; +// Reducer +export default createReducer(initialState, { + [RESET_STATE]: () => { + return { ...initialState }; + }, + [ADD_ENTITIES]: (state, action) => { + return { ...state, list: action.payload.campaigns }; + }, + [actionTypes.CREATE_CAMPAIGN.REQUEST]: (state, action) => { + return { ...state, isLoading: true }; + }, + [actionTypes.CREATE_CAMPAIGN.SUCCESS]: (state, action) => { + return { ...state, isLoading: false }; + }, + [actionTypes.CREATE_CAMPAIGN.FAILURE]: (state, action) => { + return { ...state, isLoading: false, error: action.error }; + }, + [actionTypes.SET_CAMPAIGN.SUCCESS]: (state, action) => { + return { ...state, currentCampaignId: action.campaignId }; + }, + [actionTypes.GET_CAMPAIGNS.REQUEST]: (state, action) => { + return { ...state, isLoading: true }; + }, + [actionTypes.GET_CAMPAIGNS.SUCCESS]: (state, action) => { + return { ...state, isLoading: false }; + }, + [actionTypes.GET_CAMPAIGNS.FAILURE]: (state, action) => { + return { ...state, isLoading: false, error: action.error }; + }, +}); + +// Action Creators +export const actionCreators = { + createCampaign: { + request: () => action(actionTypes.CREATE_CAMPAIGN.REQUEST), + success: () => action(actionTypes.CREATE_CAMPAIGN.SUCCESS), + failure: error => action(actionTypes.CREATE_CAMPAIGN.FAILURE, { error }), + }, + setCampaign: { + success: campaignId => + action(actionTypes.SET_CAMPAIGN.SUCCESS, { campaignId }), + }, + getCampaigns: { + request: () => action(actionTypes.GET_CAMPAIGNS.REQUEST), + success: () => action(actionTypes.GET_CAMPAIGNS.SUCCESS), + failure: error => action(actionTypes.GET_CAMPAIGNS.FAILURE, { error }), + }, + updateCampaignName: { + request: () => action(actionTypes.UPDATE_CAMPAIGN_NAME.REQUEST), + success: () => action(actionTypes.UPDATE_CAMPAIGN_NAME.SUCCESS), + failure: error => + action(actionTypes.UPDATE_CAMPAIGN_NAME.FAILURE, { error }), + }, +}; + +// Side Effects, e.g. thunks +export function createCampaignForGovernment( + governmentId, + campaignName, + officeSought, + email, + firstName, + lastName +) { + return async (dispatch, getState, { api, schema }) => { + dispatch(actionCreators.createCampaign.request()); + const campaignAttrs = { + governmentId, + name: campaignName, + officeSought, + }; + try { + const response = await api.createCampaignForGovernment(campaignAttrs); + if (response.status === 201) { + const data = normalize(await response.json(), schema.campaign); + dispatch(addEntities(data.entities)); + dispatch(actionCreators.createCampaign.success()); + dispatch( + inviteUser( + email, + firstName, + lastName, + data.result, + api.UserRoleEnum.CAMPAIGN_ADMIN + ) + ); + dispatch( + flashMessage('Campaign created', { props: { variant: 'success' } }) + ); + } else { + dispatch(actionCreators.createCampaign.failure()); + dispatch( + flashMessage('Unable to create Campaign', { + props: { variant: 'error' }, + }) + ); + } + } catch (error) { + dispatch(actionCreators.createCampaign.failure(error)); + dispatch( + flashMessage(`Unable to create Campaign - ${error}`, { + props: { variant: 'error' }, + }) + ); + } + }; +} + +export function updateCampaignName(governmentId, campaignId, campaignName) { + return async (dispatch, getState, { api, schema }) => { + dispatch(actionCreators.updateCampaignName.request()); + const campaignAttrs = { + governmentId, + campaignId, + newName: campaignName, + }; + try { + const response = await api.updateCampaignNameForGovernment(campaignAttrs); + if (response.status === 201) { + dispatch(actionCreators.updateCampaignName.success()); + dispatch( + flashMessage('Campaign name updated', { + props: { + variant: 'success', + }, + }) + ); + } + } catch (error) { + dispatch(actionCreators.updateCampaignName.failure(error)); + dispatch( + flashMessage(`Unable to update campaign name - ${error}`, { + props: { variant: 'error' }, + }) + ); + } + }; +} + +export function getCampaigns(governmentId) { + return async (dispatch, getState, { api, schema }) => { + dispatch(actionCreators.getCampaigns.request()); + + try { + const response = await api.getCampaignsForGovernment(governmentId); + if (Array.isArray(response)) { + const data = normalize(response, [schema.campaign]); + dispatch(addEntities(data.entities)); + dispatch(actionCreators.getCampaigns.success()); + } else { + dispatch(actionCreators.getCampaigns.failure()); + } + } catch (error) { + dispatch(actionCreators.getCampaigns.failure(error)); + } + }; +} + +// Selectors +export const rootState = state => state || {}; + +export const getCampaignInfo = createSelector( + rootState, + state => state.campaigns +); + +// Assumes one campaign +export const getCampaignName = state => { + const id = getCurrentCampaignId(state); + + return id && + state.campaigns.list && + state.campaigns.list[id] && + state.campaigns.list[id].name + ? state.campaigns.list[id].name + : 'Campaign'; +}; + +export const getCampaignList = createSelector(rootState, state => { + return state.campaigns.list ? Object.values(state.campaigns.list) : [{}]; +}); + +export const isCampaignsLoading = createSelector( + rootState, + state => state.campaigns.isLoading +); diff --git a/app2/src/state/ducks/campaigns.test.js b/app2/src/state/ducks/campaigns.test.js new file mode 100644 index 000000000..e02d12903 --- /dev/null +++ b/app2/src/state/ducks/campaigns.test.js @@ -0,0 +1,233 @@ +/* eslint-disable no-unused-vars */ +import configureMockStore from 'redux-mock-store'; +import thunk from 'redux-thunk'; +import * as campaigns from './campaigns'; +import * as api from '../../api'; +import * as schema from '../../api/schema'; +import { ADD_ENTITIES } from './common'; + +const { actionTypes, actionCreators } = campaigns; + +const middlewares = [thunk.withExtraArgument({ api, schema })]; +const mockStore = configureMockStore(middlewares); + +const govAdmin = { + email: 'govadmin@openelectionsportland.org', + password: 'password', +}; + +const invite = { + code: 'inviteme', + email: 'campaignStaff+1@openelectionsportland.org', + password: 'password', +}; + +const reset = { + code: 'resetme', + password: 'newpassword', +}; + +describe('Reducer', () => { + const reducer = campaigns.default; + it('initial state', () => { + expect(reducer(undefined, {})).toEqual({ + currentCampaignId: null, + isLoading: false, + error: null, + list: {}, + }); + }); + + it('adds campaign entities', () => { + expect( + reducer(undefined, { + type: ADD_ENTITIES, + payload: { + campaigns: { + '1': {}, + }, + }, + }) + ).toEqual({ + list: { + '1': {}, + }, + currentCampaignId: null, + isLoading: false, + error: null, + }); + }); + + it('sets current campaign', () => { + expect( + reducer( + { + currentCampaignId: null, + isLoading: false, + error: null, + }, + { + type: actionTypes.SET_CAMPAIGN.SUCCESS, + campaignId: 1, + } + ) + ).toEqual({ + currentCampaignId: 1, + isLoading: false, + error: null, + }); + }); +}); + +describe('Action Creators', () => { + it('create campaign request', () => { + const expectedAction = { + type: actionTypes.CREATE_CAMPAIGN.REQUEST, + }; + expect(actionCreators.createCampaign.request()).toEqual(expectedAction); + }); + it('create campaign success', () => { + const expectedAction = { + type: actionTypes.CREATE_CAMPAIGN.SUCCESS, + }; + expect(actionCreators.createCampaign.success()).toEqual(expectedAction); + }); + it('create campaign failure', () => { + const expectedAction = { + type: actionTypes.CREATE_CAMPAIGN.FAILURE, + }; + expect(actionCreators.createCampaign.failure()).toEqual(expectedAction); + }); + it('set campaign success', () => { + const expectedAction = { + type: actionTypes.SET_CAMPAIGN.SUCCESS, + campaignId: 1, + }; + expect(actionCreators.setCampaign.success(1)).toEqual(expectedAction); + }); + it('update campaign name request', () => { + const expectedAction = { + type: actionTypes.UPDATE_CAMPAIGN_NAME.REQUEST, + }; + expect(actionCreators.updateCampaignName.request()).toEqual(expectedAction); + }); + it('update campaign name success', () => { + const expectedAction = { + type: actionTypes.UPDATE_CAMPAIGN_NAME.SUCCESS, + }; + expect(actionCreators.updateCampaignName.success()).toEqual(expectedAction); + }); + it('update campaign name failure', () => { + const expectedAction = { + type: actionTypes.UPDATE_CAMPAIGN_NAME.FAILURE, + }; + expect(actionCreators.updateCampaignName.failure()).toEqual(expectedAction); + }); +}); + +let govAdminToken; +let campaignAdminToken; +let campaignStaffToken; +let governmentId; +let campaignId; +describe.only('Side Effects', () => { + beforeAll(async () => { + let tokenResponse = await api.login( + 'govadmin@openelectionsportland.org', + 'password' + ); + govAdminToken = tokenResponse.headers + .get('set-cookie') + .match(/=([a-zA-Z0-9].+); Path/)[1]; + let decodedToken = api.decodeToken(govAdminToken); + governmentId = decodedToken.permissions[0].governmentId; + + tokenResponse = await api.login( + 'campaignadmin@openelectionsportland.org', + 'password' + ); + campaignAdminToken = tokenResponse.headers + .get('set-cookie') + .match(/=([a-zA-Z0-9].+); Path/)[1]; + decodedToken = api.decodeToken(campaignAdminToken); + campaignId = decodedToken.permissions[0].campaignId; + + tokenResponse = await api.login( + 'campaignstaff@openelectionsportland.org', + 'password' + ); + campaignStaffToken = tokenResponse.headers + .get('set-cookie') + .match(/=([a-zA-Z0-9].+); Path/)[1]; + }); + + beforeEach(() => { + delete process.env.TOKEN; + }); + + it('creates campaign for government testme', async () => { + const expectedActions = [ + { type: actionTypes.CREATE_CAMPAIGN.REQUEST }, + { type: ADD_ENTITIES }, + { type: actionTypes.CREATE_CAMPAIGN.SUCCESS }, + ]; + const store = mockStore({}); + + process.env.TOKEN = govAdminToken; + + return store + .dispatch( + campaigns.createCampaignForGovernment( + governmentId, + 'Test New Gov Campaign', + 'Mayor', + 'campaignadminbygov@openelectionsportland.org', + 'CampaignAdmin', + 'InvitedByGov' + ) + ) + .then(() => { + const actions = store.getActions(); + expect(actions[0].type).toEqual(expectedActions[0].type); + expect(actions[1].type).toEqual(expectedActions[1].type); + expect(actions[2].type).toEqual(expectedActions[2].type); + }); + }); + + it('updates campaign name', async () => { + const expectedActions = [ + { type: actionTypes.UPDATE_CAMPAIGN_NAME.REQUEST }, + { type: actionTypes.UPDATE_CAMPAIGN_NAME.SUCCESS }, + ]; + const store = mockStore({}); + + process.env.TOKEN = govAdminToken; + + return store + .dispatch( + campaigns.updateCampaignName(governmentId, campaignId, 'campaignName') + ) + .then(() => { + const actions = store.getActions(); + expect(actions[0].type).toEqual(expectedActions[0].type); + }); + }); + + it('gets campaigns', async () => { + const expectedActions = [ + { type: actionTypes.GET_CAMPAIGNS.REQUEST }, + { type: ADD_ENTITIES }, + { type: actionTypes.GET_CAMPAIGNS.SUCCESS }, + ]; + const store = mockStore({}); + + process.env.TOKEN = govAdminToken; + + return store.dispatch(campaigns.getCampaigns(governmentId)).then(() => { + const actions = store.getActions(); + expect(actions[0].type).toEqual(expectedActions[0].type); + expect(actions[1].type).toEqual(expectedActions[1].type); + expect(actions[2].type).toEqual(expectedActions[2].type); + }); + }); +}); diff --git a/app2/src/state/ducks/common.js b/app2/src/state/ducks/common.js new file mode 100644 index 000000000..b690c379f --- /dev/null +++ b/app2/src/state/ducks/common.js @@ -0,0 +1,30 @@ +export const ADD_ENTITIES = 'ADD_ENTITIES'; +export const addEntities = entities => { + return { + type: ADD_ENTITIES, + payload: entities, + }; +}; + +export const ADD_CONTRIBUTION_ENTITIES = 'ADD_CONTRIBUTION_ENTITIES'; +export const addContributionEntities = entities => { + return { + type: ADD_CONTRIBUTION_ENTITIES, + payload: entities, + }; +}; + +export const ADD_EXPENDITURE_ENTITIES = 'ADD_EXPENDITURE_ENTITIES'; +export const addExpenditureEntities = entities => { + return { + type: ADD_EXPENDITURE_ENTITIES, + payload: entities, + }; +}; + +export const RESET_STATE = 'RESET_STATE'; +export const resetState = () => { + return { + type: RESET_STATE, + }; +}; diff --git a/app2/src/state/ducks/contributions.js b/app2/src/state/ducks/contributions.js new file mode 100644 index 000000000..89be3bd85 --- /dev/null +++ b/app2/src/state/ducks/contributions.js @@ -0,0 +1,441 @@ +/* eslint-disable no-unused-vars */ +import { normalize } from 'normalizr'; +import { createSelector } from 'reselect'; +import { isEmpty } from 'lodash'; +import { flashMessage } from 'redux-flash'; +import { push } from 'connected-react-router'; +import createReducer from '../utils/createReducer'; +import createActionTypes, { + createCustomActionTypes, +} from '../utils/createActionTypes'; +import action from '../utils/action'; +import { + addContributionEntities, + ADD_CONTRIBUTION_ENTITIES, + resetState, + RESET_STATE, +} from './common'; +import { getActivitiesByIdType } from './activities'; +import { downloadFile } from '../utils/helpers'; +import { isGovAdmin } from './auth'; +import { getMatchesByContributionId } from './matches'; +import { getContributionsByMatchId } from './pastContributions'; + +export const STATE_KEY = 'contributions'; + +// Action Types +export const actionTypes = { + CREATE_CONTRIBUTION: createActionTypes(STATE_KEY, 'CREATE_CONTRIBUTION'), + UPDATE_CONTRIBUTION: createActionTypes(STATE_KEY, 'UPDATE_CONTRIBUTION'), + GET_CONTRIBUTIONS: createActionTypes(STATE_KEY, 'GET_CONTRIBUTIONS'), + GET_CONTRIBUTION_BY_ID: createActionTypes( + STATE_KEY, + 'GET_CONTRIBUTION_BY_ID' + ), + ARCHIVE_CONTRIBUTION: createActionTypes(STATE_KEY, 'ARCHIVE_CONTRIBUTION'), + POST_CONTRIBUTION_COMMENT: createActionTypes( + STATE_KEY, + 'POST_CONTRIBUTION_COMMENT' + ), + GET_MATCHES_BY_CONTRIBUTION_ID: createActionTypes( + STATE_KEY, + 'GET_MATCHES_BY_CONTRIBUTION_ID' + ), + FILTER: createCustomActionTypes(STATE_KEY, 'FILTER', ['UPDATE']), +}; + +// Initial State +export const initialState = { + list: null, + listOrder: [], + listFilterOptions: { + from: '', + to: '', + status: 'all', + page: 0, + perPage: 50, + sort: {}, + }, + isLoading: false, + error: null, + currentId: 0, + total: 0, +}; + +export const resetContributionState = resetState; +// Reducer +export default createReducer(initialState, { + [RESET_STATE]: () => { + return { ...initialState }; + }, + [ADD_CONTRIBUTION_ENTITIES]: (state, action) => { + return { + ...state, + list: { ...action.payload.entities.contributions }, + listOrder: action.payload.result, + }; + }, + [actionTypes.CREATE_CONTRIBUTION.REQUEST]: (state, action) => { + return { ...state, isLoading: true }; + }, + [actionTypes.CREATE_CONTRIBUTION.SUCCESS]: (state, action) => { + return { ...state, isLoading: false }; + }, + [actionTypes.CREATE_CONTRIBUTION.FAILURE]: (state, action) => { + return { ...state, isLoading: false, error: action.error }; + }, + [actionTypes.UPDATE_CONTRIBUTION.REQUEST]: (state, action) => { + return { ...state, isLoading: true }; + }, + [actionTypes.UPDATE_CONTRIBUTION.SUCCESS]: (state, action) => { + return { ...state, isLoading: false }; + }, + [actionTypes.UPDATE_CONTRIBUTION.FAILURE]: (state, action) => { + return { ...state, isLoading: false, error: action.error }; + }, + [actionTypes.GET_CONTRIBUTIONS.REQUEST]: (state, action) => { + return { ...state, isLoading: true }; + }, + [actionTypes.GET_CONTRIBUTIONS.SUCCESS]: (state, action) => { + return { + ...state, + isLoading: false, + total: action.total, + }; + }, + [actionTypes.GET_CONTRIBUTIONS.FAILURE]: (state, action) => { + return { ...state, isLoading: false, error: action.error }; + }, + [actionTypes.GET_CONTRIBUTION_BY_ID.REQUEST]: (state, action) => { + return { ...state, isLoading: true }; + }, + [actionTypes.GET_CONTRIBUTION_BY_ID.SUCCESS]: (state, action) => { + return { + ...state, + isLoading: false, + currentId: action.id, + }; + }, + [actionTypes.GET_CONTRIBUTION_BY_ID.FAILURE]: (state, action) => { + return { ...state, isLoading: false, error: action.error }; + }, + [actionTypes.ARCHIVE_CONTRIBUTION.REQUEST]: (state, action) => { + return { ...state, isLoading: true }; + }, + [actionTypes.ARCHIVE_CONTRIBUTION.SUCCESS]: state => { + return { ...state, isLoading: false }; + }, + [actionTypes.ARCHIVE_CONTRIBUTION.FAILURE]: state => { + return { ...state, isLoading: false, error: action.error }; + }, + [actionTypes.POST_CONTRIBUTION_COMMENT.REQUEST]: (state, action) => { + return { ...state, isLoading: true }; + }, + [actionTypes.POST_CONTRIBUTION_COMMENT.SUCCESS]: state => { + return { ...state, isLoading: false }; + }, + [actionTypes.POST_CONTRIBUTION_COMMENT.FAILURE]: (state, action) => { + return { ...state, isLoading: false, error: action.error }; + }, + [actionTypes.FILTER.UPDATE]: (state, action) => { + return { ...state, listFilterOptions: action.listFilterOptions }; + }, +}); + +// Action Creators +export const actionCreators = { + createContribution: { + request: () => action(actionTypes.CREATE_CONTRIBUTION.REQUEST), + success: () => action(actionTypes.CREATE_CONTRIBUTION.SUCCESS), + failure: error => + action(actionTypes.CREATE_CONTRIBUTION.FAILURE, { error }), + }, + updateContribution: { + request: () => action(actionTypes.UPDATE_CONTRIBUTION.REQUEST), + success: () => action(actionTypes.UPDATE_CONTRIBUTION.SUCCESS), + failure: error => + action(actionTypes.UPDATE_CONTRIBUTION.FAILURE, { error }), + }, + getContributions: { + request: () => action(actionTypes.GET_CONTRIBUTIONS.REQUEST), + success: total => action(actionTypes.GET_CONTRIBUTIONS.SUCCESS, { total }), + failure: error => action(actionTypes.GET_CONTRIBUTIONS.FAILURE, { error }), + }, + getContributionById: { + request: () => action(actionTypes.GET_CONTRIBUTION_BY_ID.REQUEST), + success: id => action(actionTypes.GET_CONTRIBUTION_BY_ID.SUCCESS, { id }), + failure: error => + action(actionTypes.GET_CONTRIBUTION_BY_ID.FAILURE, { error }), + }, + archiveContribution: { + request: () => action(actionTypes.ARCHIVE_CONTRIBUTION.REQUEST), + success: () => action(actionTypes.ARCHIVE_CONTRIBUTION.SUCCESS), + failure: error => + action(actionTypes.ARCHIVE_CONTRIBUTION.FAILURE, { error }), + }, + postContributionComment: { + request: () => action(actionTypes.POST_CONTRIBUTION_COMMENT.REQUEST), + success: () => action(actionTypes.POST_CONTRIBUTION_COMMENT.SUCCESS), + failure: error => + action(actionTypes.POST_CONTRIBUTION_COMMENT.FAILURE, { error }), + }, + filter: { + update: listFilterOptions => { + return action(actionTypes.FILTER.UPDATE, { listFilterOptions }); + }, + }, +}; + +// Side Effects, e.g. thunks +export function updateFilter(newFilterOptions) { + return (dispatch, getState) => { + // eslint-disable-next-line prefer-const + let filterOptions = getState().contributions.listFilterOptions; + if (newFilterOptions.perPage) { + filterOptions.page = Math.floor( + (filterOptions.page * filterOptions.perPage) / newFilterOptions.perPage + ); + } + Object.entries(filterOptions).forEach(([key, value]) => { + if (Object.prototype.hasOwnProperty.call(newFilterOptions, key)) + filterOptions[key] = newFilterOptions[key]; + }); + dispatch(actionCreators.filter.update(filterOptions)); + }; +} + +export const getFilterOptionsForRequest = state => { + const filter = state.contributions.listFilterOptions; + const sort = state.contributions.listFilterOptions.sort || {}; + const returnObj = {}; + + Object.entries(filter).forEach(([key, value]) => { + // Look for any filters such as status + if (value) { + returnObj[key] = value; + } + }); + if (sort.field) { + // If the sort field is set make sure there is also a direction + returnObj.sort = { + field: sort.field, + direction: sort.direction || 'DESC', + }; + } else { + // Remove sort if there isn't any, defauts to last modified DESC + delete returnObj.sort; + } + + // API defaults to all statuses but all is not a status + if (returnObj.status === 'all') delete returnObj.status; + + // Always pass in the pagination to maintain sync with table + returnObj.perPage = filter.perPage; + returnObj.page = filter.page * filter.perPage; + return returnObj; +}; + +export function createContribution(contributionAttrs) { + return async (dispatch, getState, { api, schema }) => { + dispatch(actionCreators.createContribution.request()); + try { + const response = await api.createContribution(contributionAttrs); + if (response.status === 201) { + const data = normalize(await response.json(), schema.contribution); + dispatch(addContributionEntities(data)); + dispatch(actionCreators.createContribution.success()); + dispatch( + flashMessage(`Contribution Added`, { + props: { variant: 'success' }, + }) + ); + dispatch(push(`/contributions/${data.result}`)); + return data.result; + } + dispatch(actionCreators.createContribution.failure()); + dispatch( + flashMessage(`Error - ${response.status} status returned`, { + props: { variant: 'error' }, + }) + ); + } catch (error) { + dispatch(actionCreators.createContribution.failure(error)); + dispatch( + flashMessage(`Error - ${error}`, { props: { variant: 'error' } }) + ); + } + }; +} + +export function updateContribution(contributionAttrs) { + return async (dispatch, getState, { api, schema }) => { + dispatch(actionCreators.updateContribution.request()); + try { + const response = await api.updateContribution(contributionAttrs); + if (response.status === 204) { + let status = ''; + if (contributionAttrs.status) { + status = contributionAttrs.status; + } + dispatch(actionCreators.updateContribution.success()); + dispatch( + flashMessage(`Contribution Updated ${status}`, { + props: { variant: 'success' }, + }) + ); + dispatch(push('/contributions')); + } else { + dispatch(actionCreators.updateContribution.failure()); + const error = await response.json(); + dispatch( + flashMessage(`Error - ${error}`, { props: { variant: 'error' } }) + ); + return error; + } + } catch (error) { + dispatch(actionCreators.updateContribution.failure(error)); + dispatch( + flashMessage(`Error - ${error}`, { props: { variant: 'error' } }) + ); + return error; + } + }; +} + +export function getContributions(contributionSearchAttrs, applyFilter = false) { + return async (dispatch, getState, { api, schema }) => { + dispatch(actionCreators.getContributions.request()); + try { + const filter = applyFilter ? getFilterOptionsForRequest(getState()) : {}; + const response = await api.getContributions({ + ...contributionSearchAttrs, + ...filter, + }); + if (contributionSearchAttrs.format === 'csv' && response.status === 200) { + const contributions = await response.text(); + downloadFile(contributions, `contributions-download-${Date.now()}.csv`); + } else if ( + contributionSearchAttrs.format === 'xml' && + response.status === 200 + ) { + const contributions = await response.json(); + contributions.map((contribution, index) => { + return downloadFile( + contribution, + `contributions-download-${index + 1}-${Date.now()}.xml` + ); + }); + } else if (response.status === 200) { + const contributions = await response.json(); + const data = normalize(contributions.data, [schema.contribution]); + dispatch(addContributionEntities(data)); + dispatch(actionCreators.getContributions.success(contributions.total)); + } else { + dispatch(actionCreators.getContributions.failure()); + } + } catch (error) { + dispatch(actionCreators.getContributions.failure(error)); + } + }; +} + +export function getContributionById(id) { + return async (dispatch, getState, { api, schema }) => { + dispatch(actionCreators.getContributionById.request()); + try { + const response = await api.getContributionById(id); + if (response.status === 200) { + const json = await response.json(); + const data = normalize(json, schema.contribution); + dispatch(addContributionEntities(data)); + dispatch(actionCreators.getContributionById.success(id)); + if (isGovAdmin(getState())) { + dispatch(getMatchesByContributionId(id)); + if (json.matchId) { + dispatch(getContributionsByMatchId(json.matchId)); + } + } + // dispatch(getContributionActivities(id)); + } else { + dispatch(actionCreators.getContributionById.failure()); + } + } catch (error) { + dispatch(actionCreators.getContributionById.failure(error)); + } + }; +} + +export function archiveContribution(id) { + return async (dispatch, getState, { api, schema }) => { + dispatch(actionCreators.archiveContribution.request()); + try { + const response = await api.archiveContribution(id); + if (response.status === 200) { + const data = normalize(await response.json(), schema.contribution); + dispatch(addContributionEntities(data)); + dispatch(actionCreators.archiveContribution.success()); + } else { + dispatch(actionCreators.archiveContribution.failure()); + } + } catch (error) { + dispatch(actionCreators.archiveContribution.failure(error)); + } + }; +} + +export function postContributionComment(id, comment, attachment) { + return async (dispatch, getState, { api, schema }) => { + dispatch(actionCreators.postContributionComment.request()); + try { + const response = await api.postContributionComment( + id, + comment, + attachment + ); + if (response.status === 204) { + dispatch(getActivitiesByIdType({ contributionId: id })); + dispatch(actionCreators.postContributionComment.success()); + } else { + dispatch(actionCreators.postContributionComment.failure()); + } + } catch (error) { + dispatch(actionCreators.postContributionComment.failure(error)); + } + }; +} + +// Selectors +export const rootState = state => state || {}; + +export const getContributionsList = createSelector(rootState, state => { + if ( + isEmpty(state.contributions.list) || + isEmpty(state.contributions.listOrder) + ) { + return []; + } + return state.contributions.listOrder.map(id => state.contributions.list[id]); +}); + +export const getContributionsTotal = createSelector(rootState, state => { + return state.contributions.total; +}); + +export const getCurrentContribution = state => { + return state.contributions && + state.contributions.list && + state.contributions.currentId + ? state.contributions.list[state.contributions.currentId] + : false; +}; + +export const getContributionCampaignName = state => { + const contribution = getCurrentContribution(state); + return contribution ? contribution.campaign.name : null; +}; + +export const getFilterOptions = state => { + const filter = state.contributions.listFilterOptions; + const sort = state.contributions.listFilterOptions.sort || {}; + return { ...filter, sort }; +}; diff --git a/app2/src/state/ducks/contributions.test.js b/app2/src/state/ducks/contributions.test.js new file mode 100644 index 000000000..3bf9d165a --- /dev/null +++ b/app2/src/state/ducks/contributions.test.js @@ -0,0 +1,363 @@ +import configureMockStore from 'redux-mock-store'; +import thunk from 'redux-thunk'; +import * as contributions from './contributions'; +import * as activities from './activities'; +import * as api from '../../api'; +import * as schema from '../../api/schema'; +import { ADD_CONTRIBUTION_ENTITIES } from './common'; + +const { actionTypes, actionCreators } = contributions; + +const middlewares = [thunk.withExtraArgument({ api, schema })]; +const mockStore = configureMockStore(middlewares); + +describe('Reducer', () => { + const reducer = contributions.default; + it('initial state', () => { + expect(reducer(undefined, {})).toEqual({ + list: null, + isLoading: false, + error: null, + currentId: 0, + listOrder: [], + listFilterOptions: { + from: '', + to: '', + status: 'all', + page: 0, + perPage: 50, + sort: {}, + }, + total: 0, + }); + }); + + it('adds contribution entities', () => { + expect( + reducer(undefined, { + type: ADD_CONTRIBUTION_ENTITIES, + payload: { + entities: { + contributions: { + '1': {}, + }, + }, + }, + }) + ).toEqual({ + list: { + '1': {}, + }, + isLoading: false, + listFilterOptions: { + from: '', + to: '', + status: 'all', + page: 0, + perPage: 50, + sort: {}, + }, + error: null, + currentId: 0, + total: 0, + }); + }); +}); + +describe('Action Creators', () => { + it('create contribution request', () => { + const expectedAction = { + type: actionTypes.CREATE_CONTRIBUTION.REQUEST, + }; + expect(actionCreators.createContribution.request()).toEqual(expectedAction); + }); + it('create contribution success', () => { + const expectedAction = { + type: actionTypes.CREATE_CONTRIBUTION.SUCCESS, + }; + expect(actionCreators.createContribution.success()).toEqual(expectedAction); + }); + it('create contribution failure', () => { + const expectedAction = { + type: actionTypes.CREATE_CONTRIBUTION.FAILURE, + }; + expect(actionCreators.createContribution.failure()).toEqual(expectedAction); + }); +}); + +let govAdminToken; +let campaignAdminToken; +let campaignStaffToken; +let governmentId; +let campaignId; +let campaignStaffId; +let campaignAdminId; +describe('Side Effects', () => { + beforeAll(async () => { + let tokenResponse = await api.login( + 'govadmin@openelectionsportland.org', + 'password' + ); + govAdminToken = tokenResponse.headers + .get('set-cookie') + .match(/=([a-zA-Z0-9].+); Path/)[1]; + let decodedToken = api.decodeToken(govAdminToken); + governmentId = decodedToken.permissions[0].governmentId; + + tokenResponse = await api.login( + 'campaignadmin@openelectionsportland.org', + 'password' + ); + campaignAdminToken = tokenResponse.headers + .get('set-cookie') + .match(/=([a-zA-Z0-9].+); Path/)[1]; + decodedToken = api.decodeToken(campaignAdminToken); + campaignId = decodedToken.permissions[0].campaignId; + + campaignAdminId = decodedToken.id; + + tokenResponse = await api.login( + 'campaignstaff@openelectionsportland.org', + 'password' + ); + campaignStaffToken = tokenResponse.headers + .get('set-cookie') + .match(/=([a-zA-Z0-9].+); Path/)[1]; + decodedToken = api.decodeToken(campaignStaffToken); + campaignStaffId = decodedToken.id; + }); + + beforeEach(() => { + delete process.env.TOKEN; + }); + + it('creates contribution', async () => { + const expectedActions = [ + { type: actionTypes.CREATE_CONTRIBUTION.REQUEST }, + { type: ADD_CONTRIBUTION_ENTITIES }, + { type: actionTypes.CREATE_CONTRIBUTION.SUCCESS }, + ]; + const store = mockStore({}); + + process.env.TOKEN = campaignStaffToken; + return store + .dispatch( + contributions.createContribution({ + address1: '123 ABC ST', + amount: 250, + campaignId, + city: 'Portland', + currentUserId: campaignStaffId, + date: 1562436237619, + firstName: 'John', + middleInitial: '', + lastName: 'Doe', + governmentId, + type: api.ContributionTypeEnum.CONTRIBUTION, + subType: api.ContributionSubTypeEnum.CASH, + paymentMethod: api.PaymentMethodEnum.CASH, + state: 'OR', + status: api.ContributionStatusEnum.DRAFT, + zip: '97214', + contributorType: api.ContributorTypeEnum.INDIVIDUAL, + }) + ) + .then(() => { + const actions = store.getActions(); + expect(actions[0].type).toEqual(expectedActions[0].type); + expect(actions[1].type).toEqual(expectedActions[1].type); + expect(actions[2].type).toEqual(expectedActions[2].type); + }); + }); + + it('updates contribution', async () => { + const expectedActions = [ + { type: actionTypes.UPDATE_CONTRIBUTION.REQUEST }, + { type: actionTypes.UPDATE_CONTRIBUTION.SUCCESS }, + ]; + const store = mockStore({}); + + process.env.TOKEN = campaignAdminToken; + + const contribution = await api.createContribution({ + address1: '123 ABC ST', + amount: 250, + campaignId, + city: 'Portland', + currentUserId: campaignAdminId, + date: 1562436237619, + firstName: 'John', + middleInitial: '', + lastName: 'Doe', + governmentId, + type: api.ContributionTypeEnum.CONTRIBUTION, + subType: api.ContributionSubTypeEnum.CASH, + paymentMethod: api.PaymentMethodEnum.CASH, + state: 'OR', + status: api.ContributionStatusEnum.DRAFT, + zip: '97214', + contributorType: api.ContributorTypeEnum.INDIVIDUAL, + }); + const { id } = await contribution.json(); + + return store + .dispatch( + contributions.updateContribution({ + id, + firstName: 'Ian', + currentUserId: campaignAdminId, + }) + ) + .then(() => { + const actions = store.getActions(); + expect(actions[0].type).toEqual(expectedActions[0].type); + expect(actions[1].type).toEqual(expectedActions[1].type); + }); + }); + + it('gets contributions', async () => { + const expectedActions = [ + { type: actionTypes.GET_CONTRIBUTIONS.REQUEST }, + { type: ADD_CONTRIBUTION_ENTITIES }, + { type: actionTypes.GET_CONTRIBUTIONS.SUCCESS }, + ]; + const store = mockStore({}); + + process.env.TOKEN = campaignAdminToken; + + return store + .dispatch( + contributions.getContributions({ + governmentId, + campaignId, + currentUserId: campaignAdminId, + }) + ) + .then(() => { + const actions = store.getActions(); + expect(actions[0].type).toEqual(expectedActions[0].type); + expect(actions[1].type).toEqual(expectedActions[1].type); + expect(actions[2].type).toEqual(expectedActions[2].type); + }); + }); + + it('gets contribution by id', async () => { + const expectedActions = [ + { type: actionTypes.GET_CONTRIBUTION_BY_ID.REQUEST }, + { type: ADD_CONTRIBUTION_ENTITIES }, + { type: actionTypes.GET_CONTRIBUTION_BY_ID.SUCCESS }, + ]; + const store = mockStore({}); + + process.env.TOKEN = campaignAdminToken; + + const contribution = await api.createContribution({ + address1: '123 ABC ST', + amount: 250, + campaignId, + city: 'Portland', + currentUserId: campaignAdminId, + date: 1562436237619, + firstName: 'John', + middleInitial: '', + lastName: 'Doe', + governmentId, + type: api.ContributionTypeEnum.CONTRIBUTION, + subType: api.ContributionSubTypeEnum.CASH, + paymentMethod: api.PaymentMethodEnum.CASH, + state: 'OR', + status: api.ContributionStatusEnum.DRAFT, + zip: '97214', + contributorType: api.ContributorTypeEnum.INDIVIDUAL, + }); + const { id } = await contribution.json(); + + return store.dispatch(contributions.getContributionById(id)).then(() => { + const actions = store.getActions(); + expect(actions[0].type).toEqual(expectedActions[0].type); + expect(actions[1].type).toEqual(expectedActions[1].type); + expect(actions[2].type).toEqual(expectedActions[2].type); + }); + }); + + it('archives contribution by id', async () => { + const expectedActions = [ + { type: actionTypes.ARCHIVE_CONTRIBUTION.REQUEST }, + { type: ADD_CONTRIBUTION_ENTITIES }, + { type: actionTypes.ARCHIVE_CONTRIBUTION.SUCCESS }, + ]; + const store = mockStore({}); + + process.env.TOKEN = campaignAdminToken; + + const contribution = await api.createContribution({ + address1: '123 ABC ST', + amount: 250, + campaignId, + city: 'Portland', + currentUserId: campaignAdminId, + date: 1562436237619, + firstName: 'John', + middleInitial: '', + lastName: 'Doe', + governmentId, + type: api.ContributionTypeEnum.CONTRIBUTION, + subType: api.ContributionSubTypeEnum.CASH, + paymentMethod: api.PaymentMethodEnum.CASH, + state: 'OR', + status: api.ContributionStatusEnum.DRAFT, + zip: '97214', + contributorType: api.ContributorTypeEnum.INDIVIDUAL, + }); + const { id } = await contribution.json(); + + return store.dispatch(contributions.archiveContribution(id)).then(() => { + const actions = store.getActions(); + expect(actions[0].type).toEqual(expectedActions[0].type); + expect(actions[1].type).toEqual(expectedActions[1].type); + expect(actions[2].type).toEqual(expectedActions[2].type); + }); + }); + + xit('post comments', async () => { + const expectedActions = [ + { type: actionTypes.POST_CONTRIBUTION_COMMENT.REQUEST }, + { type: activities.actionTypes.GET_CONTRIBUTION_ACTIVITIES.REQUEST }, + { type: actionTypes.POST_CONTRIBUTION_COMMENT.SUCCESS }, + ]; + const store = mockStore({}); + + process.env.TOKEN = campaignAdminToken; + + const contribution = await api.createContribution({ + address1: '123 ABC ST', + amount: 250, + campaignId, + city: 'Portland', + currentUserId: campaignAdminId, + date: 1562436237619, + firstName: 'John', + middleInitial: '', + lastName: 'Doe', + governmentId, + type: api.ContributionTypeEnum.CONTRIBUTION, + subType: api.ContributionSubTypeEnum.CASH, + paymentMethod: api.PaymentMethodEnum.CASH, + state: 'OR', + status: api.ContributionStatusEnum.DRAFT, + zip: '97214', + contributorType: api.ContributorTypeEnum.INDIVIDUAL, + }); + const { id } = await contribution.json(); + + return store + .dispatch(contributions.postContributionComment(id, 'This is a comment')) + .then(() => { + const actions = store.getActions(); + expect(actions.length).toEqual(3); + expect(actions[0].type).toEqual(expectedActions[0].type); + expect(actions[1].type).toEqual(expectedActions[1].type); + expect(actions[2].type).toEqual(expectedActions[2].type); + }); + }); +}); diff --git a/app2/src/state/ducks/expenditures.js b/app2/src/state/ducks/expenditures.js new file mode 100644 index 000000000..bcec51bdf --- /dev/null +++ b/app2/src/state/ducks/expenditures.js @@ -0,0 +1,389 @@ +/* eslint-disable no-unused-vars */ +// campaigns.js +import { normalize } from 'normalizr'; +import { createSelector } from 'reselect'; +import { isEmpty } from 'lodash'; +import { flashMessage } from 'redux-flash'; +import { push } from 'connected-react-router'; +import createReducer from '../utils/createReducer'; +import createActionTypes, { + createCustomActionTypes, +} from '../utils/createActionTypes'; +import action from '../utils/action'; +import { + addExpenditureEntities, + ADD_EXPENDITURE_ENTITIES, + resetState, + RESET_STATE, +} from './common'; +import { downloadFile } from '../utils/helpers'; +import { getActivitiesByIdType } from './activities'; + +export const STATE_KEY = 'expenditures'; + +// Action Types +export const actionTypes = { + CREATE_EXPENDITURE: createActionTypes(STATE_KEY, 'CREATE_EXPENDITURE'), + UPDATE_EXPENDITURE: createActionTypes(STATE_KEY, 'UPDATE_EXPENDITURE'), + GET_EXPENDITURES: createActionTypes(STATE_KEY, 'GET_EXPENDITURES'), + GET_EXPENDITURE_BY_ID: createActionTypes(STATE_KEY, 'GET_EXPENDITURE_BY_ID'), + POST_EXPENDITURE_COMMENT: createActionTypes( + STATE_KEY, + 'POST_EXPENDITURE_COMMENT' + ), + FILTER: createCustomActionTypes(STATE_KEY, 'FILTER', ['UPDATE']), +}; + +// Initial State +export const initialState = { + isLoading: false, + error: null, + list: null, + listFilterOptions: { + from: '', + to: '', + status: 'all', + page: 0, + perPage: 50, + sort: {}, + }, + listOrder: [], + currentId: null, + total: 0, +}; + +export const resetExpenditureState = resetState; +// Reducer +export default createReducer(initialState, { + [RESET_STATE]: () => { + return { ...initialState }; + }, + [ADD_EXPENDITURE_ENTITIES]: (state, action) => { + return { + ...state, + list: { ...action.payload.entities.expenditures }, + listOrder: action.payload.result, + }; + }, + [actionTypes.CREATE_EXPENDITURE.REQUEST]: (state, action) => { + return { ...state, isLoading: true }; + }, + [actionTypes.CREATE_EXPENDITURE.SUCCESS]: (state, action) => { + return { ...state, isLoading: false }; + }, + [actionTypes.CREATE_EXPENDITURE.FAILURE]: (state, action) => { + return { ...state, isLoading: false, error: action.error }; + }, + [actionTypes.UPDATE_EXPENDITURE.REQUEST]: (state, action) => { + return { ...state, isLoading: true }; + }, + [actionTypes.UPDATE_EXPENDITURE.SUCCESS]: (state, action) => { + return { ...state, isLoading: false }; + }, + [actionTypes.UPDATE_EXPENDITURE.FAILURE]: (state, action) => { + return { ...state, isLoading: false, error: action.error }; + }, + [actionTypes.GET_EXPENDITURES.REQUEST]: (state, action) => { + return { ...state, isLoading: true }; + }, + [actionTypes.GET_EXPENDITURES.SUCCESS]: (state, action) => { + return { ...state, isLoading: false, total: action.total }; + }, + [actionTypes.GET_EXPENDITURES.FAILURE]: (state, action) => { + return { ...state, isLoading: false, error: action.error }; + }, + [actionTypes.GET_EXPENDITURE_BY_ID.REQUEST]: (state, action) => { + return { ...state, isLoading: true }; + }, + [actionTypes.GET_EXPENDITURE_BY_ID.SUCCESS]: (state, action) => { + return { + ...state, + isLoading: false, + currentId: action.id, + }; + }, + [actionTypes.GET_EXPENDITURE_BY_ID.FAILURE]: (state, action) => { + return { ...state, isLoading: false, error: action.error }; + }, + [actionTypes.POST_EXPENDITURE_COMMENT.REQUEST]: state => { + return { ...state, isLoading: true }; + }, + [actionTypes.POST_EXPENDITURE_COMMENT.SUCCESS]: state => { + return { ...state, isLoading: false }; + }, + [actionTypes.POST_EXPENDITURE_COMMENT.FAILURE]: (state, action) => { + return { ...state, isLoading: false, error: action.error }; + }, + [actionTypes.FILTER.UPDATE]: (state, action) => { + return { ...state, listFilterOptions: action.listFilterOptions }; + }, +}); + +// Action Creators +export const actionCreators = { + createExpenditure: { + request: () => action(actionTypes.CREATE_EXPENDITURE.REQUEST), + success: () => action(actionTypes.CREATE_EXPENDITURE.SUCCESS), + failure: error => action(actionTypes.CREATE_EXPENDITURE.FAILURE, { error }), + }, + updateExpenditure: { + request: () => action(actionTypes.UPDATE_EXPENDITURE.REQUEST), + success: () => action(actionTypes.UPDATE_EXPENDITURE.SUCCESS), + failure: error => action(actionTypes.UPDATE_EXPENDITURE.FAILURE, { error }), + }, + getExpenditures: { + request: () => action(actionTypes.GET_EXPENDITURES.REQUEST), + success: total => action(actionTypes.GET_EXPENDITURES.SUCCESS, { total }), + failure: error => action(actionTypes.GET_EXPENDITURES.FAILURE, { error }), + }, + getExpenditureById: { + request: () => action(actionTypes.GET_EXPENDITURE_BY_ID.REQUEST), + success: id => action(actionTypes.GET_EXPENDITURE_BY_ID.SUCCESS, { id }), + failure: error => + action(actionTypes.GET_EXPENDITURE_BY_ID.FAILURE, { error }), + }, + postExpenditureComment: { + request: () => action(actionTypes.POST_EXPENDITURE_COMMENT.REQUEST), + success: () => action(actionTypes.POST_EXPENDITURE_COMMENT.SUCCESS), + failure: error => + action(actionTypes.POST_EXPENDITURE_COMMENT.FAILURE, { error }), + }, + filter: { + update: listFilterOptions => { + return action(actionTypes.FILTER.UPDATE, { listFilterOptions }); + }, + }, +}; + +export function updateFilter(newFilterOptions) { + return (dispatch, getState) => { + // eslint-disable-next-line prefer-const + let filterOptions = getState().expenditures.listFilterOptions; + if (newFilterOptions.perPage) { + filterOptions.page = Math.floor( + (filterOptions.page * filterOptions.perPage) / newFilterOptions.perPage + ); + } + Object.entries(filterOptions).forEach(([key, value]) => { + if (Object.prototype.hasOwnProperty.call(newFilterOptions, key)) + filterOptions[key] = newFilterOptions[key]; + }); + dispatch(actionCreators.filter.update(filterOptions)); + }; +} + +export const getFilterOptionsForRequest = state => { + const filter = state.expenditures.listFilterOptions; + const sort = state.expenditures.listFilterOptions.sort || {}; + const returnObj = {}; + + Object.entries(filter).forEach(([key, value]) => { + // Look for any filters such as status + if (value) { + returnObj[key] = value; + } + }); + if (sort.field) { + // If the sort field is set make sure there is also a direction + returnObj.sort = { + field: sort.field, + direction: sort.direction || 'DESC', + }; + } else { + // Remove sort if there isn't any, defauts to last modified DESC + delete returnObj.sort; + } + + // API defaults to all statuses but all is not a status + if (returnObj.status === 'all') delete returnObj.status; + + // Always pass in the pagination to maintain sync with table + returnObj.perPage = filter.perPage; + returnObj.page = filter.page * filter.perPage; + return returnObj; +}; + +// Side Effects, e.g. thunks +export function createExpenditure(expenditureAttrs) { + return async (dispatch, getState, { api, schema }) => { + dispatch(actionCreators.createExpenditure.request()); + try { + const response = await api.createExpenditure(expenditureAttrs); + if (response.status === 201) { + const data = normalize(await response.json(), schema.expenditure); + dispatch(addExpenditureEntities(data)); + dispatch(actionCreators.createExpenditure.success()); + dispatch( + flashMessage(`Expenditure Added`, { + props: { variant: 'success' }, + }) + ); + return data.result; + } + dispatch(actionCreators.createExpenditure.failure()); + dispatch( + flashMessage(`Error - ${response.status} status returned`, { + props: { variant: 'error' }, + }) + ); + } catch (error) { + dispatch(actionCreators.createExpenditure.failure(error)); + dispatch( + flashMessage(`Error - ${error}`, { props: { variant: 'error' } }) + ); + } + }; +} + +export function updateExpenditure(expenditureAttrs) { + return async (dispatch, getState, { api, schema }) => { + dispatch(actionCreators.updateExpenditure.request()); + try { + const response = await api.updateExpenditure(expenditureAttrs); + if (response.status === 204) { + let status = ''; + if (expenditureAttrs.status) { + status = expenditureAttrs.status; + } + dispatch(actionCreators.updateExpenditure.success()); + dispatch( + flashMessage(`Expenditure Updated ${status}`, { + props: { variant: 'success' }, + }) + ); + dispatch(push('/expenses')); + } else { + dispatch(actionCreators.updateExpenditure.failure()); + const error = await response.json(); + dispatch( + flashMessage(`Error - ${error}`, { props: { variant: 'error' } }) + ); + return error; + } + } catch (error) { + dispatch(actionCreators.updateExpenditure.failure(error)); + dispatch( + flashMessage(`Error - ${error}`, { props: { variant: 'error' } }) + ); + return error; + } + }; +} + +export function getExpenditures(expenditureSearchAttrs, applyFilter = false) { + return async (dispatch, getState, { api, schema }) => { + dispatch(actionCreators.getExpenditures.request()); + try { + const filter = applyFilter ? getFilterOptionsForRequest(getState()) : {}; + const response = await api.getExpenditures({ + ...expenditureSearchAttrs, + ...filter, + }); + if (expenditureSearchAttrs.format === 'csv' && response.status === 200) { + const expenditures = await response.text(); + downloadFile(expenditures, `expenditures-download-${Date.now()}.csv`); + } else if ( + expenditureSearchAttrs.format === 'xml' && + response.status === 200 + ) { + const expenditures = await response.json(); + expenditures.map((expenditure, index) => { + return downloadFile( + expenditure, + `expenditures-download-${index + 1}-${Date.now()}.xml` + ); + }); + } else if (response.status === 200) { + const expenses = await response.json(); + const data = normalize(expenses.data, [schema.expenditure]); + dispatch(addExpenditureEntities(data)); + dispatch(actionCreators.getExpenditures.success(expenses.total)); + } else { + dispatch(actionCreators.getExpenditures.failure()); + } + } catch (error) { + dispatch(actionCreators.getExpenditures.failure(error)); + } + }; +} + +export function getExpenditureById(id) { + return async (dispatch, getState, { api, schema }) => { + dispatch(actionCreators.getExpenditureById.request()); + try { + const response = await api.getExpenditureById(id); + if (response.status === 200) { + const data = normalize(await response.json(), schema.expenditure); + dispatch(addExpenditureEntities(data)); + dispatch(actionCreators.getExpenditureById.success(id)); + } else { + dispatch(actionCreators.getExpenditureById.failure()); + } + } catch (error) { + dispatch(actionCreators.getExpenditureById.failure(error)); + } + }; +} + +export function postExpenditureComment(id, comment, attachment) { + return async (dispatch, getState, { api, schema }) => { + dispatch(actionCreators.postExpenditureComment.request()); + try { + const response = await api.postExpenditureComment( + id, + comment, + attachment + ); + if (response.status === 204) { + dispatch(actionCreators.postExpenditureComment.success()); + dispatch(getActivitiesByIdType({ expenditureId: id })); + } else { + dispatch(actionCreators.postExpenditureComment.failure()); + } + } catch (error) { + dispatch(actionCreators.postExpenditureComment.failure(error)); + } + }; +} + +// Selectors +export const rootState = state => state || {}; + +export const getExpendituresList = createSelector(rootState, state => { + if ( + isEmpty(state.expenditures.list) || + isEmpty(state.expenditures.listOrder) + ) { + return []; + } + return state.expenditures.listOrder.map(id => state.expenditures.list[id]); +}); + +export const getExpendituresTotal = createSelector(rootState, state => { + return state.expenditures.total; +}); + +export const getCurrentExpenditureId = state => { + return state.expenditures && + state.expenditures.list && + state.expenditures.currentId + ? state.expenditures.currentId + : false; +}; + +export const getCurrentExpenditure = state => { + return getCurrentExpenditureId(state) + ? state.expenditures.list[getCurrentExpenditureId(state)] + : false; +}; + +export const getExpenditureCampaignName = state => { + const expenditure = getCurrentExpenditure(state); + return expenditure ? expenditure.campaign.name : null; +}; + +export const getFilterOptions = state => { + const filter = state.expenditures.listFilterOptions; + const sort = state.expenditures.listFilterOptions.sort || {}; + return { ...filter, sort }; +}; diff --git a/app2/src/state/ducks/expenditures.test.js b/app2/src/state/ducks/expenditures.test.js new file mode 100644 index 000000000..0e14b8fbd --- /dev/null +++ b/app2/src/state/ducks/expenditures.test.js @@ -0,0 +1,275 @@ +import configureMockStore from 'redux-mock-store'; +import thunk from 'redux-thunk'; +import * as expenditures from './expenditures'; +import * as api from '../../api'; +import * as schema from '../../api/schema'; +import { ADD_EXPENDITURE_ENTITIES } from './common'; + +const { actionTypes, actionCreators } = expenditures; + +const middlewares = [thunk.withExtraArgument({ api, schema })]; +const mockStore = configureMockStore(middlewares); + +describe('Reducer', () => { + const reducer = expenditures.default; + it('initial state', () => { + expect(reducer(undefined, {})).toEqual({ + isLoading: false, + error: null, + list: null, + currentId: null, + listOrder: [], + total: 0, + listFilterOptions: { + from: '', + to: '', + status: 'all', + page: 0, + perPage: 50, + sort: {}, + }, + }); + }); + + it('adds expenditure entities', () => { + expect( + reducer(undefined, { + type: ADD_EXPENDITURE_ENTITIES, + payload: { + entities: { + expenditures: { + '1': {}, + }, + }, + }, + }) + ).toEqual({ + list: { + '1': {}, + }, + currentId: null, + isLoading: false, + error: null, + total: 0, + listFilterOptions: { + from: '', + to: '', + status: 'all', + page: 0, + perPage: 50, + sort: {}, + }, + }); + }); +}); + +describe('Action Creators', () => { + it('create expenditure request', () => { + const expectedAction = { + type: actionTypes.CREATE_EXPENDITURE.REQUEST, + }; + expect(actionCreators.createExpenditure.request()).toEqual(expectedAction); + }); + it('create expenditure success', () => { + const expectedAction = { + type: actionTypes.CREATE_EXPENDITURE.SUCCESS, + }; + expect(actionCreators.createExpenditure.success()).toEqual(expectedAction); + }); + it('create expenditure failure', () => { + const expectedAction = { + type: actionTypes.CREATE_EXPENDITURE.FAILURE, + }; + expect(actionCreators.createExpenditure.failure()).toEqual(expectedAction); + }); +}); + +let govAdminToken; +let campaignAdminToken; +let campaignStaffToken; +let governmentId; +let campaignId; +let campaignStaffId; +let campaignAdminId; +describe('Side Effects', () => { + beforeAll(async () => { + let tokenResponse = await api.login( + 'govadmin@openelectionsportland.org', + 'password' + ); + govAdminToken = tokenResponse.headers + .get('set-cookie') + .match(/=([a-zA-Z0-9].+); Path/)[1]; + let decodedToken = api.decodeToken(govAdminToken); + governmentId = decodedToken.permissions[0].governmentId; + + tokenResponse = await api.login( + 'campaignadmin@openelectionsportland.org', + 'password' + ); + campaignAdminToken = tokenResponse.headers + .get('set-cookie') + .match(/=([a-zA-Z0-9].+); Path/)[1]; + decodedToken = api.decodeToken(campaignAdminToken); + campaignId = decodedToken.permissions[0].campaignId; + + campaignAdminId = decodedToken.id; + + tokenResponse = await api.login( + 'campaignstaff@openelectionsportland.org', + 'password' + ); + campaignStaffToken = tokenResponse.headers + .get('set-cookie') + .match(/=([a-zA-Z0-9].+); Path/)[1]; + decodedToken = api.decodeToken(campaignStaffToken); + campaignStaffId = decodedToken.id; + }); + + beforeEach(() => { + delete process.env.TOKEN; + }); + + it('creates expenditure testme', async () => { + const expectedActions = [ + { type: actionTypes.CREATE_EXPENDITURE.REQUEST }, + { type: ADD_EXPENDITURE_ENTITIES }, + { type: actionTypes.CREATE_EXPENDITURE.SUCCESS }, + ]; + const store = mockStore({}); + + process.env.TOKEN = campaignStaffToken; + return store + .dispatch( + expenditures.createExpenditure({ + address1: '123 ABC ST', + amount: 250, + campaignId, + city: 'Portland', + currentUserId: campaignStaffId, + date: 1565060230243, + governmentId, + type: api.ExpenditureTypeEnum.EXPENDITURE, + subType: api.ExpenditureSubTypeEnum.CASH_EXPENDITURE, + state: 'OR', + status: api.ExpenditureStatusEnum.DRAFT, + zip: '97214', + payeeType: api.PayeeTypeEnum.INDIVIDUAL, + name: 'Test Expenditure', + description: 'This is a test', + }) + ) + .then(() => { + const actions = store.getActions(); + expect(actions[0].type).toEqual(expectedActions[0].type); + expect(actions[1].type).toEqual(expectedActions[1].type); + expect(actions[2].type).toEqual(expectedActions[2].type); + }); + }); + + it('gets expenditures', async () => { + const expectedActions = [ + { type: actionTypes.GET_EXPENDITURES.REQUEST }, + { type: ADD_EXPENDITURE_ENTITIES }, + { type: actionTypes.GET_EXPENDITURES.SUCCESS }, + ]; + const store = mockStore({}); + + process.env.TOKEN = campaignAdminToken; + + return store + .dispatch( + expenditures.getExpenditures({ + governmentId, + campaignId, + currentUserId: campaignAdminId, + }) + ) + .then(() => { + const actions = store.getActions(); + expect(actions[0].type).toEqual(expectedActions[0].type); + expect(actions[1].type).toEqual(expectedActions[1].type); + expect(actions[2].type).toEqual(expectedActions[2].type); + }); + }); + + it('updates expenditure', async () => { + const expectedActions = [ + { type: actionTypes.UPDATE_EXPENDITURE.REQUEST }, + { type: actionTypes.UPDATE_EXPENDITURE.SUCCESS }, + ]; + const store = mockStore({}); + + process.env.TOKEN = campaignAdminToken; + + const expenditure = await api.createExpenditure({ + address1: '123 ABC ST', + amount: 250, + campaignId, + city: 'Portland', + currentUserId: campaignStaffId, + date: 1564881802534, + governmentId, + type: api.ExpenditureTypeEnum.EXPENDITURE, + subType: api.ExpenditureSubTypeEnum.CASH_EXPENDITURE, + state: 'OR', + status: api.ExpenditureStatusEnum.DRAFT, + zip: '97214', + payeeType: api.PayeeTypeEnum.INDIVIDUAL, + name: 'Test Expenditure', + description: 'This is a test', + }); + const { id } = await expenditure.json(); + + return store + .dispatch( + expenditures.updateExpenditure({ + id, + amount: 500, + currentUserId: campaignAdminId, + }) + ) + .then(() => { + const actions = store.getActions(); + expect(actions[0].type).toEqual(expectedActions[0].type); + expect(actions[1].type).toEqual(expectedActions[1].type); + }); + }); + + it('gets expenditure', async () => { + const expectedActions = [ + { type: actionTypes.GET_EXPENDITURE_BY_ID.REQUEST }, + { type: ADD_EXPENDITURE_ENTITIES }, + { type: actionTypes.GET_EXPENDITURE_BY_ID.SUCCESS }, + ]; + const store = mockStore({}); + + process.env.TOKEN = campaignAdminToken; + + const expenditure = await api.createExpenditure({ + address1: '123 ABC ST', + amount: 250, + campaignId, + city: 'Portland', + currentUserId: campaignStaffId, + date: 1564881802534, + governmentId, + type: api.ExpenditureTypeEnum.EXPENDITURE, + subType: api.ExpenditureSubTypeEnum.CASH_EXPENDITURE, + state: 'OR', + status: api.ExpenditureStatusEnum.DRAFT, + zip: '97214', + payeeType: api.PayeeTypeEnum.INDIVIDUAL, + name: 'Test Expenditure', + description: 'This is a test', + }); + const { id } = await expenditure.json(); + + return store.dispatch(expenditures.getExpenditureById(id)).then(() => { + const actions = store.getActions(); + expect(actions[0].type).toEqual(expectedActions[0].type); + expect(actions[1].type).toEqual(expectedActions[1].type); + expect(actions[2].type).toEqual(expectedActions[2].type); + }); + }); +}); diff --git a/app2/src/state/ducks/externalData.js b/app2/src/state/ducks/externalData.js new file mode 100644 index 000000000..fdc22675c --- /dev/null +++ b/app2/src/state/ducks/externalData.js @@ -0,0 +1,64 @@ +import createActionTypes from '../utils/createActionTypes'; +import createReducer from '../utils/createReducer'; +import action from '../utils/action'; +import { RESET_STATE } from './common'; + +export const STATE_KEY = 'externalData'; +// Action Types +export const actionTypes = { + GET_EXTERNAL_DATA: createActionTypes(STATE_KEY, 'GET_EXTERNAL_DATA'), +}; + +// Initial State +export const initialState = { + data: { + type: 'FeatureCollection', + features: [], + }, + isLoading: false, + error: null, +}; + +// Reducer +export default createReducer(initialState, { + [RESET_STATE]: () => { + return { ...initialState }; + }, + [actionTypes.GET_EXTERNAL_DATA.REQUEST]: state => { + return { ...state, isLoading: true }; + }, + [actionTypes.GET_EXTERNAL_DATA.SUCCESS]: (state, action) => { + return { + ...state, + isLoading: false, + data: action.payload, + timeLoaded: new Date(), + }; + }, + [actionTypes.GET_EXTERNAL_DATA.FAILURE]: (state, action) => { + return { ...state, isLoading: false, error: action.error }; + }, +}); + +// Action Creators +export const actionCreators = { + getExternalData: { + request: () => action(actionTypes.GET_EXTERNAL_DATA.REQUEST), + success: payload => + action(actionTypes.GET_EXTERNAL_DATA.SUCCESS, { payload }), + failure: error => action(actionTypes.GET_EXTERNAL_DATA.FAILURE, { error }), + }, +}; + +// Side Effects, e.g. thunks +export function getExternalData() { + return async (dispatch, _getState, { api }) => { + dispatch(actionCreators.getExternalData.request()); + try { + const response = await api.getExternalContributionGeoData(); + dispatch(actionCreators.getExternalData.success(response)); + } catch (error) { + dispatch(actionCreators.getExternalData.failure(error)); + } + }; +} diff --git a/app2/src/state/ducks/governments.js b/app2/src/state/ducks/governments.js new file mode 100644 index 000000000..f181d2af6 --- /dev/null +++ b/app2/src/state/ducks/governments.js @@ -0,0 +1,58 @@ +// governments.js +import createReducer from '../utils/createReducer'; +import { ADD_ENTITIES, resetState, RESET_STATE } from './common'; +import createActionTypes from '../utils/createActionTypes'; +import action from '../utils/action'; + +export const STATE_KEY = 'governments'; + +export const actionTypes = { + SET_GOVERNMENT: createActionTypes(STATE_KEY, 'SET_GOVERNMENT'), +}; + +// Action Types + +// Initial State +export const initialState = { + isLoading: false, + error: null, + currentGovernmentId: null, +}; + +export const resetGovernmentState = resetState; +// Reducer +export default createReducer(initialState, { + [RESET_STATE]: () => { + return { ...initialState }; + }, + [ADD_ENTITIES]: (state, action) => { + return { ...state, ...action.payload.governments }; + }, + [actionTypes.SET_GOVERNMENT.SUCCESS]: (state, action) => { + return { ...state, currentGovernmentId: action.governmentId }; + }, +}); + +// Action Creators + +export const actionCreators = { + setGovernment: { + success: governmentId => + action(actionTypes.SET_GOVERNMENT.SUCCESS, { governmentId }), + }, +}; + +// Side Effects, e.g. thunks + +// Selectors +export const rootState = state => state || {}; + +// TODO: Remove default gov id to 1 +export const getCurrentGovernmentId = state => { + if (state.governments && state.governments.currentGovernmentId) { + return state.governments.currentGovernmentId !== null + ? state.governments.currentGovernmentId + : 1; + } + return 1; +}; diff --git a/app2/src/state/ducks/governments.test.js b/app2/src/state/ducks/governments.test.js new file mode 100644 index 000000000..e5a442926 --- /dev/null +++ b/app2/src/state/ducks/governments.test.js @@ -0,0 +1,37 @@ +import * as governments from './governments'; + +const { actionTypes, actionCreators } = governments; + +describe('Reducer', () => { + const reducer = governments.default; + + it('sets current government', () => { + expect( + reducer( + { + currentGovernmentId: null, + isLoading: false, + error: null, + }, + { + type: actionTypes.SET_GOVERNMENT.SUCCESS, + governmentId: 1, + } + ) + ).toEqual({ + currentGovernmentId: 1, + isLoading: false, + error: null, + }); + }); +}); + +describe('Action Creators', () => { + it('set government success', () => { + const expectedAction = { + type: actionTypes.SET_GOVERNMENT.SUCCESS, + governmentId: 1, + }; + expect(actionCreators.setGovernment.success(1)).toEqual(expectedAction); + }); +}); diff --git a/app2/src/state/ducks/matches.js b/app2/src/state/ducks/matches.js new file mode 100644 index 000000000..30a135e8d --- /dev/null +++ b/app2/src/state/ducks/matches.js @@ -0,0 +1,191 @@ +/* eslint-disable no-unused-vars */ +import { cloneDeep } from 'lodash'; +import { flashMessage } from 'redux-flash'; +import createReducer from '../utils/createReducer'; +import { RESET_STATE } from './common'; +import createActionTypes from '../utils/createActionTypes'; +import action from '../utils/action'; +import { getContributionById, getCurrentContribution } from './contributions'; + +export const STATE_KEY = 'matches'; + +// Action Types +export const actionTypes = { + GET_MATCHES_BY_CONTRIBUTION_ID: createActionTypes( + STATE_KEY, + 'GET_MATCHES_BY_CONTRIBUTION_ID' + ), + UPDATE_MATCH_ID: createActionTypes(STATE_KEY, 'UPDATE_MATCH_ID'), +}; + +// Initial State +export const initialState = { + isLoading: false, + error: null, + list: {}, +}; + +// Reducer +export default createReducer(initialState, { + [RESET_STATE]: () => { + return { ...initialState }; + }, + [actionTypes.GET_MATCHES_BY_CONTRIBUTION_ID.REQUEST]: (state, action) => { + return { ...state, isLoading: true }; + }, + [actionTypes.GET_MATCHES_BY_CONTRIBUTION_ID.SUCCESS]: (state, action) => { + const newState = cloneDeep(state); + const match = action.match; + newState.list[match.id] = match; + return { ...state, isLoading: false, list: newState.list }; + }, + [actionTypes.GET_MATCHES_BY_CONTRIBUTION_ID.FAILURE]: (state, action) => { + return { ...state, isLoading: false, error: action.error }; + }, + [actionTypes.UPDATE_MATCH_ID.REQUEST]: (state, action) => { + return { ...state, isLoading: true }; + }, + [actionTypes.UPDATE_MATCH_ID.SUCCESS]: (state, action) => { + return { ...state, isLoading: false }; + }, + [actionTypes.UPDATE_MATCH_ID.FAILURE]: (state, action) => { + return { ...state, isLoading: false, error: action.error }; + }, +}); + +// Action Creators + +export const actionCreators = { + getMatchesByContributionId: { + request: () => action(actionTypes.GET_MATCHES_BY_CONTRIBUTION_ID.REQUEST), + success: match => + action(actionTypes.GET_MATCHES_BY_CONTRIBUTION_ID.SUCCESS, { match }), + failure: error => + action(actionTypes.GET_MATCHES_BY_CONTRIBUTION_ID.FAILURE, { error }), + }, + updateMatchForContribution: { + request: () => action(actionTypes.UPDATE_MATCH_ID.REQUEST), + success: match => action(actionTypes.UPDATE_MATCH_ID.SUCCESS, { match }), + failure: error => action(actionTypes.UPDATE_MATCH_ID.FAILURE, { error }), + }, +}; + +// Side Effects, e.g. thunks +export function getMatchesByContributionId(contributionId) { + return async (dispatch, getState, { api, schema }) => { + dispatch(actionCreators.getMatchesByContributionId.request()); + try { + const response = await api.getMatchesByContributionId(contributionId); + if (response.status === 200) { + const match = await response.json(); + match.id = contributionId; + dispatch(actionCreators.getMatchesByContributionId.success(match)); + } else { + dispatch(actionCreators.getMatchesByContributionId.failure()); + } + } catch (error) { + dispatch(actionCreators.getMatchesByContributionId.failure(error)); + } + }; +} +/* +@attrs { +contributionId: number, +matchId: string, +matchStrength: enum[exact, strong, weak, none] + } + */ +export function updateMatchForContribution(attrs) { + return async (dispatch, getState, { api, schema }) => { + dispatch(actionCreators.updateMatchForContribution.request()); + try { + const response = await api.updateMatchForContribution(attrs); + if (response.status === 204 || response.status === 200) { + dispatch(getMatchesByContributionId(attrs.contributionId)); + dispatch(getContributionById(attrs.contributionId)); + dispatch( + flashMessage(`Match Updated`, { + props: { variant: 'success' }, + }) + ); + } else { + dispatch(actionCreators.updateMatchForContribution.failure()); + dispatch( + flashMessage(`Error - ${response.status} status returned`, { + props: { variant: 'error' }, + }) + ); + } + } catch (error) { + dispatch(actionCreators.updateMatchForContribution.failure(error)); + flashMessage(`Error - ${error}`, { props: { variant: 'error' } }); + } + }; +} + +export const matchStrengthEnum = ['exact', 'strong', 'weak', 'none']; +export const getCurrentContributionMatch = state => { + return state.matches && state.matches.list && state.contributions.currentId + ? state.matches.list[state.contributions.currentId] + : false; +}; + +export const getCurrentMatchResults = state => { + const currentMatches = getCurrentContributionMatch(state); + const matches = []; + const results = currentMatches.results; + const currentContribution = getCurrentContribution(state); + let match = {}; + let selectedMatchId = ''; + if (results) { + selectedMatchId = currentContribution ? currentContribution.matchId : ''; + const matchId = currentMatches.matchId; + // Create a easy to traverse structure + for (const matchStrength of matchStrengthEnum) { + if ( + results[matchStrength] && + Array.isArray(results[matchStrength]) && + results[matchStrength].length > 0 + ) { + // Pass back camelcase to be pretty happy + for (const result of results[matchStrength]) { + match = { + id: result.id, + bestMatch: !!(matchId === result.id), + matchStrength, + selected: !!(selectedMatchId === result.id), + firstName: result.first_name, + lastName: result.last_name, + address1: result.address_1, + address2: result.address_2, + city: result.city, + state: result.state, + zip: result.zip, + }; + // Ensure the selected or best matched result is first + if (match.selected || (match.bestMatch && !selectedMatchId)) { + matches.unshift(match); + } else { + matches.push(match); + } + } + } + } + } + if (currentMatches.matchStrength !== 'exact') { + if (currentContribution.matchStrength === 'none') { + matches.unshift({ + id: results.none, + selected: true, + matchStrength: 'none', + }); + } else { + matches.push({ + id: results.none, + selected: false, + matchStrength: 'none', + }); + } + } + return matches; +}; diff --git a/app2/src/state/ducks/modal.js b/app2/src/state/ducks/modal.js new file mode 100644 index 000000000..e6891aaf1 --- /dev/null +++ b/app2/src/state/ducks/modal.js @@ -0,0 +1,67 @@ +/* eslint-disable no-unused-vars */ +import { createSelector } from 'reselect'; +import createReducer from '../utils/createReducer'; +import createAction from '../utils/createAction'; +import action from '../utils/action'; + +export const STATE_KEY = 'modal'; + +// Action Types +export const actionTypes = { + SHOW_MODAL: createAction(STATE_KEY, 'SHOW_MODAL'), + DISMISS_MODAL: createAction(STATE_KEY, 'DISMISS_MODAL'), +}; + +// Initial State +export const initialState = { + currentModal: null, + isActive: false, + isLoading: false, + state: null, + error: null, +}; + +// Reducer +export default createReducer(initialState, { + [actionTypes.SHOW_MODAL]: (state, action) => { + return { + ...state, + isActive: true, + currentModal: action.payload.component, + _props: action.payload.props, + state: action.payload.state, + }; + }, + [actionTypes.DISMISS_MODAL]: (state, action) => { + return { ...state, isActive: false, currentModal: null, state: null }; + }, +}); + +// Action Creators +export const actionCreators = { + showmodal: payload => { + return action(actionTypes.SHOW_MODAL, { payload }); + }, + dismissmodal: () => action(actionTypes.DISMISS_MODAL), +}; + +export function showModal(payload) { + return (dispatch, getState) => { + dispatch(actionCreators.showmodal(payload)); + }; +} + +export function clearModal() { + return (dispatch, getState) => { + dispatch(actionCreators.dismissmodal()); + }; +} + +// Selectors +export const rootState = state => state || {}; +export const getModalState = createSelector(rootState, state => state.modal); + +export const modalIsActive = createSelector( + rootState, + state => state.modal.isActive +); diff --git a/app2/src/state/ducks/pastContributions.js b/app2/src/state/ducks/pastContributions.js new file mode 100644 index 000000000..27b7ae778 --- /dev/null +++ b/app2/src/state/ducks/pastContributions.js @@ -0,0 +1,82 @@ +/* eslint-disable no-unused-vars */ +import { cloneDeep } from 'lodash'; +import createReducer from '../utils/createReducer'; +import { RESET_STATE } from './common'; +import createActionTypes from '../utils/createActionTypes'; +import action from '../utils/action'; + +export const STATE_KEY = 'pastContributions'; + +// Action Types +export const actionTypes = { + GET_PAST_CONTRIBUTIONS_BY_MATCH_ID: createActionTypes( + STATE_KEY, + 'GET_PAST_CONTRIBUTIONS_BY_MATCH_ID' + ), +}; + +// Initial State +export const initialState = { + isLoading: false, + error: null, + list: {}, +}; + +// Reducer +export default createReducer(initialState, { + [RESET_STATE]: () => { + return { ...initialState }; + }, + [actionTypes.GET_PAST_CONTRIBUTIONS_BY_MATCH_ID.REQUEST]: (state, action) => { + return { ...state, isLoading: true }; + }, + [actionTypes.GET_PAST_CONTRIBUTIONS_BY_MATCH_ID.SUCCESS]: (state, action) => { + const newState = cloneDeep(state); + const pastContributions = action.pastContributions; + newState.list[action.matchId] = pastContributions; + return { ...state, isLoading: false, list: newState.list }; + }, + [actionTypes.GET_PAST_CONTRIBUTIONS_BY_MATCH_ID.FAILURE]: (state, action) => { + return { ...state, isLoading: false, error: action.error }; + }, +}); + +// Action Creators + +export const actionCreators = { + getContributionsByMatchId: { + request: () => + action(actionTypes.GET_PAST_CONTRIBUTIONS_BY_MATCH_ID.REQUEST), + success: (matchId, pastContributions) => + action(actionTypes.GET_PAST_CONTRIBUTIONS_BY_MATCH_ID.SUCCESS, { + matchId, + pastContributions, + }), + failure: error => + action(actionTypes.GET_PAST_CONTRIBUTIONS_BY_MATCH_ID.FAILURE, { error }), + }, +}; + +// Side Effects, e.g. thunks +export function getContributionsByMatchId(matchId) { + return async (dispatch, getState, { api, schema }) => { + dispatch(actionCreators.getContributionsByMatchId.request()); + try { + const response = await api.getContributions({ matchId, governmentId: 1 }); + + if (response.status === 200) { + const contributions = await response.json(); + dispatch( + actionCreators.getContributionsByMatchId.success( + matchId, + contributions.data + ) + ); + } else { + dispatch(actionCreators.getContributionsByMatchId.failure()); + } + } catch (error) { + dispatch(actionCreators.getContributionsByMatchId.failure(error)); + } + }; +} diff --git a/app2/src/state/ducks/permissions.js b/app2/src/state/ducks/permissions.js new file mode 100644 index 000000000..c889f4da9 --- /dev/null +++ b/app2/src/state/ducks/permissions.js @@ -0,0 +1,49 @@ +/* eslint-disable no-unused-vars */ +import createReducer from '../utils/createReducer'; +import { ADD_ENTITIES, resetState, RESET_STATE } from './common'; +import createActionTypes from '../utils/createActionTypes'; +import action from '../utils/action'; + +export const STATE_KEY = 'permissions'; + +// Action Types +export const actionTypes = { + REMOVE_PERMISSION: createActionTypes(STATE_KEY, 'REMOVE_PERMISSION'), +}; + +// Initial State +export const initialState = { + isLoading: false, + error: null, +}; + +export const resetPermissionState = resetState; +// Reducer +export default createReducer(initialState, { + [RESET_STATE]: () => { + return { ...initialState }; + }, + [ADD_ENTITIES]: (state, action) => { + return { ...state, ...action.payload.permissions }; + }, + [actionTypes.REMOVE_PERMISSION.SUCCESS]: (state, action) => { + const newState = { ...state, isLoading: false }; + delete newState[action.permissionId]; + return newState; + }, +}); + +// Action Creators + +export const actionCreators = { + removePermission: { + success: permissionId => + action(actionTypes.REMOVE_PERMISSION.SUCCESS, { permissionId }), + }, +}; + +// Side Effects, e.g. thunks + +export function removePermission(permissionId) { + return actionCreators.removePermission.success(permissionId); +} diff --git a/app2/src/state/ducks/permissions.test.js b/app2/src/state/ducks/permissions.test.js new file mode 100644 index 000000000..124981b7e --- /dev/null +++ b/app2/src/state/ducks/permissions.test.js @@ -0,0 +1,84 @@ +/* eslint-disable no-unused-vars */ +import configureMockStore from 'redux-mock-store'; +import thunk from 'redux-thunk'; +import * as permissions from './permissions'; +import * as api from '../../api'; +import * as schema from '../../api/schema'; +import { ADD_ENTITIES } from './common'; + +const { actionTypes, actionCreators } = permissions; + +const middlewares = [thunk.withExtraArgument({ api, schema })]; +const mockStore = configureMockStore(middlewares); + +describe('Reducer', () => { + const reducer = permissions.default; + it('initial state', () => { + expect(reducer(undefined, {})).toEqual({ + isLoading: false, + error: null, + }); + }); + + it('adds permissions entities', () => { + expect( + reducer(undefined, { + type: ADD_ENTITIES, + payload: { + permissions: { + '1': { + userId: 1, + campaignId: 1, + governmentId: 1, + role: 'CAMPAIGN_STAFF', + }, + }, + }, + }) + ).toEqual({ + '1': { + userId: 1, + campaignId: 1, + governmentId: 1, + role: 'CAMPAIGN_STAFF', + }, + isLoading: false, + error: null, + }); + }); + + it('removes permission entity', () => { + expect( + reducer( + { + '1': { + userId: 1, + campaignId: 1, + governmentId: 1, + role: 'CAMPAIGN_STAFF', + }, + isLoading: false, + error: null, + }, + { + type: actionTypes.REMOVE_PERMISSION.SUCCESS, + permissionId: 1, + error: null, + } + ) + ).toEqual({ + isLoading: false, + error: null, + }); + }); +}); + +describe('Action Creators', () => { + it('remove permissions success', () => { + const expectedAction = { + permissionId: 1, + type: actionTypes.REMOVE_PERMISSION.SUCCESS, + }; + expect(actionCreators.removePermission.success(1)).toEqual(expectedAction); + }); +}); diff --git a/app2/src/state/ducks/publicData.js b/app2/src/state/ducks/publicData.js new file mode 100644 index 000000000..3218f5bbd --- /dev/null +++ b/app2/src/state/ducks/publicData.js @@ -0,0 +1,1017 @@ +/* eslint-disable no-unused-vars */ +import { createSelector } from 'reselect'; +import { isAfter, isBefore, isEqual } from 'date-fns'; +import { civicFormat } from '@hackoregon/component-library/dist/utils'; +import { fromPairs } from 'lodash'; +import createReducer from '../utils/createReducer'; +import createActionTypes, { + createCustomActionTypes, +} from '../utils/createActionTypes'; +import action from '../utils/action'; +import { RESET_STATE, resetState } from './common'; +import campaigns from './campaigns'; + +const { titleCase } = civicFormat; +export const STATE_KEY = 'publicData'; + +const isInclusiveAfter = (date, compare) => + isEqual(date, compare) || isAfter(date, compare); + +const isInclusiveBefore = (date, compare) => + isEqual(date, compare) || isBefore(date, compare); + +const numericSort = (a, b) => a - b; + +const median = arr => { + if (!arr || !arr.length) return null; + + arr.sort(numericSort); + + if (arr.length % 2 === 0) { + const a = arr[arr.length / 2 - 1]; + const b = arr[arr.length / 2]; + return (a + b) / 2; + } + + return arr[Math.floor(arr.length / 2)]; +}; + +const groupBy = (field, list) => { + const groups = {}; + list.forEach(d => { + // Skip datapoints that do not have the field in question + if (!d[field]) return; + + if (!groups[d[field]]) { + groups[d[field]] = [d]; + } else { + groups[d[field]].push(d); + } + }); + + return groups; +}; + +const makeArray = input => { + if (input instanceof Array) return input; + if (input == null) return []; + return [input]; +}; + +// Action Types +export const actionTypes = { + GET_PUBLIC_DATA: createActionTypes(STATE_KEY, 'GET_PUBLIC_DATA'), + GET_EXTERNAL_PUBLIC_DATA: createActionTypes( + STATE_KEY, + 'GET_EXTERNAL_PUBLIC_DATA' + ), + SET_FILTER: createCustomActionTypes(STATE_KEY, 'SET_FILTER', [ + 'OFFICES', + 'FINANCING', + 'CAMPAIGNS', + 'START_DATE', + 'END_DATE', + 'COUNT', + 'COMPARE', + 'RESET_ALL', + 'CUSTOM', + ]), +}; + +// Initial State +export const initialState = { + data: { + type: 'FeatureCollection', + features: [], + }, + externalData: { + type: 'FeatureCollection', + features: [], + }, + filters: { + financing: 'public', + campaigns: [], + offices: [], + startDate: null, + endDate: null, + count: false, + compare: false, + }, + isLoading: false, + isExternalLoading: false, + error: null, + externalError: null, +}; + +// Reducer +export default createReducer(initialState, { + [RESET_STATE]: () => { + return { ...initialState }; + }, + [actionTypes.GET_PUBLIC_DATA.REQUEST]: state => { + return { ...state, isLoading: true }; + }, + [actionTypes.GET_PUBLIC_DATA.SUCCESS]: (state, action) => { + return { + ...state, + isLoading: false, + data: action.payload, + timeLoaded: new Date(), + }; + }, + [actionTypes.GET_PUBLIC_DATA.FAILURE]: (state, action) => { + return { ...state, isLoading: false, error: action.error }; + }, + [actionTypes.GET_EXTERNAL_PUBLIC_DATA.REQUEST]: state => { + return { ...state, isExternalLoading: true }; + }, + [actionTypes.GET_EXTERNAL_PUBLIC_DATA.SUCCESS]: (state, action) => { + return { + ...state, + isExternalLoading: false, + externalData: action.payload, + }; + }, + [actionTypes.GET_EXTERNAL_PUBLIC_DATA.FAILURE]: (state, action) => { + return { ...state, isExternalLoading: false, externalError: action.error }; + }, + [actionTypes.SET_FILTER.OFFICES]: (state, action) => { + return { + ...state, + filters: { ...state.filters, offices: makeArray(action.offices) }, + }; + }, + [actionTypes.SET_FILTER.FINANCING]: (state, action) => { + return { + ...state, + filters: { + ...state.filters, + financing: action.financing, + compare: false, + }, + }; + }, + [actionTypes.SET_FILTER.CAMPAIGNS]: (state, action) => { + return { + ...state, + filters: { + ...state.filters, + campaigns: makeArray(action.campaigns), + compare: makeArray(action.campaigns).length > 1, + }, + }; + }, + [actionTypes.SET_FILTER.START_DATE]: (state, action) => { + return { + ...state, + filters: { ...state.filters, startDate: action.startDate }, + }; + }, + [actionTypes.SET_FILTER.END_DATE]: (state, action) => { + return { ...state, filters: { ...state.filters, endDate: action.endDate } }; + }, + [actionTypes.SET_FILTER.COUNT]: (state, action) => { + return { ...state, filters: { ...state.filters, count: action.count } }; + }, + [actionTypes.SET_FILTER.COMPARE]: (state, action) => { + return { ...state, filters: { ...state.filters, compare: action.compare } }; + }, + [actionTypes.SET_FILTER.RESET_ALL]: state => { + return { + ...state, + filters: { + financing: 'public', + campaigns: [], + offices: [], + startDate: null, + endDate: null, + count: false, + compare: false, + }, + }; + }, + [actionTypes.SET_FILTER.CUSTOM]: (state, action) => { + return { + ...state, + filters: { + financing: 'public', + campaigns: [], + offices: [], + startDate: null, + endDate: null, + count: false, + compare: false, + ...action.filters, + }, + }; + }, +}); + +// Action Creators +export const actionCreators = { + getPublicData: { + request: () => action(actionTypes.GET_PUBLIC_DATA.REQUEST), + success: payload => + action(actionTypes.GET_PUBLIC_DATA.SUCCESS, { payload }), + failure: error => action(actionTypes.GET_PUBLIC_DATA.FAILURE, { error }), + }, + getExternalPublicData: { + request: () => action(actionTypes.GET_EXTERNAL_PUBLIC_DATA.REQUEST), + success: payload => + action(actionTypes.GET_EXTERNAL_PUBLIC_DATA.SUCCESS, { payload }), + failure: error => + action(actionTypes.GET_EXTERNAL_PUBLIC_DATA.FAILURE, { error }), + }, + setFilter: { + offices: offices => action(actionTypes.SET_FILTER.OFFICES, { offices }), + financing: financing => + action(actionTypes.SET_FILTER.FINANCING, { financing }), + campaigns: campaigns => + action(actionTypes.SET_FILTER.CAMPAIGNS, { campaigns }), + startDate: startDate => + action(actionTypes.SET_FILTER.START_DATE, { startDate }), + endDate: endDate => action(actionTypes.SET_FILTER.END_DATE, { endDate }), + count: count => action(actionTypes.SET_FILTER.COUNT, { count }), + compare: compare => action(actionTypes.SET_FILTER.COMPARE, { compare }), + resetAll: () => action(actionTypes.SET_FILTER.RESET_ALL), + custom: filters => action(actionTypes.SET_FILTER.CUSTOM, { filters }), + }, +}; + +export const setSelectedOffices = actionCreators.setFilter.offices; +export const setSelectedFinancing = actionCreators.setFilter.financing; +export const setSelectedCampaigns = actionCreators.setFilter.campaigns; +export const setSelectedStartDate = actionCreators.setFilter.startDate; +export const setSelectedEndDate = actionCreators.setFilter.endDate; +export const setSelectedCount = actionCreators.setFilter.count; +export const setSelectedCompare = actionCreators.setFilter.compare; +export const resetAll = actionCreators.setFilter.resetAll; +export const setCustomFilters = actionCreators.setFilter.custom; + +// Side Effects, e.g. thunks +export function getPublicData() { + return async (dispatch, getState, { api, schema }) => { + dispatch(actionCreators.getPublicData.request()); + try { + const response = await api.getContributionGeoData(); + dispatch(actionCreators.getPublicData.success(response)); + } catch (error) { + dispatch(actionCreators.getPublicData.failure(error)); + } + }; +} + +export function getExternalPublicData() { + return async (dispatch, getState, { api, schema }) => { + dispatch(actionCreators.getExternalPublicData.request()); + try { + const response = await api.getExternalContributionGeoData(); + dispatch(actionCreators.getExternalPublicData.success(response)); + } catch (error) { + dispatch(actionCreators.getExternalPublicData.failure(error)); + } + }; +} + +export const rootState = state => state || {}; +export const allPublicData = createSelector( + rootState, + state => state[STATE_KEY] || {} +); + +export const publicDataRequest = createSelector(allPublicData, state => { + const { data, isLoading, error, timeLoaded } = state; + return { data, isLoading, error, timeLoaded }; +}); + +export const externalPublicDataRequest = createSelector( + allPublicData, + state => { + const { externalData, isExternalLoading, externalError } = state; + return { externalData, isExternalLoading, externalError }; + } +); + +export const publicDataRequestIsLoading = createSelector( + allPublicData, + state => { + const { isLoading, isExternalLoading } = state; + return !(!isLoading && !isExternalLoading); + } +); + +export const publicDataFilters = createSelector( + allPublicData, + state => state.filters +); + +export const mostRecentExternalContributionDate = createSelector( + externalPublicDataRequest, + extReq => { + const externalData = extReq.externalData; + // Return undefined if no external contributions + if (!externalData.features) return undefined; + if (externalData.features.length < 1) return undefined; + + // Convert date strings to Date objects + externalData.features.forEach(f => { + if (f.properties.date) { + f.properties.date = new Date(f.properties.date); + // force date to be PDT timezone + f.properties.date.setUTCHours(7); + } + }); + + // Create a shallow copy of the combined Geojson and sort latest date + const dataCopy = { ...externalData }; + dataCopy.features = externalData.features.slice(); + + const donations = dataCopy.features.map(f => f.properties); + donations.sort((a, b) => b.date - a.date); + const mostRecentDonationDate = donations[0].date; + + return mostRecentDonationDate; + } +); + +export const publicDataGeojson = createSelector( + publicDataRequest, + externalPublicDataRequest, + (req, extReq) => { + const data = req.data; + if (!data.features) return data; + const externalData = extReq.externalData; + if (!externalData.features) return externalData; + + // Convert date strings to Date objects + data.features.forEach(f => { + if (f.properties.date) { + f.properties.date = new Date(f.properties.date); + } + }); + + // Convert date strings to Date objects and set match to 0 + externalData.features.forEach(f => { + if (f.properties.date) { + f.properties.date = new Date(f.properties.date); + } + f.properties.oaeType = 'not participating'; + f.properties.matchAmount = null; + }); + + // Create a shallow copy of the combined Geojson + const dataCopy = { ...data }; + dataCopy.features = data.features + .slice() + .concat(externalData.features.slice()); + + return dataCopy; + } +); + +// Filter Options (based off of the complete public dataset) + +export const allOffices = createSelector(publicDataGeojson, json => { + if (!json || !json.features) return []; + + const offices = new Set(); + json.features.forEach(f => { + offices.add(f.properties.officeSought); + }); + return Array.from(offices); +}); + +export const allCampaigns = createSelector(publicDataGeojson, json => { + if (!json || !json.features) return []; + + const campaignHash = json.features.reduce((campaigns, f) => { + const { campaignName, officeSought } = f.properties; + campaigns[f.properties.campaignId] = { campaignName, officeSought }; + return campaigns; + }, {}); + + return Object.keys(campaignHash).map(id => ({ + id, + name: campaignHash[id].campaignName, + officeSought: campaignHash[id].officeSought, + })); +}); + +// Filter selections + +export const selectedOffices = createSelector( + publicDataFilters, + filters => filters.offices || [] +); + +export const selectedFinancing = createSelector( + publicDataFilters, + filters => filters.financing +); + +export const selectedCampaigns = createSelector( + publicDataFilters, + filters => filters.campaigns || [] +); + +export const selectedCampaignNames = createSelector( + selectedCampaigns, + campaigns => campaigns.map(campaign => campaign.name) +); + +export const selectedStartDate = createSelector(publicDataFilters, filters => + typeof filters.startDate === 'string' + ? new Date(filters.startDate) + : filters.startDate +); + +export const selectedEndDate = createSelector(publicDataFilters, filters => + typeof filters.endDate === 'string' + ? new Date(filters.endDate) + : filters.endDate +); + +export const selectedCount = createSelector( + publicDataFilters, + filters => filters.count +); + +export const selectedCompare = createSelector( + publicDataFilters, + filters => filters.compare +); + +// Filtered filter options + +export const availableCampaigns = createSelector( + allCampaigns, + selectedOffices, + (campaigns, offices) => { + if (!offices || !offices.length) return campaigns; + + return campaigns.filter(campaign => + offices.includes(campaign.officeSought) + ); + } +); + +export const availableCampaignNames = createSelector( + availableCampaigns, + campaigns => campaigns.map(campaign => campaign.name) +); + +// The only non-participating candidate this election cycle is Ted Wheeler +const participatingCandidate = f => f.properties.campaignName !== 'Ted Wheeler'; + +const nonParticipatingCandidate = f => + f.properties.campaignName === 'Ted Wheeler'; +// Filtered public dataset (based on above filters) + +export const filteredPublicData = createSelector( + publicDataGeojson, + selectedOffices, + selectedFinancing, + selectedCampaigns, + selectedStartDate, + selectedEndDate, + (data, offices, financing, campaigns, start, end) => { + const campaignIds = campaigns.map(c => +c.id); + // Create a shallow copy of the underlying Geojson + const dataCopy = { ...data }; + dataCopy.features = dataCopy.features.slice(); + + // Filter data starting with the fastest, broadest filters first + if (campaigns.length) { + dataCopy.features = dataCopy.features.filter(f => + campaignIds.includes(+f.properties.campaignId) + ); + } + + if (offices.length) { + dataCopy.features = dataCopy.features.filter(f => + offices.includes(f.properties.officeSought) + ); + } + + if (financing !== 'all') { + if (financing === 'public') { + dataCopy.features = dataCopy.features.filter(participatingCandidate); + } + if (financing === 'private') { + dataCopy.features = dataCopy.features.filter(nonParticipatingCandidate); + } + } + + if (start && end) { + dataCopy.features = dataCopy.features.filter( + f => + isInclusiveAfter(f.properties.date, start) && + isInclusiveBefore(f.properties.date, end) + ); + } else if (start) { + dataCopy.features = dataCopy.features.filter(f => + isInclusiveAfter(f.properties.date, start) + ); + } else if (end) { + dataCopy.features = dataCopy.features.filter(f => + isInclusiveBefore(f.properties.date, end) + ); + } + + // filter out public_matching_contributions + dataCopy.features = dataCopy.features.filter( + f => f.properties.oaeType !== 'public_matching_contribution' + ); + + return dataCopy; + } +); + +// Aggregated data per chart + +// Done: map takes Geojson of the filtered donations +export const mapData = createSelector(filteredPublicData, data => data); + +const addParticipatingStatus = (data, status) => { + return { ...data, participatingStatus: status }; +}; + +export const filteredPublicDataParticipatingOnly = createSelector( + filteredPublicData, + data => { + // Create a shallow copy of the underlying Geojson + const dataCopy = { ...data }; + dataCopy.features = dataCopy.features.slice(); + // Filter out non-participating candidates + dataCopy.features = dataCopy.features.filter(participatingCandidate); + return dataCopy; + } +); + +export const filteredPublicDataNonParticipatingOnly = createSelector( + filteredPublicData, + data => { + // Create a shallow copy of the underlying Geojson + const dataCopy = { ...data }; + dataCopy.features = dataCopy.features.slice(); + // Filter for non-participating candidates + dataCopy.features = dataCopy.features.filter(nonParticipatingCandidate); + return dataCopy; + } +); + +const sortedDonations = createSelector(filteredPublicData, data => { + const donations = data.features.map(f => f.properties); + donations.sort((a, b) => a.amount - b.amount); + return donations; +}); + +const sortedDonationsNonParticipatingOnly = createSelector( + filteredPublicDataNonParticipatingOnly, + data => { + const donations = data.features.map(f => f.properties); + donations.sort((a, b) => a.amount - b.amount); + return donations; + } +); + +const sortedDonationsParticipatingOnly = createSelector( + filteredPublicDataParticipatingOnly, + data => { + const donations = data.features.map(f => f.properties); + donations.sort((a, b) => a.amount - b.amount); + return donations; + } +); + +export const sortedDonationsByCandidate = createSelector( + filteredPublicData, + selectedCampaignNames, + (data, campaigns) => { + const campaignDonations = {}; + campaigns.map(campaign => { + const donations = data.features + .filter(f => f.properties.campaignName === campaign) + .map(f => f.properties); + donations.sort((a, b) => a.amount - b.amount); + campaignDonations[campaign] = donations; + return {}; + }); + return campaignDonations; + } + // returns an array of donation for each candidate + + // want to return a keyed object based on candidate name + // { ted: donations, sarah: donations } +); + +const summarize = donations => { + const donationsCount = donations.length; + + const nonOAEContributions = []; + const markedDonors = {}; + const markedCampaigns = {}; + let donorsCount = 0; + let totalAmountContributed = 0; + let totalAmountMatched = 0; + let campaignsCount = 0; + + // Only iterate over the array once for better performance + donations.forEach(d => { + // NOTE: contributor name is not a strong idenfitier, could result in miscounting + // NOTE: Count each "Miscellaneous Cash Contributions $100 and under " as one donor + + if ( + !markedDonors[d.contributorName] || + d.contributorName === 'Miscellaneous Cash Contributions $100 and under ' + ) { + donorsCount += 1; + markedDonors[d.contributorName] = true; + } + + if (!markedCampaigns[d.campaignName]) { + campaignsCount += 1; + markedCampaigns[d.campaignName] = true; + } + + // Guard against bad data + if (+d.amount === d.amount && d.amount >= 0) { + totalAmountContributed += d.amount; + if (d.oaeType !== 'public_matching_contribution') { + nonOAEContributions.push(d.amount); + } + } + + if (+d.matchAmount === d.matchAmount && d.matchAmount >= 0) { + totalAmountMatched += d.matchAmount; + } + }); + + return { + campaignsCount, + donationsCount, + donorsCount, + totalAmountContributed, + totalAmountMatched, + medianContributionSize: median(nonOAEContributions), + }; +}; + +// Done: summary data includes aggregations and averages +// - number of campaigns +// - number of donors +// - number of donations +// - median contribution size (exclude OAE type public match) +// - total amount contributed (by campaign?) +// - total amount matched (requires explanatory text since it won't be exactly 6x) + +export const summaryData = createSelector(sortedDonations, donations => + summarize(donations) +); + +export const summaryDataByParticipation = createSelector( + sortedDonationsParticipatingOnly, + sortedDonationsNonParticipatingOnly, + (participatingDonations, nonParticipatingDonations) => { + const summaryData = []; + participatingDonations.length > 0 && + summaryData.push( + addParticipatingStatus(summarize(participatingDonations), true) + ); + nonParticipatingDonations.length > 0 && + summaryData.push( + addParticipatingStatus(summarize(nonParticipatingDonations), false) + ); + return summaryData; + } +); + +const bracketize = donations => { + const aggregates = { + micro: { + total: 0, + contributions: [], + }, + small: { + total: 0, + contributions: [], + }, + medium: { + total: 0, + contributions: [], + }, + large: { + total: 0, + contributions: [], + }, + mega: { + total: 0, + contributions: [], + }, + }; + + const markers = ['micro', 'small', 'medium', 'large', 'mega']; + const breakpoints = [25, 100, 250, 1000]; + + let index = 0; + let marker = markers[index]; + let breakpoint = breakpoints[index]; + + donations.forEach(d => { + // Skip non-numeric values + if (+d.amount !== d.amount) return; + + if (d.amount > breakpoint) { + while (d.amount > breakpoint) { + index += 1; + marker = markers[index]; + if (index >= breakpoints.length) { + breakpoint = Number.MAX_VALUE; + break; + } + breakpoint = breakpoints[index]; + } + } + + // Categorize "Miscellaneous Cash Contributions $100 and under" in the 25-100 category + if ( + d.contributorName === 'Miscellaneous Cash Contributions $100 and under ' + ) { + aggregates.small.total += d.amount; + aggregates.small.contributions.push(d.amount); + return; + } + + aggregates[marker].total += d.amount; + aggregates[marker].contributions.push(d.amount); + }); + + return aggregates; +}; + +// Done: aggregate donation amounts by binned donations ranges +// - micro ($0-25) +// - small ($25-100) +// - medium ($100-250) +// - large ($250-1000) +// - mega ($1000+) +// For each bucket include three properties ({ name: 'micro', count: number of donations, total: sum of donations}) +export const donationSizeByDonationRange = createSelector( + sortedDonations, + donations => bracketize(donations) +); + +export const donationSizeByDonationRangeByCandidate = createSelector( + sortedDonationsByCandidate, + candidateDonations => + fromPairs( + Object.entries(candidateDonations).map(entry => [ + entry[0], + bracketize(entry[1]), + ]) + ) +); + +const aggregateDonationsBySize = aggregates => { + const markers = ['micro', 'small', 'medium', 'large', 'mega']; + const labels = ['<$25', '$25-$100', '$100-$250', '$250-$1000', '>$1000']; + const summarizedAggregates = markers.map((category, index) => { + return { + type: category, + formattedType: labels[index], + total: aggregates[category].total, + contributions: aggregates[category].contributions, + count: aggregates[category].contributions.length, + }; + }); + return summarizedAggregates; +}; + +export const aggregatedDonationSize = createSelector( + donationSizeByDonationRange, + aggregateDonationsBySize +); + +export const aggregatedDonationSizeByCandidate = createSelector( + donationSizeByDonationRangeByCandidate, + candidateDonations => { + if (Object.keys(candidateDonations).length < 1) { + return []; + } + return fromPairs( + Object.entries(candidateDonations).map(entry => [ + entry[0], + aggregateDonationsBySize(entry[1]), + ]) + ); + } +); + +// Done: count of and sum of donations for each contributor type +// (individual, business, family, labor, political_committee, political_party, unregistered, other) +// For each type include three properties ({ type: 'individual', count: number of donations, total: sum of donations }) +// Note: pad out the rest of the map with zeroes for each type that isn't represented in the data +const aggregateDonationsByContributorType = donations => { + const categories = [ + 'individual', + 'business', + 'family', + 'labor', + 'political_committee', + 'political_party', + 'unregistered', + 'other', + ]; + const aggregates = categories.reduce((agg, type) => { + agg[type] = { + total: 0, + contributions: [], + }; + return agg; + }, {}); + + donations.forEach(d => { + const bucket = aggregates[d.contributorType || 'other']; + bucket.total += d.amount; + bucket.contributions.push(d.amount); + }); + + const summarizedAggregates = categories.map(category => { + return { + type: category, + label: titleCase(category), + total: aggregates[category].total, + contributions: aggregates[category].contributions, + count: aggregates[category].contributions.length, + }; + }); + + return summarizedAggregates; +}; + +export const aggregatedContributorTypes = createSelector( + sortedDonations, + aggregateDonationsByContributorType +); + +export const aggregatedContributorTypesByCandidate = createSelector( + sortedDonationsByCandidate, + candidateDonations => { + if (Object.keys(candidateDonations).length < 1) { + return []; + } + return fromPairs( + Object.entries(candidateDonations).map(entry => [ + entry[0], + aggregateDonationsByContributorType(entry[1]), + ]) + ); + } +); + +// Done: count of and sum of donations for each contribution type +// (cash, inkind, other) +// Same as above data shape +const aggregateDonationsByContributionType = donations => { + const categories = ['cash', 'inkind', 'other']; + const aggregates = categories.reduce((agg, type) => { + agg[type] = { + total: 0, + contributions: [], + }; + return agg; + }, {}); + + donations.forEach(d => { + let type = 'other'; + if (d.contributionSubType === 'cash') type = 'cash'; + if ((d.contributionSubType || '').startsWith('inkind_')) type = 'inkind'; + + const bucket = aggregates[type]; + bucket.total += d.amount; + bucket.contributions.push(d.amount); + }); + + const summarizedAggregates = categories.map(category => { + return { + type: category, + formattedType: titleCase(category), + total: aggregates[category].total, + contributions: aggregates[category].contributions, + count: aggregates[category].contributions.length, + }; + }); + + return summarizedAggregates; +}; + +export const aggregatedContributionTypes = createSelector( + sortedDonations, + aggregateDonationsByContributionType +); + +export const aggregatedContributionTypesByCandidate = createSelector( + sortedDonationsByCandidate, + candidateDonations => { + if (Object.keys(candidateDonations).length < 1) { + return []; + } + return fromPairs( + Object.entries(candidateDonations).map(entry => [ + entry[0], + aggregateDonationsByContributionType(entry[1]), + ]) + ); + } +); + +// Done: count and sum of donations for each region +// (portland, oregon, outside) +// Note: filter out OAE subtype public_matching +// Note: do not include portland in oregon +const aggregateDonationsByRegion = donations => { + const categories = ['portland', 'oregon', 'out_of_state']; + const aggregates = categories.reduce((agg, type) => { + agg[type] = { + total: 0, + contributions: [], + }; + return agg; + }, {}); + + donations.forEach(d => { + let type = 'out_of_state'; + if ((d.state || '').toUpperCase() === 'OR') { + type = 'oregon'; + // NOTE: this is a strict address match. If we want to include the entire metro area, + // it would probably be better to check against a set of zipcodes or something. + if ((d.city || '').toUpperCase() === 'PORTLAND') type = 'portland'; + } + + const bucket = aggregates[type]; + bucket.total += d.amount; + bucket.contributions.push(d.amount); + }); + + const summarizedAggregates = categories.map(category => { + return { + type: category, + label: titleCase(category), + total: aggregates[category].total, + contributions: aggregates[category].contributions, + count: aggregates[category].contributions.length, + }; + }); + + return summarizedAggregates; +}; + +export const aggregatedContributionsByRegion = createSelector( + sortedDonations, + aggregateDonationsByRegion +); + +export const aggregatedContributionsByRegionByCandidate = createSelector( + sortedDonationsByCandidate, + candidateDonations => { + if (Object.keys(candidateDonations).length < 1) { + return []; + } + return fromPairs( + Object.entries(candidateDonations).map(entry => [ + entry[0], + aggregateDonationsByRegion(entry[1]), + ]) + ); + } +); + +// Done: create a table that matches this format +// | Campaign Name | Total Amount | Total Donations | Total Match Amount | Micro | Small | Medium | Large | Mega | +// | ------------- | ------------ | --------------- | ------------------ | ----- | ----- | ------ | ----- | ---- | +// | One | $1,234 | 29 | $20,444 | 15 | 12 | 1 | 1 | 0 | +// | Two | $1,234 | 29 | $20,444 | 15 | 12 | 1 | 1 | 0 | +export const campaignsTable = createSelector(sortedDonations, donations => { + const donationsByCampaign = groupBy('campaignId', donations); + const campaigns = Object.keys(donationsByCampaign).map(k => ({ + campaignId: k, + contributions: donationsByCampaign[k], + })); + + campaigns.forEach(campaign => { + Object.assign( + campaign, + summarize(campaign.contributions), + bracketize(campaign.contributions) + ); + + // Pull common properties of a contribution up + // to the campaign for convenience + const contribution = campaign.contributions[0]; + campaign.campaignName = contribution.campaignName; + campaign.officeSought = contribution.officeSought; + campaign.participatingStatus = contribution.campaignName !== 'Ted Wheeler'; + }); + + return campaigns; +}); diff --git a/app2/src/state/ducks/publicData.test.js b/app2/src/state/ducks/publicData.test.js new file mode 100644 index 000000000..544770dc3 --- /dev/null +++ b/app2/src/state/ducks/publicData.test.js @@ -0,0 +1,1767 @@ +import * as publicData from './publicData'; + +const { actionTypes } = publicData; + +const makeData = (features = [], overrides = {}) => { + const state = { + [publicData.STATE_KEY]: { + ...publicData.initialState, + data: { + type: 'FeatureCollection', + features, + }, + ...overrides, + }, + }; + return [state, JSON.parse(JSON.stringify(state[publicData.STATE_KEY]))]; +}; + +const point = (properties = {}, geometry = {}) => ({ + type: 'Feature', + properties, + geometry: { + type: 'Point', + coordinates: [-122.654, 45.516], + ...geometry, + }, +}); + +describe('Reducer', () => { + const reducer = publicData.default; + + describe('set campaigns', () => { + it('sets the campaigns filter', () => { + expect( + reducer(publicData.initialState, { + type: actionTypes.SET_FILTER.CAMPAIGNS, + campaigns: ['1', '2', '3'], + }).filters + ).toEqual({ + campaigns: ['1', '2', '3'], + financing: 'public', + offices: [], + startDate: null, + endDate: null, + count: false, + compare: true, + }); + }); + + it('is liberal with what it accepts', () => { + expect( + reducer(publicData.initialState, { + type: actionTypes.SET_FILTER.CAMPAIGNS, + campaigns: null, + }).filters + ).toEqual({ + campaigns: [], + financing: 'public', + offices: [], + startDate: null, + endDate: null, + count: false, + compare: false, + }); + + expect( + reducer(publicData.initialState, { + type: actionTypes.SET_FILTER.CAMPAIGNS, + campaigns: 'just-the-one', + }).filters + ).toEqual({ + campaigns: ['just-the-one'], + financing: 'public', + offices: [], + startDate: null, + endDate: null, + count: false, + compare: false, + }); + }); + }); + + describe('set offices', () => { + it('sets the offices filter', () => { + expect( + reducer(publicData.initialState, { + type: actionTypes.SET_FILTER.OFFICES, + offices: ['1', '2', '3'], + }).filters + ).toEqual({ + campaigns: [], + financing: 'public', + offices: ['1', '2', '3'], + startDate: null, + endDate: null, + count: false, + compare: false, + }); + }); + + it('is liberal with what it accepts', () => { + expect( + reducer(publicData.initialState, { + type: actionTypes.SET_FILTER.OFFICES, + offices: null, + }).filters + ).toEqual({ + campaigns: [], + financing: 'public', + offices: [], + startDate: null, + endDate: null, + count: false, + compare: false, + }); + + expect( + reducer(publicData.initialState, { + type: actionTypes.SET_FILTER.OFFICES, + offices: 'just-the-one', + }).filters + ).toEqual({ + campaigns: [], + financing: 'public', + offices: ['just-the-one'], + startDate: null, + endDate: null, + count: false, + compare: false, + }); + }); + }); + + describe('set financing', () => { + it('sets the financing filter', () => { + expect( + reducer(publicData.initialState, { + type: actionTypes.SET_FILTER.FINANCING, + financing: 'all', + }).filters + ).toEqual({ + campaigns: [], + financing: 'all', + offices: [], + startDate: null, + endDate: null, + count: false, + compare: false, + }); + }); + }); + + describe('set start date', () => { + it('sets the start date filter', () => { + const date = new Date(); + expect( + reducer(publicData.initialState, { + type: actionTypes.SET_FILTER.START_DATE, + startDate: date, + }).filters + ).toEqual({ + campaigns: [], + financing: 'public', + offices: [], + startDate: date, + endDate: null, + count: false, + compare: false, + }); + }); + }); + + describe('set end date', () => { + it('sets the end date filter', () => { + const date = new Date(); + expect( + reducer(publicData.initialState, { + type: actionTypes.SET_FILTER.END_DATE, + endDate: date, + }).filters + ).toEqual({ + campaigns: [], + financing: 'public', + offices: [], + startDate: null, + endDate: date, + count: false, + compare: false, + }); + }); + }); + + describe('set compare', () => { + it('sets the compare filter', () => { + expect( + reducer(publicData.initialState, { + type: actionTypes.SET_FILTER.COMPARE, + compare: true, + }).filters + ).toEqual({ + campaigns: [], + financing: 'public', + offices: [], + startDate: null, + endDate: null, + count: false, + compare: true, + }); + }); + }); + + describe('set custom', () => { + it('sets a custom filter', () => { + expect( + reducer(publicData.initialState, { + type: actionTypes.SET_FILTER.CUSTOM, + filters: { + financing: 'all', + count: true, + offices: ['1', '2', '3'], + campaigns: ['hazel'], + compare: true, + }, + }).filters + ).toEqual({ + campaigns: ['hazel'], + financing: 'all', + offices: ['1', '2', '3'], + startDate: null, + endDate: null, + count: true, + compare: true, + }); + }); + }); +}); + +describe('Selectors', () => { + describe('allPublicData', () => { + const [state, data] = makeData(); + + it('returns the object at the module STATE_KEY', () => { + expect(publicData.allPublicData(state)).toEqual(data); + }); + }); + + describe('publicDataFilters', () => { + const [emptyState] = makeData(); + + const filters = { + campaigns: [1, 2, 3], + offices: ['Mayor'], + startDate: new Date().toISOString(), + endDate: null, + count: false, + }; + const [stateWithSelections] = makeData([], { filters }); + + it('returns the current filter selections', () => { + expect(publicData.publicDataFilters(emptyState)).toEqual( + publicData.initialState.filters + ); + expect(publicData.publicDataFilters(stateWithSelections)).toEqual( + filters + ); + }); + }); + + describe('publicDataRequest', () => { + const [emptyState, emptyData] = makeData(); + const [stateWithData, dataWithData] = makeData( + [ + point({ type: 'contribution', campaignId: 1 }), + point({ type: 'contribution', campaignId: 2 }), + ], + { + isLoading: false, + error: null, + } + ); + + it('returns the data, isLoading, and error states', () => { + expect(publicData.publicDataRequest(emptyState)).toEqual({ + data: emptyData.data, + isLoading: emptyData.isLoading, + error: emptyData.error, + }); + + expect(publicData.publicDataRequest(stateWithData)).toEqual({ + data: dataWithData.data, + isLoading: dataWithData.isLoading, + error: dataWithData.error, + }); + }); + }); + + describe('publicDataGeojson', () => { + it('returns just the data from the state tree', () => { + const [state, data] = makeData(); + expect(publicData.publicDataGeojson(state)).toEqual(data.data); + }); + + it('converts date strings into Date objects where applicable', () => { + const [state, data] = makeData([ + point({ date: '2019-12-14T04:02:09.416Z' }), + point({ date: '2019-12-13T04:02:09.416Z' }), + point({ date: '2019-12-12T04:02:09.416Z' }), + ]); + + expect(publicData.publicDataGeojson(state)).not.toEqual(data.data); + expect( + publicData.publicDataGeojson(state).features.map(f => f.properties.date) + ).toEqual(data.data.features.map(f => new Date(f.properties.date))); + }); + }); + + describe('allOffices', () => { + it('returns an array of offices based on the data prop', () => { + const [state] = makeData([ + point({ officeSought: 'Mayor' }), + point({ officeSought: 'Commissioner 1' }), + point({ officeSought: 'Commissioner 2' }), + ]); + + expect(publicData.allOffices(state)).toEqual([ + 'Mayor', + 'Commissioner 1', + 'Commissioner 2', + ]); + }); + + it('does not return duplicate values', () => { + const [state] = makeData([ + point({ officeSought: 'Mayor' }), + point({ officeSought: 'Mayor' }), + point({ officeSought: 'Mayor' }), + ]); + + expect(publicData.allOffices(state)).toEqual(['Mayor']); + }); + + it('returns an empty array when there is no data', () => { + const [state] = makeData(); + + expect(publicData.allOffices(state)).toEqual([]); + }); + }); + + describe('allCampaigns', () => { + it('returns an array of campaign objects, including ID and Name', () => { + const campaigns = [ + { campaignId: '1', campaignName: 'Foo', officeSought: 'Mayor' }, + { campaignId: '2', campaignName: 'Bar', officeSought: 'Mayor' }, + { campaignId: '3', campaignName: 'Baz', officeSought: 'Commissioner' }, + ]; + const [state] = makeData(campaigns.map(point)); + + expect(publicData.allCampaigns(state)).toEqual( + campaigns.map(c => ({ + id: c.campaignId, + name: c.campaignName, + officeSought: c.officeSought, + })) + ); + }); + + it('does not return duplicate values (based on ID, last name wins)', () => { + const campaigns = [ + { campaignId: '1', campaignName: 'Foo 1', officeSought: 'Mayor' }, + { campaignId: '1', campaignName: 'Foo 2', officeSought: 'Mayor' }, + { campaignId: '2', campaignName: 'Bar 1', officeSought: 'Mayor' }, + { campaignId: '2', campaignName: 'Bar 2', officeSought: 'Mayor' }, + { campaignId: '3', campaignName: 'Foo 1', officeSought: 'Mayor' }, + { campaignId: '3', campaignName: 'Foo 2', officeSought: 'Mayor' }, + ]; + const [state] = makeData(campaigns.map(point)); + + expect(publicData.allCampaigns(state)).toEqual([ + { id: '1', name: 'Foo 2', officeSought: 'Mayor' }, + { id: '2', name: 'Bar 2', officeSought: 'Mayor' }, + { id: '3', name: 'Foo 2', officeSought: 'Mayor' }, + ]); + }); + + it('returns an empty array when there is no data', () => { + const [state] = makeData(); + + expect(publicData.allCampaigns(state)).toEqual([]); + }); + }); + + describe('availableCampaigns', () => { + const campaigns = [ + { campaignId: '1', campaignName: 'Foo', officeSought: 'First' }, + { campaignId: '2', campaignName: 'Bar', officeSought: 'Second' }, + { campaignId: '3', campaignName: 'Baz', officeSought: 'Third' }, + ]; + + it('returns an array of all campaigns when there is no office filter selection', () => { + const [state] = makeData(campaigns.map(point)); + expect(publicData.availableCampaigns(state)).toEqual([ + { id: '1', name: 'Foo', officeSought: 'First' }, + { id: '2', name: 'Bar', officeSought: 'Second' }, + { id: '3', name: 'Baz', officeSought: 'Third' }, + ]); + }); + + it('returns an array of only matching campaigns when there is an office filter selection', () => { + const [state] = makeData(campaigns.map(point), { + filters: { + offices: ['First', 'Third'], + }, + }); + expect(publicData.availableCampaigns(state)).toEqual([ + { id: '1', name: 'Foo', officeSought: 'First' }, + { id: '3', name: 'Baz', officeSought: 'Third' }, + ]); + }); + }); + + describe('filter selections', () => { + const startDate = new Date(); + const endDate = new Date(); + + const [state] = makeData([], { + filters: { + offices: ['Mayor', 'Test', 'Case'], + campaigns: [ + { id: '1', name: 'One' }, + { id: '2', name: 'Four' }, + { id: '3', name: 'Three' }, + ], + startDate, + endDate, + }, + }); + + const [emptyState] = makeData([], { + filters: {}, + }); + + it('returns a list of offices for selectedOffices', () => { + expect(publicData.selectedOffices(state)).toEqual([ + 'Mayor', + 'Test', + 'Case', + ]); + }); + + it('defaults to an empty array for selectedOffices', () => { + expect(publicData.selectedOffices(emptyState)).toEqual([]); + }); + + it('returns a list of campaign IDs for selectedCampaigns', () => { + expect(publicData.selectedCampaigns(state)).toEqual([ + { id: '1', name: 'One' }, + { id: '2', name: 'Four' }, + { id: '3', name: 'Three' }, + ]); + }); + + it('defaults to an empty array for selectedCampaigns', () => { + expect(publicData.selectedCampaigns(emptyState)).toEqual([]); + }); + + it('returns a date for selectedStartDate', () => { + expect(publicData.selectedStartDate(state)).toEqual(startDate); + }); + + it('returns a date for selectedEndDate', () => { + expect(publicData.selectedEndDate(state)).toEqual(endDate); + }); + }); + + describe('filtered selectors', () => { + const ids = d => d.properties.id; + + let incr = 0; + const factory = staticProps => date => { + incr += 1; + return point({ + id: incr, + date, + ...staticProps, + }); + }; + + const campaign1 = factory({ + officeSought: 'Mayor', + campaignId: '1', + campaignName: 'One', + }); + const campaign2 = factory({ + officeSought: 'Mayor', + campaignId: '2', + campaignName: 'Two', + }); + const campaign3 = factory({ + officeSought: 'Commissioner 1', + campaignId: '3', + campaignName: 'Three', + }); + const campaign4 = factory({ + officeSought: 'Commissioner 2', + campaignId: '4', + campaignName: 'Four', + }); + + const points = [ + campaign1('2019-12-01T04:02:09.416Z'), + campaign1('2019-12-07T04:02:09.416Z'), + campaign1('2019-12-14T04:02:09.416Z'), + + campaign2('2019-12-02T04:02:09.416Z'), + campaign2('2019-12-08T04:02:09.416Z'), + campaign2('2019-12-15T04:02:09.416Z'), + + campaign3('2019-12-03T04:02:09.416Z'), + campaign3('2019-12-09T04:02:09.416Z'), + campaign3('2019-12-16T04:02:09.416Z'), + + campaign4('2019-12-04T04:02:09.416Z'), + campaign4('2019-12-10T04:02:09.416Z'), + campaign4('2019-12-17T04:02:09.416Z'), + ]; + + describe('filteredPublicData', () => { + it('returns all data when there is no active filter', () => { + const [state] = makeData(points, { + filters: {}, + }); + + const { features } = publicData.filteredPublicData(state); + expect(features).toHaveLength(points.length); + expect(features.map(ids)).toEqual(points.map(ids)); + }); + + it('returns all data matching any selected office', () => { + const [singleState] = makeData(points, { + filters: { + offices: ['Mayor'], + }, + }); + + const [multiState] = makeData(points, { + filters: { + offices: ['Mayor', 'Commissioner 2'], + }, + }); + + const { features: singleFeatures } = publicData.filteredPublicData( + singleState + ); + const { features: multiFeatures } = publicData.filteredPublicData( + multiState + ); + + expect(singleFeatures.map(ids)).toEqual([1, 2, 3, 4, 5, 6]); + expect(multiFeatures.map(ids)).toEqual([1, 2, 3, 4, 5, 6, 10, 11, 12]); + }); + + it('returns all data matching any selected campaign', () => { + const [singleState] = makeData(points, { + filters: { + campaigns: [{ id: '1', name: 'One' }], + }, + }); + + const [multiState] = makeData(points, { + filters: { + campaigns: [ + { id: '1', name: 'One' }, + { id: '3', name: 'Three' }, + { id: '4', name: 'Four' }, + ], + }, + }); + + const { features: singleFeatures } = publicData.filteredPublicData( + singleState + ); + const { features: multiFeatures } = publicData.filteredPublicData( + multiState + ); + + expect(singleFeatures.map(ids)).toEqual([1, 2, 3]); + expect(multiFeatures.map(ids)).toEqual([1, 2, 3, 7, 8, 9, 10, 11, 12]); + }); + + it('returns only data matching both selected campaigns AND selected offices', () => { + const [state] = makeData(points, { + filters: { + campaigns: [ + { id: '2', name: 'Two' }, + { id: '4', name: 'Four' }, + ], + offices: ['Mayor', 'Commissioner 1'], + }, + }); + + const { features } = publicData.filteredPublicData(state); + + expect(features.map(ids)).toEqual([4, 5, 6]); + }); + + it('returns all data after or including the start date', () => { + const [state] = makeData(points, { + filters: { + startDate: new Date('2019-12-10T04:02:09.416Z'), + }, + }); + + const { features } = publicData.filteredPublicData(state); + expect(features.map(ids)).toEqual([3, 6, 9, 11, 12]); + }); + + it('returns all data before or including the end date', () => { + const [state] = makeData(points, { + filters: { + endDate: new Date('2019-12-06T04:02:09.416Z'), + }, + }); + + const { features } = publicData.filteredPublicData(state); + expect(features.map(ids)).toEqual([1, 4, 7, 10]); + }); + + it('returns only data within (inclusive) the start and end date', () => { + const [state] = makeData(points, { + filters: { + startDate: new Date('2019-12-06T04:02:09.416Z'), + endDate: new Date('2019-12-10T04:02:09.416Z'), + }, + }); + + const { features } = publicData.filteredPublicData(state); + expect(features.map(ids)).toEqual([2, 5, 8, 11]); + }); + + it('returns only data within the start and end date matching both selected campaigns AND selected offices', () => { + const [state] = makeData(points, { + filters: { + campaigns: [ + { id: '2', name: 'Two' }, + { id: '4', name: 'Four' }, + ], + offices: ['Mayor'], + startDate: new Date('2019-12-03T04:02:09.416Z'), + endDate: new Date('2019-12-14T04:02:09.416Z'), + }, + }); + + const { features } = publicData.filteredPublicData(state); + expect(features.map(ids)).toEqual([5]); + }); + }); + + describe('mapData', () => { + it('returns filteredPublicData, since it is already GeoJSON', () => { + const [state] = makeData(points, { + filters: { + offices: ['Mayor'], + }, + }); + + expect(publicData.mapData(state)).toEqual({ + type: 'FeatureCollection', + features: points.slice(0, 6), + }); + }); + }); + }); + + describe('summaryData', () => { + const summaryPoint = ( + campaignName, + contributorName, + amount, + matchAmount, + oaeType + ) => point({ campaignName, contributorName, amount, matchAmount, oaeType }); + + const points = [ + summaryPoint('Zyx', 'Abc', 10, null, 'allowable'), + summaryPoint('Zyx', 'Abc', 20, 120, 'matchable'), + summaryPoint('Yxw', 'Def', 30, 150, 'matchable'), + summaryPoint('Xwv', 'Ghi', 100, null, 'public_matching_contribution'), + summaryPoint('Wvu', 'Jkl', 5, 30, 'matchable'), + summaryPoint( + 'Wvu', + 'Miscellaneous Cash Contributions $100 and under ', + 150, + null, + 'allowable' + ), + summaryPoint( + 'Wvu', + 'Miscellaneous Cash Contributions $100 and under ', + 150, + null, + 'allowable' + ), + ]; + + const [state] = makeData(points); + + it('returns the total number of donations (excluding public_matching_contribution', () => { + expect(publicData.summaryData(state).donationsCount).toEqual( + points.length - 1 + ); + }); + + it('returns the total number of campaigns (uniqued by campaign name, excluding public matching contribution)', () => { + expect(publicData.summaryData(state).campaignsCount).toEqual(3); + }); + + it('returns the total number of donors (uniqued by contributor name, excluding public matching contribution, counting each bundled contribution as 1 donor)', () => { + expect(publicData.summaryData(state).donorsCount).toEqual(5); + }); + + it('returns the total amount contributed (excluding public matching contributions) and the total amount matched', () => { + const total = 10 + 20 + 30 + 5 + 150 + 150; + const matchTotal = 120 + 150 + 30; + expect(publicData.summaryData(state).totalAmountContributed).toEqual( + total + ); + expect(publicData.summaryData(state).totalAmountMatched).toEqual( + matchTotal + ); + }); + + it('returns the median contribution size, excluding public_matching_contribution types', () => { + // Contributions + // [ 10, 20, 30, 100, 5, 150, 150 ] + // Exclude public_matching_contribution types + // [ 10, 20, 30, 5, 150, 150 ] + // Sort + // [ 5.23, 10, 20, 30, 150, 150 ] + // Median (avg middle data points) + // (20 + 30) / 2 = 25 + expect(publicData.summaryData(state).medianContributionSize).toEqual(25); + }); + }); + + describe('donationSizeByDonationRange', () => { + it('buckets and summates donations appropriately', () => { + const points = [ + point({ amount: 0 }), + point({ amount: 5 }), + point({ amount: 10 }), + point({ amount: 20 }), + point({ amount: 30 }), + point({ amount: 50 }), + point({ amount: 100 }), + point({ amount: 150 }), + point({ amount: 200 }), + point({ amount: 500 }), + point({ amount: 750 }), + point({ amount: 1000 }), + point({ amount: 2500 }), + ]; + + const [state] = makeData(points); + + expect(publicData.donationSizeByDonationRange(state)).toEqual({ + micro: { + total: 0 + 5 + 10 + 20, + contributions: [0, 5, 10, 20], + }, + small: { + total: 30 + 50 + 100, + contributions: [30, 50, 100], + }, + medium: { + total: 150 + 200, + contributions: [150, 200], + }, + large: { + total: 500 + 750 + 1000, + contributions: [500, 750, 1000], + }, + mega: { + total: 2500, + contributions: [2500], + }, + }); + }); + + it('buckets and summates donations appropriately including ', () => { + const points = [ + point({ amount: 0 }), + point({ amount: 5 }), + point({ amount: 10 }), + point({ amount: 20 }), + point({ amount: 30 }), + point({ amount: 50 }), + point({ amount: 100 }), + point({ amount: 150 }), + point({ amount: 200 }), + point({ amount: 500 }), + point({ amount: 750 }), + point({ amount: 1000 }), + point({ + amount: 2500, + contributorName: 'Miscellaneous Cash Contributions $100 and under ', + }), + point({ amount: 2500 }), + ]; + + const [state] = makeData(points); + + expect(publicData.donationSizeByDonationRange(state)).toEqual({ + micro: { + total: 0 + 5 + 10 + 20, + contributions: [0, 5, 10, 20], + }, + small: { + total: 30 + 50 + 100 + 2500, + contributions: [30, 50, 100, 2500], + }, + medium: { + total: 150 + 200, + contributions: [150, 200], + }, + large: { + total: 500 + 750 + 1000, + contributions: [500, 750, 1000], + }, + mega: { + total: 2500, + contributions: [2500], + }, + }); + }); + + it('reports 0 for any empty buckets', () => { + const points = [ + point({ amount: 30 }), + point({ amount: 50 }), + point({ amount: 1000 }), + point({ amount: 2500 }), + ]; + + const [state] = makeData(points); + + expect(publicData.donationSizeByDonationRange(state)).toEqual({ + micro: { + total: 0, + contributions: [], + }, + small: { + total: 30 + 50, + contributions: [30, 50], + }, + medium: { + total: 0, + contributions: [], + }, + large: { + total: 1000, + contributions: [1000], + }, + mega: { + total: 2500, + contributions: [2500], + }, + }); + }); + }); + + describe('donationSizeByDonationRangeByCandidate', () => { + const summaryPoint = (campaignId, campaignName, amount) => + point({ + campaignId, + campaignName, + amount, + officeSought: 'Mayor', + }); + + const points = [ + summaryPoint('1', 'One', 5), + summaryPoint('1', 'One', 1000), + + summaryPoint('2', 'Two', 5), + summaryPoint('2', 'Two', 20), + ]; + + const filters = { + campaigns: [ + { id: '1', name: 'One' }, + { id: '2', name: 'Two' }, + ], + }; + + const [stateWithSelections] = makeData(points, { filters }); + + it('buckets and summates appropriately in an object by candidate', () => { + expect( + publicData.donationSizeByDonationRangeByCandidate(stateWithSelections) + ).toEqual({ + One: { + micro: { + total: 5, + contributions: [5], + }, + small: { + total: 0, + contributions: [], + }, + medium: { + total: 0, + contributions: [], + }, + large: { + total: 1000, + contributions: [1000], + }, + mega: { + total: 0, + contributions: [], + }, + }, + Two: { + micro: { + total: 5 + 20, + contributions: [5, 20], + }, + small: { + total: 0, + contributions: [], + }, + medium: { + total: 0, + contributions: [], + }, + large: { + total: 0, + contributions: [], + }, + mega: { + total: 0, + contributions: [], + }, + }, + }); + }); + }); + + describe('aggregatedContributorTypes', () => { + const summaryPoint = (contributorType, amount) => + point({ contributorType, amount }); + + it('buckets and summates donations appropriately', () => { + const points = [ + summaryPoint('individual', 10), + summaryPoint('individual', 15), + summaryPoint('business', 100), + summaryPoint('business', 1450), + summaryPoint('business', 890), + summaryPoint('family', 50), + summaryPoint('labor', 500), + summaryPoint('political_committee', 30), + summaryPoint('political_party', 100), + summaryPoint('unregistered', 150), + summaryPoint('other', 10), + summaryPoint(null, 9), + ]; + + const [state] = makeData(points); + + expect(publicData.aggregatedContributorTypes(state)).toEqual([ + { + type: 'individual', + label: 'Individual', + total: 10 + 15, + contributions: [10, 15], + count: 2, + }, + { + type: 'business', + label: 'Business', + total: 100 + 1450 + 890, + contributions: [100, 890, 1450], + count: 3, + }, + { + type: 'family', + label: 'Family', + total: 50, + contributions: [50], + count: 1, + }, + { + type: 'labor', + label: 'Labor', + total: 500, + contributions: [500], + count: 1, + }, + { + type: 'political_committee', + label: 'Political Committee', + total: 30, + contributions: [30], + count: 1, + }, + { + type: 'political_party', + label: 'Political Party', + total: 100, + contributions: [100], + count: 1, + }, + { + type: 'unregistered', + label: 'Unregistered', + total: 150, + contributions: [150], + count: 1, + }, + { + type: 'other', + label: 'Other', + total: 9 + 10, + contributions: [9, 10], + count: 2, + }, + ]); + }); + + it('reports 0 for any empty buckets', () => { + const points = [ + summaryPoint('individual', 10), + summaryPoint('individual', 15), + summaryPoint('business', 100), + summaryPoint('business', 1450), + summaryPoint('business', 890), + summaryPoint('unregistered', 150), + ]; + + const [state] = makeData(points); + + expect(publicData.aggregatedContributorTypes(state)).toEqual([ + { + type: 'individual', + label: 'Individual', + total: 10 + 15, + contributions: [10, 15], + count: 2, + }, + { + type: 'business', + label: 'Business', + total: 100 + 1450 + 890, + contributions: [100, 890, 1450], + count: 3, + }, + { + type: 'family', + label: 'Family', + total: 0, + contributions: [], + count: 0, + }, + { + type: 'labor', + label: 'Labor', + total: 0, + contributions: [], + count: 0, + }, + { + type: 'political_committee', + label: 'Political Committee', + total: 0, + contributions: [], + count: 0, + }, + { + type: 'political_party', + label: 'Political Party', + total: 0, + contributions: [], + count: 0, + }, + { + type: 'unregistered', + label: 'Unregistered', + total: 150, + contributions: [150], + count: 1, + }, + { + type: 'other', + label: 'Other', + total: 0, + contributions: [], + count: 0, + }, + ]); + }); + }); + + describe('aggregatedContributorTypesByCandidate', () => { + const summaryPoint = (campaignId, campaignName, amount, contributorType) => + point({ + campaignId, + campaignName, + amount, + contributorType, + }); + + const points = [ + summaryPoint('1', 'One', 5, 'individual'), + summaryPoint('1', 'One', 5, 'individual'), + summaryPoint('1', 'One', 20, 'unregistered'), + summaryPoint('2', 'Two', 1000, 'business'), + ]; + + const filters = { + campaigns: [ + { id: '1', name: 'One' }, + { id: '2', name: 'Two' }, + ], + }; + + const [stateWithSelections] = makeData(points, { filters }); + + it('buckets and summates appropriately in an object by candidate', () => { + expect( + publicData.aggregatedContributorTypesByCandidate(stateWithSelections) + ).toEqual({ + One: [ + { + type: 'individual', + label: 'Individual', + total: 5 + 5, + contributions: [5, 5], + count: 2, + }, + { + type: 'business', + label: 'Business', + total: 0, + contributions: [], + count: 0, + }, + { + type: 'family', + label: 'Family', + total: 0, + contributions: [], + count: 0, + }, + { + type: 'labor', + label: 'Labor', + total: 0, + contributions: [], + count: 0, + }, + { + type: 'political_committee', + label: 'Political Committee', + total: 0, + contributions: [], + count: 0, + }, + { + type: 'political_party', + label: 'Political Party', + total: 0, + contributions: [], + count: 0, + }, + { + type: 'unregistered', + label: 'Unregistered', + total: 20, + contributions: [20], + count: 1, + }, + { + type: 'other', + label: 'Other', + total: 0, + contributions: [], + count: 0, + }, + ], + Two: [ + { + type: 'individual', + label: 'Individual', + total: 0, + contributions: [], + count: 0, + }, + { + type: 'business', + label: 'Business', + total: 1000, + contributions: [1000], + count: 1, + }, + { + type: 'family', + label: 'Family', + total: 0, + contributions: [], + count: 0, + }, + { + type: 'labor', + label: 'Labor', + total: 0, + contributions: [], + count: 0, + }, + { + type: 'political_committee', + label: 'Political Committee', + total: 0, + contributions: [], + count: 0, + }, + { + type: 'political_party', + label: 'Political Party', + total: 0, + contributions: [], + count: 0, + }, + { + type: 'unregistered', + label: 'Unregistered', + total: 0, + contributions: [], + count: 0, + }, + { + type: 'other', + label: 'Other', + total: 0, + contributions: [], + count: 0, + }, + ], + }); + }); + }); + + describe('aggregatedContributionTypes', () => { + const summaryPoint = (contributionSubType, amount) => + point({ contributionSubType, amount }); + + it('buckets and summates donations appropriately', () => { + const points = [ + summaryPoint('cash', 10), + summaryPoint('cash', 14), + summaryPoint('inkind_onefish', 40), + summaryPoint('inkind_2_fish', 95), + summaryPoint('inkind_redfish', 100), + summaryPoint('inkind_bluefish', 139), + summaryPoint('other', 10), + summaryPoint('nothing', 25), + summaryPoint(null, 5), + ]; + + const [state] = makeData(points); + + expect(publicData.aggregatedContributionTypes(state)).toEqual([ + { + type: 'cash', + formattedType: 'Cash', + total: 10 + 14, + contributions: [10, 14], + count: 2, + }, + { + type: 'inkind', + formattedType: 'Inkind', + total: 40 + 95 + 100 + 139, + contributions: [40, 95, 100, 139], + count: 4, + }, + { + type: 'other', + formattedType: 'Other', + total: 10 + 25 + 5, + contributions: [5, 10, 25], + count: 3, + }, + ]); + }); + + it('reports 0 for any empty buckets', () => { + const points = [ + summaryPoint('inkind_onefish', 40), + summaryPoint('inkind_2_fish', 95), + summaryPoint('inkind_redfish', 100), + summaryPoint('inkind_bluefish', 139), + ]; + + const [state] = makeData(points); + + expect(publicData.aggregatedContributionTypes(state)).toEqual([ + { + type: 'cash', + formattedType: 'Cash', + total: 0, + contributions: [], + count: 0, + }, + { + type: 'inkind', + formattedType: 'Inkind', + total: 40 + 95 + 100 + 139, + contributions: [40, 95, 100, 139], + count: 4, + }, + { + type: 'other', + formattedType: 'Other', + total: 0, + contributions: [], + count: 0, + }, + ]); + }); + }); + + describe('aggregatedContributionTypesByCandidate', () => { + const summaryPoint = ( + campaignId, + campaignName, + amount, + contributionSubType + ) => + point({ + campaignId, + campaignName, + amount, + contributionSubType, + }); + + const points = [ + summaryPoint('1', 'One', 5, 'cash'), + summaryPoint('1', 'One', 7, 'cash'), + summaryPoint('1', 'One', 20, 'inkind_onefish'), + summaryPoint('2', 'Two', 1000, 'other'), + ]; + + const filters = { + campaigns: [ + { id: '1', name: 'One' }, + { id: '2', name: 'Two' }, + ], + }; + + const [stateWithSelections] = makeData(points, { filters }); + + it('buckets and summates donations appropriately in an object by candidate', () => { + expect( + publicData.aggregatedContributionTypesByCandidate(stateWithSelections) + ).toEqual({ + One: [ + { + type: 'cash', + formattedType: 'Cash', + total: 5 + 7, + contributions: [5, 7], + count: 2, + }, + { + type: 'inkind', + formattedType: 'Inkind', + total: 20, + contributions: [20], + count: 1, + }, + { + type: 'other', + formattedType: 'Other', + total: 0, + contributions: [], + count: 0, + }, + ], + Two: [ + { + type: 'cash', + formattedType: 'Cash', + total: 0, + contributions: [], + count: 0, + }, + { + type: 'inkind', + formattedType: 'Inkind', + total: 0, + contributions: [], + count: 0, + }, + { + type: 'other', + formattedType: 'Other', + total: 1000, + contributions: [1000], + count: 1, + }, + ], + }); + }); + }); + + describe('aggregatedContributionsByRegion', () => { + const summaryPoint = (city, state, amount) => + point({ city, state, amount }); + + it('buckets and summates donations appropriately', () => { + const points = [ + summaryPoint('portland', 'or', 10), + summaryPoint('portland', 'or', 25), + summaryPoint('portland', 'me', 200), + summaryPoint('eugene', 'or', 100), + summaryPoint('gresham', 'or', 25), + summaryPoint('wamic', 'or', 100), + summaryPoint('culver', 'or', 50), + summaryPoint('new york city', 'ny', 1000), + ]; + + const [state] = makeData(points); + + expect(publicData.aggregatedContributionsByRegion(state)).toEqual([ + { + type: 'portland', + label: 'Portland', + total: 10 + 25, + contributions: [10, 25], + count: 2, + }, + { + type: 'oregon', + label: 'Oregon', + total: 100 + 25 + 100 + 50, + contributions: [25, 50, 100, 100], + count: 4, + }, + { + type: 'out_of_state', + label: 'Out Of State', + total: 200 + 1000, + contributions: [200, 1000], + count: 2, + }, + ]); + }); + + it('reports 0 for any empty buckets', () => { + const points = [ + summaryPoint('eugene', 'or', 100), + summaryPoint('gresham', 'or', 25), + summaryPoint('wamic', 'or', 100), + summaryPoint('culver', 'or', 50), + ]; + + const [state] = makeData(points); + + expect(publicData.aggregatedContributionsByRegion(state)).toEqual([ + { + type: 'portland', + label: 'Portland', + total: 0, + contributions: [], + count: 0, + }, + { + type: 'oregon', + label: 'Oregon', + total: 100 + 25 + 100 + 50, + contributions: [25, 50, 100, 100], + count: 4, + }, + { + type: 'out_of_state', + label: 'Out Of State', + total: 0, + contributions: [], + count: 0, + }, + ]); + }); + }); + + describe('aggregatedContributionsByRegionByCandidate', () => { + const summaryPoint = (campaignId, campaignName, amount, city, state) => + point({ + campaignId, + campaignName, + amount, + city, + state, + }); + + const points = [ + summaryPoint('1', 'One', 5, 'portland', 'or'), + summaryPoint('1', 'One', 7, 'gresham', 'or'), + summaryPoint('1', 'One', 20, 'washington', 'dc'), + summaryPoint('2', 'Two', 1000, 'washington', 'dc'), + ]; + + const filters = { + campaigns: [ + { id: '1', name: 'One' }, + { id: '2', name: 'Two' }, + ], + }; + + const [stateWithSelections] = makeData(points, { filters }); + + it('aggregates and summates appropriately in an object by candidate', () => { + expect( + publicData.aggregatedContributionsByRegionByCandidate( + stateWithSelections + ) + ).toEqual({ + One: [ + { + type: 'portland', + label: 'Portland', + total: 5, + contributions: [5], + count: 1, + }, + { + type: 'oregon', + label: 'Oregon', + total: 7, + contributions: [7], + count: 1, + }, + { + type: 'out_of_state', + label: 'Out Of State', + total: 20, + contributions: [20], + count: 1, + }, + ], + Two: [ + { + type: 'portland', + label: 'Portland', + total: 0, + contributions: [], + count: 0, + }, + { + type: 'oregon', + label: 'Oregon', + total: 0, + contributions: [], + count: 0, + }, + { + type: 'out_of_state', + label: 'Out Of State', + total: 1000, + contributions: [1000], + count: 1, + }, + ], + }); + }); + }); + + describe('campaignsTable', () => { + const summaryPoint = ( + campaignId, + campaignName, + contributorName, + amount, + matchAmount, + oaeType + ) => + point({ + campaignId, + campaignName, + contributorName, + amount, + matchAmount, + oaeType, + officeSought: 'Mayor', + }); + + // public_matching_contribution + + const points = [ + summaryPoint('1', 'One', 'Abc', 5, 30, 'matchable'), + summaryPoint('1', 'One', 'Def', 20, 120, 'matchable'), + summaryPoint('1', 'One', 'Def', 100, 0, 'allowable'), + summaryPoint('1', 'One', 'Ghi', 1000, null, 'allowable'), + + summaryPoint('2', 'Two', 'Def', 5, 30, 'matchable'), + summaryPoint('2', 'Two', 'Ghi', 5, 30, 'matchable'), + summaryPoint('2', 'Two', 'Ghi', 20, 120, 'matchable'), + summaryPoint('2', 'Two', 'Jkl', 25, 150, 'matchable'), + summaryPoint('2', 'Two', 'Jkl', 35, 210, 'matchable'), + summaryPoint('2', 'Two', 'Mno', 100, 0, 'allowable'), + summaryPoint( + '2', + 'Two', + 'Mno', + 500, + null, + 'public_matching_contribution' + ), + + summaryPoint('3', 'Three', 'Abc', 50, 300, 'matchable'), + summaryPoint('3', 'Three', 'Abc', 50, 300, 'matchable'), + summaryPoint('3', 'Three', 'Abc', 78, 0, 'allowable'), + summaryPoint('3', 'Three', 'Abc', 501, 30, 'allowable'), + + summaryPoint('4', 'Four', 'Def', 5, 30, 'matchable'), + summaryPoint('4', 'Four', 'Ghi', 6, 36, 'matchable'), + summaryPoint('4', 'Four', 'Jkl', 7, 42, 'matchable'), + ]; + + const [state] = makeData(points); + + expect(publicData.campaignsTable(state)).toEqual([ + { + campaignId: '1', + campaignName: 'One', + campaignsCount: 1, + officeSought: 'Mayor', + participatingStatus: true, + donationsCount: 4, + donorsCount: 3, + totalAmountContributed: 5 + 20 + 100 + 1000, + totalAmountMatched: 30 + 120, + medianContributionSize: 60, + micro: { + total: 5 + 20, + contributions: [5, 20], + }, + small: { + total: 100, + contributions: [100], + }, + medium: { + total: 0, + contributions: [], + }, + large: { + total: 1000, + contributions: [1000], + }, + mega: { + total: 0, + contributions: [], + }, + contributions: points.slice(0, 4).map(p => p.properties), + }, + { + campaignId: '2', + campaignName: 'Two', + campaignsCount: 1, + officeSought: 'Mayor', + participatingStatus: true, + donationsCount: 6, + donorsCount: 4, + totalAmountContributed: 5 + 5 + 20 + 25 + 35 + 100, + totalAmountMatched: 30 + 30 + 120 + 150 + 210, + medianContributionSize: 22.5, + micro: { + total: 5 + 5 + 20 + 25, + contributions: [5, 5, 20, 25], + }, + small: { + total: 35 + 100, + contributions: [35, 100], + }, + medium: { + total: 0, + contributions: [], + }, + large: { + total: 0, + contributions: [], + }, + mega: { + total: 0, + contributions: [], + }, + contributions: points.slice(4, 10).map(p => p.properties), + }, + { + campaignId: '3', + campaignName: 'Three', + campaignsCount: 1, + officeSought: 'Mayor', + participatingStatus: true, + donationsCount: 4, + donorsCount: 1, + totalAmountContributed: 50 + 50 + 78 + 501, + totalAmountMatched: 300 + 300 + 30, + medianContributionSize: 64, + micro: { + total: 0, + contributions: [], + }, + small: { + total: 50 + 50 + 78, + contributions: [50, 50, 78], + }, + medium: { + total: 0, + contributions: [], + }, + large: { + total: 501, + contributions: [501], + }, + mega: { + total: 0, + contributions: [], + }, + contributions: points.slice(11, 15).map(p => p.properties), + }, + { + campaignId: '4', + campaignName: 'Four', + campaignsCount: 1, + officeSought: 'Mayor', + participatingStatus: true, + donationsCount: 3, + donorsCount: 3, + totalAmountContributed: 5 + 6 + 7, + totalAmountMatched: 30 + 36 + 42, + medianContributionSize: 6, + micro: { + total: 5 + 6 + 7, + contributions: [5, 6, 7], + }, + small: { + total: 0, + contributions: [], + }, + medium: { + total: 0, + contributions: [], + }, + large: { + total: 0, + contributions: [], + }, + mega: { + total: 0, + contributions: [], + }, + contributions: points.slice(15).map(p => p.properties), + }, + ]); + }); +}); diff --git a/app2/src/state/ducks/summary.js b/app2/src/state/ducks/summary.js new file mode 100644 index 000000000..2b304c3b7 --- /dev/null +++ b/app2/src/state/ducks/summary.js @@ -0,0 +1,69 @@ +/* eslint-disable no-unused-vars */ +import createReducer from '../utils/createReducer'; +import createActionTypes from '../utils/createActionTypes'; +import action from '../utils/action'; + +export const STATE_KEY = 'summary'; + +// Action Types +export const actionTypes = { + GET_SUMMARY: createActionTypes(STATE_KEY, 'GET_SUMMARY'), +}; + +// Initial State +export const initialState = { + isLoading: false, + error: null, + contributions: [], + expenditures: [], +}; +// Reducer + +export default createReducer(initialState, { + [actionTypes.GET_SUMMARY.REQUEST]: state => { + return { ...state, isLoading: true }; + }, + [actionTypes.GET_SUMMARY.SUCCESS]: (state, action) => { + return { + isLoading: false, + contributions: action.contributions, + expenditures: action.expenditures, + }; + }, + [actionTypes.GET_SUMMARY.FAILURE]: (state, action) => { + return { ...state, isLoading: false, error: action.error }; + }, +}); + +// Action Creators +export const actionCreators = { + getStatusSummary: { + request: () => action(actionTypes.GET_SUMMARY.REQUEST), + success: (contributions, expenditures) => + action(actionTypes.GET_SUMMARY.SUCCESS, { + contributions, + expenditures, + }), + failure: error => action(actionTypes.GET_SUMMARY.FAILURE, { error }), + }, +}; + +// Side Effects, e.g. thunks +// attrs of campaignId or governmentId +export function getStatusSummaryAction(attrs) { + return async (dispatch, getState, { api, schema }) => { + dispatch(actionCreators.getStatusSummary.request()); + try { + const response = await api.getStatusSummary(attrs); + const body = await response.json(); + dispatch( + actionCreators.getStatusSummary.success( + body.contributions, + body.expenditures + ) + ); + } catch (error) { + dispatch(actionCreators.getStatusSummary.failure(error)); + } + }; +} diff --git a/app2/src/state/ducks/users.js b/app2/src/state/ducks/users.js new file mode 100644 index 000000000..2c3615f09 --- /dev/null +++ b/app2/src/state/ducks/users.js @@ -0,0 +1,252 @@ +/* eslint-disable no-unused-vars */ +import { normalize } from 'normalizr'; +import { createSelector } from 'reselect'; +import { get, startCase } from 'lodash'; +import { flashMessage } from 'redux-flash'; +import { push } from 'connected-react-router'; +import createReducer from '../utils/createReducer'; +import createActionTypes from '../utils/createActionTypes'; +import action from '../utils/action'; +import { addEntities, ADD_ENTITIES, resetState, RESET_STATE } from './common'; +import { removePermission } from './permissions'; +import { clearModal } from './modal'; + +export const STATE_KEY = 'users'; + +// Action Types +export const actionTypes = { + INVITE_USER: createActionTypes(STATE_KEY, 'INVITE_USER'), + RESEND_USER_INVITE: createActionTypes(STATE_KEY, 'RESEND_USER_INVITE'), + GET_GOVERNMENT_USERS: createActionTypes(STATE_KEY, 'GET_GOVERNMENT_USERS'), + GET_CAMPAIGN_USERS: createActionTypes(STATE_KEY, 'GET_CAMPAIGN_USERS'), + REMOVE_USER: createActionTypes(STATE_KEY, 'REMOVE_USER'), +}; + +// Initial State +export const initialState = { + isLoading: false, + error: null, +}; + +export const resetUserState = resetState; +// Reducer +export default createReducer(initialState, { + [RESET_STATE]: () => { + return { ...initialState }; + }, + [ADD_ENTITIES]: (state, action) => { + return { ...state, ...action.payload.users }; + }, + [actionTypes.INVITE_USER.REQUEST]: state => { + return { ...state, isLoading: true }; + }, + [actionTypes.INVITE_USER.SUCCESS]: state => { + return { ...state, isLoading: false }; + }, + [actionTypes.INVITE_USER.FAILURE]: (state, action) => { + return { ...state, isLoading: false, error: action.error }; + }, + [actionTypes.RESEND_USER_INVITE.REQUEST]: state => { + return { ...state, isLoading: true }; + }, + [actionTypes.RESEND_USER_INVITE.SUCCESS]: state => { + return { ...state, isLoading: false }; + }, + [actionTypes.RESEND_USER_INVITE.FAILURE]: (state, action) => { + return { ...state, isLoading: false, error: action.error }; + }, + [actionTypes.GET_GOVERNMENT_USERS.REQUEST]: state => { + return { ...state, isLoading: true }; + }, + [actionTypes.GET_GOVERNMENT_USERS.SUCCESS]: state => { + return { ...state, isLoading: false }; + }, + [actionTypes.GET_GOVERNMENT_USERS.FAILURE]: (state, action) => { + return { ...state, isLoading: false, error: action.error }; + }, + [actionTypes.GET_CAMPAIGN_USERS.REQUEST]: state => { + return { ...state, isLoading: true }; + }, + [actionTypes.GET_CAMPAIGN_USERS.SUCCESS]: state => { + return { ...state, isLoading: false }; + }, + [actionTypes.GET_CAMPAIGN_USERS.FAILURE]: (state, action) => { + return { ...state, isLoading: false, error: action.error }; + }, + [actionTypes.REMOVE_USER.REQUEST]: (state, action) => { + return { ...state, isLoading: true, error: action.error || null }; + }, + [actionTypes.REMOVE_USER.SUCCESS]: (state, action) => { + const newState = { ...state, isLoading: false }; + delete newState[action.userId]; + return newState; + }, + [actionTypes.REMOVE_USER.FAILURE]: (state, action) => { + return { ...state, isLoading: false, error: action.error }; + }, +}); + +// Action Creators +export const actionCreators = { + inviteUser: { + request: () => action(actionTypes.INVITE_USER.REQUEST), + success: () => action(actionTypes.INVITE_USER.SUCCESS), + failure: error => action(actionTypes.INVITE_USER.FAILURE, { error }), + }, + resendUserInvite: { + request: () => action(actionTypes.RESEND_USER_INVITE.REQUEST), + success: () => action(actionTypes.RESEND_USER_INVITE.SUCCESS), + failure: error => action(actionTypes.RESEND_USER_INVITE.FAILURE, { error }), + }, + getGovernmentUsers: { + request: () => action(actionTypes.GET_GOVERNMENT_USERS.REQUEST), + success: () => action(actionTypes.GET_GOVERNMENT_USERS.SUCCESS), + failure: error => + action(actionTypes.GET_GOVERNMENT_USERS.FAILURE, { error }), + }, + getCampaignUsers: { + request: () => action(actionTypes.GET_CAMPAIGN_USERS.REQUEST), + success: () => action(actionTypes.GET_CAMPAIGN_USERS.SUCCESS), + failure: error => action(actionTypes.GET_CAMPAIGN_USERS.FAILURE, { error }), + }, + removeUser: { + request: () => action(actionTypes.REMOVE_USER.REQUEST), + success: userId => action(actionTypes.REMOVE_USER.SUCCESS, { userId }), + failure: error => action(actionTypes.REMOVE_USER.FAILURE, { error }), + }, +}; + +export function getGovernmentUsers(governmentId) { + return async (dispatch, getState, { api, schema }) => { + dispatch(actionCreators.getGovernmentUsers.request()); + try { + const response = await api.getGovernmentUsers(governmentId); + const data = normalize(response, [schema.permission]); + dispatch(addEntities(data.entities)); + dispatch(actionCreators.getGovernmentUsers.success()); + } catch (error) { + dispatch(actionCreators.getGovernmentUsers.failure(error)); + } + }; +} + +export function getCampaignUsers(campaignId) { + return async (dispatch, getState, { api, schema }) => { + dispatch(actionCreators.getCampaignUsers.request()); + try { + const response = await api.getCampaignUsers(campaignId); + const data = normalize(response, [schema.permission]); + dispatch(addEntities(data.entities)); + dispatch(actionCreators.getCampaignUsers.success()); + } catch (error) { + dispatch(actionCreators.getCampaignUsers.failure(error)); + } + }; +} + +// Side Effects, e.g. thunks +export function inviteUser( + email, + firstName, + lastName, + campaignOrGovernmentId, + role = null +) { + return async (dispatch, getState, { api }) => { + dispatch(actionCreators.inviteUser.request()); + try { + const { status } = role + ? await api.inviteUsertoCampaign( + email, + firstName, + lastName, + campaignOrGovernmentId, + role + ) + : await api.inviteUsertoGovernment( + email, + firstName, + lastName, + campaignOrGovernmentId + ); + if (status === 201) { + dispatch(actionCreators.inviteUser.success()); + role + ? dispatch(getCampaignUsers(campaignOrGovernmentId)) + : dispatch(getGovernmentUsers(campaignOrGovernmentId)); + dispatch( + flashMessage('User Invited', { props: { variant: 'success' } }) + ); + } else { + dispatch(actionCreators.inviteUser.failure()); + } + } catch (error) { + dispatch(actionCreators.inviteUser.failure(error)); + } + }; +} + +export function removeUser(userId, permissionId) { + return async (dispatch, getState, { api }) => { + dispatch(actionCreators.removeUser.request()); + try { + const response = await api.removePermission(permissionId); + if (response.status === 200) { + dispatch(actionCreators.removeUser.success(userId)); + dispatch(removePermission(permissionId)); + dispatch( + flashMessage('User Removed', { props: { variant: 'success' } }) + ); + dispatch(push('/settings')); + dispatch(clearModal()); + } else { + dispatch(actionCreators.removeUser.failure()); + dispatch( + flashMessage('Unable to remove user', { props: { variant: 'error' } }) + ); + dispatch(clearModal()); + } + } catch (error) { + dispatch(actionCreators.removeUser.failure(error)); + dispatch( + flashMessage(`Unable to remove user - ${error}`, { + props: { variant: 'error' }, + }) + ); + dispatch(clearModal()); + } + }; +} + +export function resendUserInvite(userId) { + return async (dispatch, getState, { api }) => { + dispatch(actionCreators.resendUserInvite.request()); + try { + const { status } = await api.resendInvite(userId); + status === 204 + ? dispatch(actionCreators.resendUserInvite.success()) + : dispatch(actionCreators.resendUserInvite.failure()); + } catch (error) { + dispatch(actionCreators.resendUserInvite.failure(error)); + } + }; +} + +// Selectors +export const rootState = state => state || {}; + +export const getUsers = createSelector(rootState, state => + Object.values(state.permissions) + .filter(perm => !!get(perm, 'id')) + .map(perm => { + const userAndRole = { ...state.users[perm.user] }; + userAndRole.role = startCase(perm.role); + userAndRole.roleId = perm.id; + return userAndRole; + }) +); + +export const isUsersLoading = createSelector( + rootState, + state => state.users.isLoading +); diff --git a/app2/src/state/ducks/users.test.js b/app2/src/state/ducks/users.test.js new file mode 100644 index 000000000..5708d322e --- /dev/null +++ b/app2/src/state/ducks/users.test.js @@ -0,0 +1,534 @@ +/* eslint-disable no-unused-vars */ +import configureMockStore from 'redux-mock-store'; +import thunk from 'redux-thunk'; +import * as users from './users'; +import * as permissions from './permissions'; +import * as api from '../../api'; +import * as schema from '../../api/schema'; +import { ADD_ENTITIES } from './common'; + +const { actionTypes, actionCreators } = users; + +const middlewares = [thunk.withExtraArgument({ api, schema })]; +const mockStore = configureMockStore(middlewares); + +const govAdmin = { + email: 'govadmin@openelectionsportland.org', + password: 'password', +}; + +const invite = { + code: 'inviteme', + email: 'campaignStaff+1@openelectionsportland.org', + password: 'password', +}; + +const reset = { + code: 'resetme', + password: 'newpassword', +}; + +describe('Reducer', () => { + const reducer = users.default; + it('initial state', () => { + expect(reducer(undefined, {})).toEqual({ + isLoading: false, + error: null, + }); + }); + + it('invite', () => { + expect( + reducer(undefined, { + type: actionTypes.INVITE_USER.REQUEST, + }) + ).toEqual({ + isLoading: true, + error: null, + }); + + expect( + reducer(undefined, { + type: actionTypes.INVITE_USER.SUCCESS, + }) + ).toEqual({ + isLoading: false, + error: null, + }); + + expect( + reducer(undefined, { + type: actionTypes.INVITE_USER.FAILURE, + error: '', + }) + ).toEqual({ + isLoading: false, + error: '', + }); + }); + + it('resend invite', () => { + expect( + reducer(undefined, { + type: actionTypes.RESEND_USER_INVITE.REQUEST, + }) + ).toEqual({ + isLoading: true, + error: null, + }); + + expect( + reducer(undefined, { + type: actionTypes.RESEND_USER_INVITE.SUCCESS, + }) + ).toEqual({ + isLoading: false, + error: null, + }); + + expect( + reducer(undefined, { + type: actionTypes.RESEND_USER_INVITE.FAILURE, + error: '', + }) + ).toEqual({ + isLoading: false, + error: '', + }); + }); + + it('adds user entities', () => { + expect( + reducer(undefined, { + type: ADD_ENTITIES, + payload: { + users: { + '1': {}, + }, + }, + }) + ).toEqual({ + '1': {}, + isLoading: false, + error: null, + }); + }); + + it('removeUser success', () => { + expect( + reducer( + { + 1: { + firstName: 'Dan', + lastName: 'Melton', + email: 'dan@civicsoftwarefoundation.org', + }, + }, + { + type: actionTypes.REMOVE_USER.SUCCESS, + userId: 1, + } + ) + ).toEqual({ + isLoading: false, + }); + }); + + it('removeUser fail', () => { + expect( + reducer( + { + 1: { + firstName: 'Dan', + lastName: 'Melton', + email: 'dan@civicsoftwarefoundation.org', + }, + isLoading: true, + error: null, + }, + { + type: actionTypes.REMOVE_USER.FAILURE, + error: 'an error', + } + ) + ).toEqual({ + 1: { + firstName: 'Dan', + lastName: 'Melton', + email: 'dan@civicsoftwarefoundation.org', + }, + isLoading: false, + error: 'an error', + }); + }); + + it('removeUser request', () => { + expect( + reducer( + { + 1: { + firstName: 'Dan', + lastName: 'Melton', + email: 'dan@civicsoftwarefoundation.org', + }, + isLoading: false, + error: null, + }, + { + type: actionTypes.REMOVE_USER.REQUEST, + } + ) + ).toEqual({ + 1: { + firstName: 'Dan', + lastName: 'Melton', + email: 'dan@civicsoftwarefoundation.org', + }, + isLoading: true, + error: null, + }); + }); +}); + +describe('Action Creators', () => { + it('invite request', () => { + const expectedAction = { + type: actionTypes.INVITE_USER.REQUEST, + }; + expect(actionCreators.inviteUser.request()).toEqual(expectedAction); + }); + it('invite success', () => { + const expectedAction = { + type: actionTypes.INVITE_USER.SUCCESS, + }; + expect(actionCreators.inviteUser.success()).toEqual(expectedAction); + }); + it('invite failure', () => { + const expectedAction = { + type: actionTypes.INVITE_USER.FAILURE, + }; + expect(actionCreators.inviteUser.failure()).toEqual(expectedAction); + }); + + it('resend invite request', () => { + const expectedAction = { + type: actionTypes.RESEND_USER_INVITE.REQUEST, + }; + expect(actionCreators.resendUserInvite.request()).toEqual(expectedAction); + }); + it('resend invite success', () => { + const expectedAction = { + type: actionTypes.RESEND_USER_INVITE.SUCCESS, + }; + expect(actionCreators.resendUserInvite.success()).toEqual(expectedAction); + }); + it('resend invite failure', () => { + const expectedAction = { + type: actionTypes.RESEND_USER_INVITE.FAILURE, + }; + expect(actionCreators.resendUserInvite.failure()).toEqual(expectedAction); + }); + + it('get government users request', () => { + const expectedAction = { + type: actionTypes.GET_GOVERNMENT_USERS.REQUEST, + }; + expect(actionCreators.getGovernmentUsers.request()).toEqual(expectedAction); + }); + it('get government users success', () => { + const expectedAction = { + type: actionTypes.GET_GOVERNMENT_USERS.SUCCESS, + }; + expect(actionCreators.getGovernmentUsers.success()).toEqual(expectedAction); + }); + it('get government users failure', () => { + const expectedAction = { + type: actionTypes.GET_GOVERNMENT_USERS.FAILURE, + }; + expect(actionCreators.getGovernmentUsers.failure()).toEqual(expectedAction); + }); + + it('get campaign users request', () => { + const expectedAction = { + type: actionTypes.GET_CAMPAIGN_USERS.REQUEST, + }; + expect(actionCreators.getCampaignUsers.request()).toEqual(expectedAction); + }); + it('get campaign users success', () => { + const expectedAction = { + type: actionTypes.GET_CAMPAIGN_USERS.SUCCESS, + }; + expect(actionCreators.getCampaignUsers.success()).toEqual(expectedAction); + }); + it('get campaign users failure', () => { + const expectedAction = { + type: actionTypes.GET_CAMPAIGN_USERS.FAILURE, + }; + expect(actionCreators.getCampaignUsers.failure()).toEqual(expectedAction); + }); + + it('removeUser Request', () => { + const expectedAction = { + type: actionTypes.REMOVE_USER.REQUEST, + }; + expect(actionCreators.removeUser.request()).toEqual(expectedAction); + }); + + it('removeUser Success', () => { + const expectedAction = { + type: actionTypes.REMOVE_USER.SUCCESS, + userId: 1, + }; + expect(actionCreators.removeUser.success(1)).toEqual(expectedAction); + }); + + it('removeUser Failure', () => { + const expectedAction = { + type: actionTypes.REMOVE_USER.FAILURE, + error: 'an error message', + }; + expect(actionCreators.removeUser.failure('an error message')).toEqual( + expectedAction + ); + }); +}); + +let govAdminToken; +let campaignAdminToken; +let campaignStaffToken; +let governmentId; +let campaignId; + +describe('Side Effects', () => { + beforeAll(async () => { + let tokenResponse = await api.login( + 'govadmin@openelectionsportland.org', + 'password' + ); + govAdminToken = tokenResponse.headers + .get('set-cookie') + .match(/=([a-zA-Z0-9].+); Path/)[1]; + let decodedToken = api.decodeToken(govAdminToken); + governmentId = decodedToken.permissions[0].governmentId; + + tokenResponse = await api.login( + 'campaignadmin@openelectionsportland.org', + 'password' + ); + campaignAdminToken = tokenResponse.headers + .get('set-cookie') + .match(/=([a-zA-Z0-9].+); Path/)[1]; + decodedToken = api.decodeToken(campaignAdminToken); + campaignId = decodedToken.permissions[0].campaignId; + + tokenResponse = await api.login( + 'campaignstaff@openelectionsportland.org', + 'password' + ); + campaignStaffToken = tokenResponse.headers + .get('set-cookie') + .match(/=([a-zA-Z0-9].+); Path/)[1]; + }); + + beforeEach(() => { + delete process.env.TOKEN; + }); + + it('invite user to gov', async () => { + const expectedActions = [ + { type: actionTypes.INVITE_USER.REQUEST }, + { type: actionTypes.INVITE_USER.SUCCESS }, + { type: actionTypes.GET_GOVERNMENT_USERS.REQUEST }, + ]; + const store = mockStore({}); + + process.env.TOKEN = govAdminToken; + + return store + .dispatch( + users.inviteUser( + 'govadmin1@openelectionsportland.org', + 'Government2', + 'Admin2', + governmentId + ) + ) + .then(() => { + const actions = store.getActions(); + expect(actions[0]).toEqual(expectedActions[0]); + expect(actions[1]).toEqual(expectedActions[1]); + expect(actions[2]).toEqual(expectedActions[2]); + }); + }); + + it('invite user to gov failure', async () => { + const expectedActions = [ + { type: actionTypes.INVITE_USER.REQUEST }, + { type: actionTypes.INVITE_USER.FAILURE }, + ]; + const store = mockStore({}); + + process.env.TOKEN = campaignAdminToken; + + return store + .dispatch( + users.inviteUser( + 'govadmin1@openelectionsportland.org', + 'Government2', + 'Admin2', + governmentId + ) + ) + .then(() => { + expect(store.getActions()).toEqual(expectedActions); + }); + }); + + it('invite user to campaign', async () => { + const expectedActions = [ + { type: actionTypes.INVITE_USER.REQUEST }, + { type: actionTypes.INVITE_USER.SUCCESS }, + { type: actionTypes.GET_CAMPAIGN_USERS.REQUEST }, + ]; + const store = mockStore({}); + + process.env.TOKEN = campaignAdminToken; + + return store + .dispatch( + users.inviteUser( + 'campaignadmin1@openelectionsportland.org', + 'Government2', + 'Admin2', + campaignId, + api.UserRoleEnum.CAMPAIGN_STAFF + ) + ) + .then(() => { + const actions = store.getActions(); + expect(actions[0]).toEqual(expectedActions[0]); + expect(actions[1]).toEqual(expectedActions[1]); + expect(actions[2]).toEqual(expectedActions[2]); + }); + }); + + it('invite user to campaign failure', async () => { + const expectedActions = [ + { type: actionTypes.INVITE_USER.REQUEST }, + { type: actionTypes.INVITE_USER.FAILURE }, + ]; + const store = mockStore({}); + + return store + .dispatch( + users.inviteUser( + 'campaignadmin1@openelectionsportland.org', + 'Government2', + 'Admin2', + campaignId, + api.UserRoleEnum.CAMPAIGN_STAFF + ) + ) + .then(() => { + expect(store.getActions()).toEqual(expectedActions); + }); + }); + + it('remove user failure', async () => { + const expectedActions = [ + { type: actionTypes.REMOVE_USER.REQUEST }, + { type: actionTypes.REMOVE_USER.FAILURE }, + ]; + const store = mockStore({}); + + process.env.TOKEN = campaignStaffToken; + const token = api.decodeToken(campaignStaffToken); + return store + .dispatch(users.removeUser(token.id, token.permissions[0].id)) + .then(() => { + const actions = store.getActions(); + expect(actions[0]).toEqual(expectedActions[0]); + expect(actions[1]).toEqual(expectedActions[1]); + }); + }); + + it('remove user success', async () => { + process.env.TOKEN = govAdminToken; + const tokenResponse = await api.login( + 'campaignstaff+removeme2@openelectionsportland.org', + 'password' + ); + + const token = tokenResponse.headers + .get('set-cookie') + .match(/=([a-zA-Z0-9].+); Path/)[1]; + + const user = api.decodeToken(token); + + const permissionId = user.permissions[0].id; + + const expectedActions = [ + { type: actionTypes.REMOVE_USER.REQUEST }, + { type: actionTypes.REMOVE_USER.SUCCESS, userId: user.id }, + { type: permissions.actionTypes.REMOVE_PERMISSION.SUCCESS, permissionId }, + ]; + const store = mockStore({}); + + return store.dispatch(users.removeUser(user.id, permissionId)).then(() => { + const actions = store.getActions(); + expect(actions[0]).toEqual(expectedActions[0]); + expect(actions[1]).toEqual(expectedActions[1]); + expect(actions[2]).toEqual(expectedActions[2]); + }); + }); + + it('fails to resend user invite as campaign admin', async () => { + const expectedActions = [ + { type: actionTypes.RESEND_USER_INVITE.REQUEST }, + { type: actionTypes.RESEND_USER_INVITE.FAILURE }, + ]; + const store = mockStore({}); + + process.env.TOKEN = campaignAdminToken; + + return store.dispatch(users.resendUserInvite(null)).then(() => { + expect(store.getActions()).toEqual(expectedActions); + }); + }); + + it('gets government users', async () => { + const expectedActions = [ + { type: actionTypes.GET_GOVERNMENT_USERS.REQUEST }, + { type: ADD_ENTITIES }, + { type: actionTypes.GET_GOVERNMENT_USERS.SUCCESS }, + ]; + const store = mockStore({}); + + process.env.TOKEN = govAdminToken; + + return store.dispatch(users.getGovernmentUsers(governmentId)).then(() => { + const actions = store.getActions(); + expect(actions[0].type).toEqual(expectedActions[0].type); + expect(actions[1].type).toEqual(expectedActions[1].type); + expect(actions[2].type).toEqual(expectedActions[2].type); + }); + }); + + it('gets campaign users', async () => { + const expectedActions = [ + { type: actionTypes.GET_CAMPAIGN_USERS.REQUEST }, + { type: ADD_ENTITIES }, + { type: actionTypes.GET_CAMPAIGN_USERS.SUCCESS }, + ]; + const store = mockStore({}); + + process.env.TOKEN = campaignAdminToken; + + return store.dispatch(users.getCampaignUsers(campaignId)).then(() => { + const actions = store.getActions(); + expect(actions[0].type).toEqual(expectedActions[0].type); + expect(actions[1].type).toEqual(expectedActions[1].type); + expect(actions[2].type).toEqual(expectedActions[2].type); + }); + }); +}); diff --git a/app2/src/state/index.ts b/app2/src/state/index.ts new file mode 100644 index 000000000..b6d031d39 --- /dev/null +++ b/app2/src/state/index.ts @@ -0,0 +1,12 @@ +import { combineReducers } from "redux"; +import { reducer as flashReducer } from "redux-flash"; + +// Whenever an action is dispatched, Redux will update each top-level application state property +// using the reducer with the matching name. It's important that the names match exactly, and that +// the reducer acts on the corresponding ApplicationState property type. +export const createReducer = (asyncReducers: any) => { + return combineReducers({ + flash: flashReducer, + ...asyncReducers, + }); +}; diff --git a/app2/src/state/slices/auth.ts b/app2/src/state/slices/auth.ts new file mode 100644 index 000000000..11f1454da --- /dev/null +++ b/app2/src/state/slices/auth.ts @@ -0,0 +1,55 @@ +import { createSlice, Draft, PayloadAction } from "@reduxjs/toolkit"; + +// Export State Key +export const STATE_KEY = "auth"; + +export interface AuthState { + me: string; + assume: boolean; + isLoading: boolean; + error: null; +} + +/** + * Default state object with initial values. + */ +// Initial State +export const initialState = { + me: null, + assume: false, + isLoading: false, + error: null, +} as const; + +/** + * Create a slice as a reducer containing actions. + * + * In this example actions are included in the slice. It is fine and can be + * changed based on your needs. + */ +export const userSlice = createSlice({ + name: STATE_KEY, + initialState, + reducers: { + setName: ( + state: Draft, + action: PayloadAction + ) => { + state.name = action.payload; + }, + setEmail: ( + state: Draft, + action: PayloadAction + ) => { + state.email = action.payload; + }, + }, +}); + +// A small helper of user state for `useSelector` function. +export const getUserState = (state: { user: UserState }) => state.user; + +// Exports all actions +export const { setName, setEmail } = userSlice.actions; + +export default userSlice.reducer; diff --git a/app2/src/state/store.ts b/app2/src/state/store.ts new file mode 100644 index 000000000..680091669 --- /dev/null +++ b/app2/src/state/store.ts @@ -0,0 +1,42 @@ +import { Action, configureStore, ThunkAction } from "@reduxjs/toolkit"; +import * as api from "../api"; +import * as schema from "../api/schema"; + +export const store = configureStore({ + reducer: { + // router: connectRouter(history), + // [ACTIVITIES_STATE_KEY]: activities, + [AUTH_STATE_KEY]: auth, + // [CAMPAIGNS_STATE_KEY]: campaigns, + // [CONTRIBUTIONS_STATE_KEY]: contributions, + // [MATCHES_STATE_KEY]: matches, + // [GOVERNMENTS_STATE_KEY]: governments, + // [PERMISSIONS_STATE_KEY]: permissions, + // [USERS_STATE_KEY]: users, + // [MODAL_STATE_KEY]: modal, + // [EXPENDITURES_STATE_KEY]: expenditures, + // [SUMMARY_STATE_KEY]: summary, + // [PAST_CONTRIBUTIONS_STATE_KEY]: pastContributions, + // [PUBLIC_DATA_STATE_KEY]: publicData, + // [EXTERNAL_DATA_STATE_KEY]: externalData, + }, + middleware: (getDefaultMiddleware) => + getDefaultMiddleware({ + thunk: { + extraArgument: { + api, + schema, + }, + }, + // flashMiddleware() + }), +}); + +export type AppDispatch = typeof store.dispatch; +export type RootState = ReturnType; +export type AppThunk = ThunkAction< + ReturnType, + RootState, + unknown, + Action +>; diff --git a/app2/src/state/utils/action.js b/app2/src/state/utils/action.js new file mode 100644 index 000000000..5bf12f630 --- /dev/null +++ b/app2/src/state/utils/action.js @@ -0,0 +1,3 @@ +export default function action(type, payload = {}) { + return { type, ...payload }; +} diff --git a/app2/src/state/utils/common-action-emitter.js b/app2/src/state/utils/common-action-emitter.js new file mode 100644 index 000000000..3848eeabb --- /dev/null +++ b/app2/src/state/utils/common-action-emitter.js @@ -0,0 +1,9 @@ +const actionEmitter = type => payload => { + const ret = { type }; + if (payload !== null) { + ret.payload = payload; + } + return ret; +}; + +export default actionEmitter; diff --git a/app2/src/state/utils/createAction.js b/app2/src/state/utils/createAction.js new file mode 100644 index 000000000..d20a13f96 --- /dev/null +++ b/app2/src/state/utils/createAction.js @@ -0,0 +1,3 @@ +export default function createAction(stateKey, base) { + return `openelections/${stateKey}/${base}`; +} diff --git a/app2/src/state/utils/createActionTypes.js b/app2/src/state/utils/createActionTypes.js new file mode 100644 index 000000000..95b94ba12 --- /dev/null +++ b/app2/src/state/utils/createActionTypes.js @@ -0,0 +1,17 @@ +const REQUEST = 'REQUEST'; +const SUCCESS = 'SUCCESS'; +const FAILURE = 'FAILURE'; + +export default function createActionTypes(stateKey, base) { + return [REQUEST, SUCCESS, FAILURE].reduce((acc, type) => { + acc[type] = `openelections/${stateKey}/${base}_${type}`; + return acc; + }, {}); +} + +export function createCustomActionTypes(stateKey, base, actions) { + return [...actions].reduce((acc, type) => { + acc[type] = `openelections/${stateKey}/${base}_${type}`; + return acc; + }, {}); +} diff --git a/app2/src/state/utils/createReducer.js b/app2/src/state/utils/createReducer.js new file mode 100644 index 000000000..59e456ca9 --- /dev/null +++ b/app2/src/state/utils/createReducer.js @@ -0,0 +1,8 @@ +export default function createReducer(initialState, handlers) { + return function reducer(state = initialState, action) { + if (Object.prototype.hasOwnProperty.call(handlers, action.type)) { + return handlers[action.type](state, action); + } + return state; + }; +} diff --git a/app2/src/state/utils/helpers.js b/app2/src/state/utils/helpers.js new file mode 100644 index 000000000..e6a6d19fa --- /dev/null +++ b/app2/src/state/utils/helpers.js @@ -0,0 +1,20 @@ +export function downloadFile(data, fileName) { + const blob = new Blob([data], { + type: 'application/csv;charset=utf-8;', + }); + + if (window.navigator.msSaveBlob) { + // FOR IE BROWSER + navigator.msSaveBlob(blob, fileName); + } else { + // FOR OTHER BROWSERS + const link = document.createElement('a'); + const csvUrl = URL.createObjectURL(blob); + link.href = csvUrl; + link.style = 'visibility:hidden'; + link.download = fileName; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + } +} diff --git a/app2/styles/Home.module.css b/app2/styles/Home.module.css new file mode 100755 index 000000000..32a57d52f --- /dev/null +++ b/app2/styles/Home.module.css @@ -0,0 +1,116 @@ +.container { + padding: 0 2rem; +} + +.main { + min-height: 100vh; + padding: 4rem 0; + flex: 1; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +.footer { + display: flex; + flex: 1; + padding: 2rem 0; + border-top: 1px solid #eaeaea; + justify-content: center; + align-items: center; +} + +.footer a { + display: flex; + justify-content: center; + align-items: center; + flex-grow: 1; +} + +.title a { + color: #0070f3; + text-decoration: none; +} + +.title a:hover, +.title a:focus, +.title a:active { + text-decoration: underline; +} + +.title { + margin: 0; + line-height: 1.15; + font-size: 4rem; +} + +.title, +.description { + text-align: center; +} + +.description { + margin: 4rem 0; + line-height: 1.5; + font-size: 1.5rem; +} + +.code { + background: #fafafa; + border-radius: 5px; + padding: 0.75rem; + font-size: 1.1rem; + font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, + Bitstream Vera Sans Mono, Courier New, monospace; +} + +.grid { + display: flex; + align-items: center; + justify-content: center; + flex-wrap: wrap; + max-width: 800px; +} + +.card { + margin: 1rem; + padding: 1.5rem; + text-align: left; + color: inherit; + text-decoration: none; + border: 1px solid #eaeaea; + border-radius: 10px; + transition: color 0.15s ease, border-color 0.15s ease; + max-width: 300px; +} + +.card:hover, +.card:focus, +.card:active { + color: #0070f3; + border-color: #0070f3; +} + +.card h2 { + margin: 0 0 1rem 0; + font-size: 1.5rem; +} + +.card p { + margin: 0; + font-size: 1.25rem; + line-height: 1.5; +} + +.logo { + height: 1em; + margin-left: 0.5rem; +} + +@media (max-width: 600px) { + .grid { + width: 100%; + flex-direction: column; + } +} diff --git a/app2/styles/globals.css b/app2/styles/globals.css new file mode 100755 index 000000000..e5e2dcc23 --- /dev/null +++ b/app2/styles/globals.css @@ -0,0 +1,16 @@ +html, +body { + padding: 0; + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, + Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; +} + +a { + color: inherit; + text-decoration: none; +} + +* { + box-sizing: border-box; +} diff --git a/app2/tsconfig.json b/app2/tsconfig.json new file mode 100755 index 000000000..b8e4cc588 --- /dev/null +++ b/app2/tsconfig.json @@ -0,0 +1,48 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + // Generate d.ts files + "declaration": true, + // Types should go into this directory. + // Removing this would place the .d.ts files + // next to the .js files + "outDir": "types", + // go to js file when using IDE functions like + // "Go to Definition" in VSCode + "declarationMap": true, + // "typeRoots": [ + // "node_modules/@types", + // "./types" + // ], + "paths": { + "*": [ + "./types/*" + ] + }, + "noEmit": true + }, + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx" + ], + "exclude": [ + "node_modules" + ] +} diff --git a/app2/types/redux-flash.d.ts b/app2/types/redux-flash.d.ts new file mode 100644 index 000000000..86b0afb5a --- /dev/null +++ b/app2/types/redux-flash.d.ts @@ -0,0 +1,41 @@ +/** Declaration file generated by dts-gen */ + +export function clearMessages(...args: any[]): void; + +export function flashErrorMessage(message: any, options: any): any; + +export function flashMessage(message: any, ...args: any[]): any; + +export function flashMessageType(p0: any, p1: any, p2: any, p3: any, p4: any, p5: any): any; + +export function flashSuccessMessage(message: any, ...args: any[]): any; + +export function getErrorMessages(state: any): any; + +export function getFlashMessages(state: any): any; + +export function getLatestMessage(state: any): any; + +export function getSuccessMessages(state: any): any; + +export function middleware(...args: any[]): any; + +export function reducer(state: any, action: any): any; + +export function removeMessage(...args: any[]): void; + +export namespace clearMessages { + function toString(): any; + +} + +export namespace flashMessageType { + function isRequired(p0: any, p1: any, p2: any, p3: any, p4: any, p5: any): any; + +} + +export namespace removeMessage { + function toString(): any; + +} +